Союз чтения / записи в C - PullRequest
0 голосов
/ 31 марта 2011

Мне трудно понять, почему вывод следующего кода не соответствует ожиданиям. В первой итерации цикла все значения печатаются правильно, однако на всех последующих итерациях вывод fi_union.float_val равен 0.

Я использую объединение, чтобы по существу заменить псевдонимы указателя и иметь возможность интерпретировать 64 бита как значение двойной точности uint64_t или IEEE 754. Это правильный путь?

Я знаю, что сдвиг битов по значению IEEE 754 по существу приведет к мусору. Как бы странно это ни звучало, я к этому и стремлюсь. Я действительно хотел бы знать, почему fi_union.float_val равен нулю после первой итерации. У меня не включена оптимизация GCC.

Я использую gcc версии 4.4.3 на архитектуре x86_64.

double v1 = 0xDE.62133p0;

union float_interpret
{
    uint64_t val;
    double float_val;

} fi_union;


for( int i = 0; i <= 35; i++ )
{
    fi_union.val = *(uint64_t*)(&v1) >> i;
    printf( "\n %f >> %*i = %16lX \t %20li \t %15f", v1, 2, i, fi_union.val, fi_union.val, fi_union.float_val );
}

Ответы [ 2 ]

3 голосов
/ 31 марта 2011

Переменные с плавающей точкой, в соответствии с IEEE 754, представляют собой составные структуры данных с тремя или четырьмя компонентами: знак, экспонента, мантисса и, необязательно, тихий флаг NaN (встроенный в мантиссу).Сдвиг представления всей памяти, как вы сделали в fi_union.val = *(uint64_t*)(&v1) >> i;, не вернет ничего значимого.

Таким образом, ожидаемые результаты действительно те, которые вы видите на первой итерации, когда i = 0,сдвиг не выполняется и возвращенное значение в порядке.Когда вы начинаете сдвигать биты в представлении памяти с плавающей запятой, вы устанавливаете бит знака над экспонентой, биты экспоненты над мантиссой и т. Д. Это вызывает беспорядок.

Если вы хотите проверить содержимоепредставления памяти числа с плавающей запятой, используйте <ieee754.h> из glibc.

Примерно так (не проверено):

#include <ieee754.h>
...
union ieee754_double x;

x.d = v1
printf("sign: %u; mantissa: %llu; exponent: %u\n",
    (unsigned) x.ieee.negative,
    ((unsigned long long) x.ieee.mantissa1 << 20) | ((unsigned long long) x.ieee.mantissa0),
    (unsigned) x.ieee.exponent - IEEE754_DOUBLE_BIAS);
0 голосов
/ 31 марта 2011

Вы говорите, что первый раз в цикле, он работает, как вы ожидаете, но не в последующих итерациях.Передо мной нет компилятора gcc, поэтому я не могу проверить это, но сработает ли это для вас?

fi_union.float_val = v1;
for( int i = 0; i <= 35; i++ )
{
    printf( "\n %f >> %*i = %16lX \t %20li \t %15f", v1, 2, i, fi_union.val, fi_union.val, fi_union.float_val );
    fi_union.val = fi_union.val >> 1;
}

Глядя на правила предшествования операторов, ваше назначение на fi_union.val должно работать, но я предполагаю, что это не работает, когда i > 0.Поэтому попробуйте обойти его, используя объединение для замены псевдонима указателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...