К сожалению, вы не можете получить такой же формат 0xa.1fp10
из printf
.Стандарт C определяет, что выходной сигнал %a
таков, что для нормального двойного числа, отличного от нуля, будет один ненулевой разряд до .
и столько цифр, сколько необходимо для точного представления значения после .
.Реализация может выбрать сколько первых бит входит в первую цифру!
Однако в стандарте C11 есть сноска 278 , в которой говорится, что
Двоичные реализации могут выбирать шестнадцатеричную цифру слева от символа десятичной запятой, чтобы последующие цифры выравнивались с полубайтовыми (4-битными) границами.
А вот и проблема.Так как IEEE 754 double
s имеет 53-битные мантиссы;первый бит равен 1 для нормальных чисел;остальные 52 бита делятся поровну на 4, реализация, следующая за этой сноской (Glibc на моей машине, кажется, равен одному), всегда выведет любое конечное ненулевое число с плавающей запятой, так что оно начинается с0x1.
!
Попробуйте, например, эту минимальную программу:
#include <stdio.h>
int main(void) {
for (double i = 1; i < 1024 * 1024; i *= 2) {
printf("%a %a %a\n", 1.0 * i, 0.7 * i, 0.67 * i);
}
}
Вывод которой на моем компьютере равен
0x1p+0 0x1.6666666666666p-1 0x1.570a3d70a3d71p-1
0x1p+1 0x1.6666666666666p+0 0x1.570a3d70a3d71p+0
0x1p+2 0x1.6666666666666p+1 0x1.570a3d70a3d71p+1
0x1p+3 0x1.6666666666666p+2 0x1.570a3d70a3d71p+2
0x1p+4 0x1.6666666666666p+3 0x1.570a3d70a3d71p+3
0x1p+5 0x1.6666666666666p+4 0x1.570a3d70a3d71p+4
0x1p+6 0x1.6666666666666p+5 0x1.570a3d70a3d71p+5
0x1p+7 0x1.6666666666666p+6 0x1.570a3d70a3d71p+6
0x1p+8 0x1.6666666666666p+7 0x1.570a3d70a3d71p+7
0x1p+9 0x1.6666666666666p+8 0x1.570a3d70a3d71p+8
0x1p+10 0x1.6666666666666p+9 0x1.570a3d70a3d71p+9
0x1p+11 0x1.6666666666666p+10 0x1.570a3d70a3d71p+10
0x1p+12 0x1.6666666666666p+11 0x1.570a3d70a3d71p+11
0x1p+13 0x1.6666666666666p+12 0x1.570a3d70a3d71p+12
0x1p+14 0x1.6666666666666p+13 0x1.570a3d70a3d71p+13
0x1p+15 0x1.6666666666666p+14 0x1.570a3d70a3d71p+14
0x1p+16 0x1.6666666666666p+15 0x1.570a3d70a3d71p+15
0x1p+17 0x1.6666666666666p+16 0x1.570a3d70a3d71p+16
0x1p+18 0x1.6666666666666p+17 0x1.570a3d70a3d71p+17
0x1p+19 0x1.6666666666666p+18 0x1.570a3d70a3d71p+18
Этот вывод эффективен - для каждого нормального кода, который должен вывести код, нужно всего 0x1.
, за которым следуют все фактические кусочки мантиссы, преобразованные в шестнадцатеричный код, завершающие полосу 0
символов и добавляющие p+
, за которыми следуетэкспонента.
Для длинных парных чисел формат x86 имеет 64 бит мантиссы.Поскольку 64 бита делятся на полубайты, разумная реализация будет иметь полный полубайт, предшествующий .
для нормальных чисел, со значениями, варьирующимися от 0x8
до 0xF
(первый бит всегда равен 1), и до точки следует до 15 кусков.
Попробуйте выполнить реализацию с
#include <stdio.h>
int main(void) {
for (long double i = 1; i < 32; i ++) {
printf("%La\n", i);
}
}
, чтобы проверить, соответствует ли это ожидание ...
Между положительными нормальными числами и нулем могут быть субнормальные числа - мой Glibc представляет эти двойные значения с 0x0.
, за которым следуют фактические кусочки мантиссы с удаленными конечными нулями и фиксированным показателем -1022
-Опять же, представление это то, что проще всего реализовать и быстрее всего вычислить.