2010-08-05 3 views
4
#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 

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

+1

Возможный дубликат [Разница между поплавком и двойным] (http://stackoverflow.com/questions/2386772/difference-between-float-and-double) –

+3

@Ben Voigt: Я не считаю, что это дубликат этого вопроса. Вопрос не спрашивает, какова разница между float и double - он пытается понять поведение, которое выпадает из ошибки представления в любом типе конечного размера. –

+0

, пожалуйста, отредактируйте название и тег вашего вопроса, это не имеет никакого отношения к тому факту, что вы используете 'float' внутри союза. –

ответ

26

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

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

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

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

То же самое происходит в вашем примере.

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, и это значение, которое печатается.

+0

Ничего себе! большое спасибо!! – RubyDubee

+1

+1, красиво объяснено. – RBerteig

14

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

+2

Столько болтовни, чтобы пробраться, и существенный факт точности поплавка не очевиден. Я не знаю, почему это так сильно поддержано. –

+0

@Mark Я добавил данные точной точности. –

7

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

+0

uh-oh !! плохой плохой плохой !! Благодарю. – RubyDubee

+0

, но должен ли он увеличиваться или уменьшаться? я полагаю, он должен был уменьшиться? – RubyDubee

+3

Я думаю, что он должен округлить до ближайшего доступного числа с плавающей точкой. Я оставляю это как упражнение :-). –

2

поплавки имеют только 7 цифр точности Смотрите эту ссылку для получения более подробной информации: link text

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

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    float f = 1094795585.00f; 
    //  1094795648.000000 
    printf("%f \n",f); 
    return 0; 
} 
1

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

#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 
+3

Иногда FPU имеет одинаковую точность. В частности, реализации SIMD часто имеют одинаковую точность. –

+3

Они также могут быть значительно быстрее; если вы пишете код для смартфона, например - на некоторых современных ARM-процессорах, float может быть в 8 (или более) раз быстрее, чем в два раза. –

+0

@ Stephen Конечно. Но я подозреваю, что большинство людей здесь используют архитектуры 80x86 и/или считают, что плавающие, естественно, быстрее, чем удваиваются, не прочитав спецификацию процессора или не проверив, имеет ли разница в производительности в своем приложении. Говоря лично, я всегда предпочитаю правильность (точность) по скорости, пока я не вынужден пожертвовать ею. – 2010-08-05 21:18:35

0

По умолчанию, 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 
+0

Речь идет не о точности форматирования% f, а о точности типа float. –

0

Это только усложняет вещи говорить десятичных цифр, потому что это двоичная арифметика. Чтобы объяснить это, мы можем начать с рассмотрения набора целых чисел в формате одиночной точности, где все целые числа представляются. Поскольку единый формат точности имеет 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.

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

Смежные вопросы