IEEE 754 Float отладка - из памяти с прямым порядком байтов до фактического числа с плавающей запятой - PullRequest
1 голос
/ 08 августа 2011

Я тестирую плавающий формат IEEE 754 с VS2008, используя приведенный ниже пример:

int main(int argc, char *argv[])
{
    float i = 0.15625;
}

Я установил & i на часы VS2008 и вижу адрес 0x0012FF60, и я вижу, что содержимое адреса 00 00 20 3e из окна отладки памяти, см. Ниже:

0x0012FF60 00 00 20 3e cc cc cc cc

Кстати, у меня есть базовые знания о плавающем формате IEEE754, и я знаю, что плавающий формат IEEE 754 состоит из трех полей: знаковый бит, экспонента и дробь. Фракция является значимой, но без ее самого значительного бита.

Но как я рассчитал точно от порядка байтов 00 00 20 3e до 0,15625?

Большое спасибо

Ответы [ 4 ]

6 голосов
/ 08 августа 2011

Расположение памяти 32-битного числа с плавающей запятой (см. http://en.wikipedia.org/wiki/Single_precision) на машине с прямым порядком байтов.

enter image description here

Небольшой порядковый номер (например, x86) просто меняет пары байтов, «cc» - это неиспользуемые биты памяти, чтобы 32-битное значение с плавающей запятой до 64-битного значения отображалось отладчиком

редактирование: Помните, что показатель степени подписан (двойное дополнение), а поскольку 0,15625 меньше 1, показатель отрицателен)

значение = знак * 2 ^ exp * мантисса.

0x3e = 0011 1110
0x20 = 0010 0000

Из-за знакового бита мы должны перетасовать их вдоль одного, так что
экспонента = 0111 1100 = -3
мантисса = 0100 0000 = 1 + 0,25 (предполагается, что перед первым местом)

т.е. 0,15625 = +1 * 2 ^ (- 3) * 1,25

3 голосов
/ 08 августа 2011

Вы распечатываете что-то сломанное. Нам нужно только 32 бита, которые:

00 00 20 3E

Ваша переменная в двоичном виде:

00000000 00000000 00100000 00111110

Логическое значение, учитывающее порядок байтов:

00111110 00100000 00000000 00000000

Согласно IEEE:

0 01111100 01000000000000000000000
S E - 127  M - 1

Так что теперь понятно:

  • знак +1 (S = 0)
  • показатель степени 124 - 127 = -3
  • Мантисса 1,01b, что составляет 5/4

Таким образом, значение равно 5/4 / 8 = 5/32 = 0,15625.

1 голос
/ 08 августа 2011

Базовый формат IEEE с плавающей запятой основан на четырехбайтовом значение, и это проще для анализа, если вы отображаете его как таковой. В этом в случае, верхний бит - показатель степени, следующие 8 - показатель степени (в избытке 127), а остальное мантисса. Самый простой способ объяснить это возможно, чтобы показать код C ++, который будет обращаться к отдельным полям:

double d;
// ...
uint32_t const* p = reinterpret_cast<uint32_t const*>( &d );
bool isNegative = (*p & 0x80000000) != 0;
int exp = ((*p & 0x78000000) >> 23) - 127;
int mantissa = (*p & 0x07FFFFFF) | 0x08000000 ;

Мантисса должна иметь неявное десятичное место чуть выше 24 биты (но я не знаю, как представить это как целое число: -)).

Если все, что у вас есть, это последовательность байтов, вы должны собрать их, в соответствии с порядком байтов, а затем примените вышеуказанное.

Отредактировано: значения констант были исправлены, после того как Руди Велтуис указал на мою ошибку.

1 голос
/ 08 августа 2011

Ваше значение шестнадцатеричное 0x3E200000 или

0011 1110 0010 0000 0000 0000 0000 0000 

или переставить:

s ----e--- ----------m------------
0 01111100 01000000000000000000000

sign_bit    = 0 (i.e. positive)
exponent    = 0x7C = 124 ---> subtract 127 to get -3
significand = 1 + 0.0100... = 1.0100... = 1*2^0 + 0*2^-1 + 1*2^-2 = 1.25

significand * 2^exponent = 1.25 * 2^-3 = 1.25 * 0.125 = 0.15625
...