Я пытался понять представление с плавающей точкой в C, использующем этот код (оба float
и int
4 байта на моей машине):
int x = 3;
float y = *(float*) &x;
printf("%d %e \n", x, y);
Мы знаем, что двоичное представление x будет следующим
00000000000000000000000000000011
Поэтому я ожидал бы, что y будет представлен следующим образом
Знаковый бит (сначала укусил от левого), = 0
Экспонента (биты 2-9 от левого) = 0
Мантисса (биты 10-32): 1 + 2^(-22)+2^(-23)
Продвижение к y = (-1)^0 * 2^(0-127) * (1+2^(-22) + 2^(-23)) = 5.87747E-39
Моя программа однако распечатывает
3 4.203895e-45
Таким образом, y имеет значение 4.203895e-45
вместо 5.87747E-39
поскольку я ожидал. Почему это происходит. Что я делаю неправильно?
P.S. Я также распечатал значения непосредственно от gdb, таким образом, это не проблема с командой printf.
Числа с плавающей запятой IEEE с полями экспоненты, равными 0, «денормализованы». Это означает, что неявная 1 перед мантиссой больше не активна. Это позволяет представлять действительно небольшие числа. См. В этой статье в Википедии . В вашем примере результат будет 3 * 2 ^ -149
-127 в экспоненте зарезервировано для денормализованных чисел. Ваш расчет предназначен для нормализованных чисел, в то время как ваше число с плавающей запятой является денормализованным.
Денормализованные числа вычисляются с использованием аналогичного метода, но:
Таким образом, это означает, что вместо этого вычисление выполняется следующим образом:
(-1)**0*2**(-126)*(2**(-22)+2**(-23)) = 4.2038953929744512e-45
Выше приведено значение python, где **
означает то же самое, что и ^
Подробно описано http://en.wikipedia.org/wiki/IEEE_754-2008 Этот стандарт предполагает, что вы сдвигаете левую мантиссу до тех пор, пока не скроете первый значащий бит (увеличивающийся показатель степени). В вашем случае у вас есть выражение 1 + 2 ^ (- 23) - тогда вы получите правильный ответ 4.9..E-32