союз, состоящий из поплавка: совершенно безумный выход - PullRequest
4 голосов
/ 06 августа 2010
#include <stdio.h>

union NumericType
{
    float value;
    int intvalue;
}Values;

int main()
{
    Values.value = 1094795585.00;
    printf("%f \n",Values.value);
    return 0;
}

Эта программа выводит как:

1094795648.000000 

Кто-нибудь может объяснить, почему это происходит?Почему значение поплавка Values.value увеличилось?Или я что-то здесь упускаю?

Ответы [ 7 ]

27 голосов
/ 06 августа 2010

Во-первых, это не имеет ничего общего с использованием union.

Теперь, предположим, вы пишете:

int x = 1.5;
printf("%d\n", x);

что произойдет?1.5 не является целочисленным значением, поэтому преобразуется в целое число (путем усечения), а x, таким образом, фактически получает значение 1, которое в точности соответствует напечатанному.1013 * В вашем примере происходит то же самое.

float x = 1094795585.0;
printf("%f\n", x);

1094795585.0 не может быть представлен как число с плавающей запятой одинарной точности, поэтому он получает преобразованный до представимого значения.Это происходит с помощью округления.Два ближайших значения:

1094795520 (0x41414100) -- closest `float` smaller than your number
1094795585 (0x41414141) -- your number
1094795648 (0x41414180) -- closest `float` larger than your number

Поскольку ваше число немного ближе к большему значению (это немного легче увидеть, если вы посмотрите на шестнадцатеричное представление), оно округляется до этого значения, так чтозначение сохраняется в x, и это значение, которое печатается.

14 голосов
/ 06 августа 2010

A float не так точно, как хотелось бы. Его эффективная 24-битная мантисса обеспечивает точность до 7-8 десятичных цифр. Ваш пример требует точности 10 десятичных цифр. Двойной имеет эффективную 53-битную мантиссу, которая обеспечивает 15-16 цифр точности, что достаточно для вашей цели.

7 голосов
/ 06 августа 2010

Это потому, что ваш тип float не имеет точности для отображения этого числа.Используйте double.

2 голосов
/ 06 августа 2010

с плавающей запятой имеют только 7 цифр точности. См. Эту ссылку для более подробной информации: текст ссылки

Когда я это делаю, я получаю те же результаты:

int _tmain(int argc, _TCHAR* argv[])
{
    float f = 1094795585.00f; 
    //        1094795648.000000
    printf("%f \n",f); 
    return 0; 
}
1 голос
/ 06 августа 2010

Я просто не понимаю, почему люди используют поплавки - они часто не быстрее удваиваются и могут быть медленнее. Этот код:

#include <stdio.h>

union NumericType
{
    double value;
    int intvalue;
}Values;

int main()
{
    Values.value = 1094795585.00;
    printf("%lf \n",Values.value);
    return 0;
}

производит:

1094795585.000000
0 голосов
/ 24 февраля 2011

Сложно говорить о десятичных цифрах, потому что это двоичная арифметика. Чтобы объяснить это, мы можем начать с просмотра набора целых чисел в формате одинарной точности, где все целые числа представимы. Поскольку формат с одинарной точностью имеет точность 23 + 1 = 24 бита, это означает, что диапазон равен

0 to 2^24-1

Это недостаточно хорошо или недостаточно подробно для объяснения, поэтому я уточню его до

0 to 2^24-2^0 in steps of 2^0

Следующий более высокий набор -

0 to 2^25-2^1 in steps of 2^1

Следующий нижний набор -

0 to 2^23-2^-1 in steps of 2^-1

Ваше число, 1094795585 (0x41414141 в шестнадцатеричном формате), попадает в диапазон, максимум которого чуть меньше 2 ^ 31 =. Этот диапазон может быть подробно выражен как от 0 до 2 ^ 31-2 ^ 7 с шагом 2 ^ 7. Это логично, потому что 2 ^ 31 - это 7 степеней на 2 больше, чем 24. Поэтому приращения также должны быть на 7 степеней на 2 больше.

Глядя на «следующие более низкие» и «следующие более высокие» значения, упомянутые в другом посте, мы видим, что разница между ними составляет 128 i e 2 ^ 7.

В этом нет ничего странного, странного, смешного или даже волшебного. Это на самом деле абсолютно ясно и довольно просто.

0 голосов
/ 06 августа 2010

По умолчанию printf с плавающей запятой с% f даст точность 6 после десятичной дроби.Если вам нужна точность в 2 цифры после десятичной точки, используйте% .2f.Даже ниже дает тот же результат

#include <stdio.h>
union NumericType
{
    float value;
    int intvalue;
}Values;

int main()
{
    Values.value = 1094795585;
    printf("%f \n",Values.value);
    return 0;
}

Result 
./a.out
1094795648.000000
...