Как распечатать номер IEEE754 (без printf)? - PullRequest
5 голосов
/ 25 ноября 2010

Для целей этого вопроса у меня нет есть возможность использовать printf средства (к сожалению, я не могу сказать вам, почему, к сожалению, давайте пока предположим, что я знаю, что явыполняю).

Для числа с одинарной точностью IEEE754 у вас есть следующие биты:

SEEE EEEE EFFF FFFF FFFF FFFF FFFF FFFF

, где S - знак, E - показатель степени и F - это дробь.

Печать знака относительно проста для всех случаев, как и все особые случаи, такие как NaN (E == 0xff, F != 0), Inf (E == 0xff, F == 0) и 0(E == 0, F == 0, считается особенным только потому, что смещение показателя не используется в этом случае).

У меня есть два вопроса.

Первый - как лучше превратить денормализованные числа (где E == 0, F != 0) в нормализованные числа (где 1 <= E <= 0xfe)?Я подозреваю, что это будет необходимо для упрощения ответа на следующий вопрос (но я могу ошибаться, поэтому не стесняйтесь обучать меня).

Второй вопрос - как распечатать нормализованные числа.Я хочу, чтобы их можно было распечатать двумя способами: экспоненциально, например -3.74195E3, и не экспоненциально, например 3741.95.Хотя, просто глядя на эти два рядом, должно быть довольно легко превратить первое в второе, просто перемещая десятичную точку вокруг.Итак, давайте просто сконцентрируемся на экспоненциальной форме.

У меня есть смутное воспоминание об алгоритме, который я использовал давно для распечатки PI, где вы использовали одну из постоянно сокращающихся формул и держали верхнюю и нижнююограничить возможности, вывести цифру, когда оба предела согласованы, и сдвинуть расчет в 10 раз (поэтому, когда верхний и нижний пределы были 3.2364 и 3.1234, вы можете вывести 3 и скорректировать егов расчетах).

Но прошло уже 1039 * времени с тех пор, как я это сделал, поэтому я даже не знаю, подходит ли этот подход здесь.Кажется, так как значение каждого бита вдвое меньше, чем у предыдущего бита при перемещении через дробную часть (1/2, 1/4, 1/8 и т. Д.)Я действительно предпочитаю , а не , чтобы перебирать исходный код printf, за исключением случаев, когда это абсолютно необходимо, поэтому, если кто-то может помочь с этим, я буду вечно благодарен.

Ответы [ 4 ]

3 голосов
/ 25 ноября 2010

Если вы хотите получать точные результаты для каждого преобразования, вам придется использовать арифметику произвольной точности, как это делается в реализациях printf ().Если вы хотите получить результаты, которые «близки», возможно, отличаются только их младшими значащими цифрами, тогда достаточно очень простого алгоритма на основе двойной точности: для целочисленной части несколько раз разделите на десять и добавьте оставшиесясформировать десятичную строку (в обратном порядке);для дробной части многократно умножьте на десять и вычтите целые части, чтобы сформировать десятичную строку.

Недавно я написал статью об этом методе: http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal-conversion/.Это не печатает научную нотацию, но это должно быть тривиальным, чтобы добавить.Алгоритм выводит субнормальные числа (те, которые я напечатал, вышли точно, но вам нужно будет провести более тщательное тестирование).

1 голос
/ 25 ноября 2010

Ненормализованные числа нельзя превратить в нормализованные числа одного и того же типа с плавающей запятой.Экспонента эквивалентного нормализованного числа будет слишком мала, чтобы быть представленной экспонентой.

Для печати нормализованных чисел я могу придумать один глупый способ - многократно умножить на 10 (ну, для дробной части).1003 *

0 голосов
/ 25 ноября 2010

Есть статья Дж. Стила, в которой более подробно описывается алгоритм, основанный на том же принципе, что и тот, который вы наметили. Если память служит, то есть время, когда вы вынуждены использовать арифметику неограниченной точности. (Я думаю, что это Как правильно печатать числа с плавающей запятой , но citeseer в данный момент не работает, я не могу подтвердить, и результаты Google загрязнены ретроспективной статьей, опубликованной 20 лет спустя).

0 голосов
/ 25 ноября 2010

Первое, что вам нужно сделать, - это преобразовать экспоненту в десятичную (поскольку, по-видимому, это то, что вы хотите получить) в логарифмах. Вы берете дробь этого результата и умножаете мантиссу на exp10 этой дроби, а затем конвертируете ее в десятичные символы. Оттуда вам просто нужно вставить десятичную точку в соответствующем месте, смещенную на теперь десятичный показатель степени.

...