IEEE 754 Float debug - от памяти немного endian до фактического числа с плавающей запятой

55
5

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

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

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

0x0012FF60 00 00 20 3e cc cc cc cc

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

Но как я вычислил точно от маленького endian 00 00 20 3e до 0,155625?

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

спросил(а) 2011-08-08T18:39:00+04:00 8 лет, 11 месяцев назад
1
Решение
79

Вы печатаете что-то сломанное. Нам нужны только 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,155625.

ответил(а) 2011-08-08T19:00:00+04:00 8 лет, 11 месяцев назад
102

Макет памяти 32-битного поплавка (см. Http://en.wikipedia.org/wiki/Single_precision) на машине большого конца.

enter image description here

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

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


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

0x3e = 0011 1110
0x20 = 0010 0000

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

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

ответил(а) 2011-08-08T18:47:00+04:00 8 лет, 11 месяцев назад
55

Основной формат плавающей точки 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 бит (но я не знаю, как представить это как целое число :-)).

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

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

ответил(а) 2011-08-08T19:02:00+04:00 8 лет, 11 месяцев назад
55

Ваше значение равно hex 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

ответил(а) 2011-08-08T19:02:00+04:00 8 лет, 11 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема