Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Помогите разобраться с float


Автор: Волод 20.8.2005, 16:22
Братцы! Объясните дураку. Возникла у меня тут необходимость написать функцию округления чисел, и вдруг столнулся с проблемой – не округляет правильно некоторые числа и все тут!
Стал копаться, и увидел неожиданную фишку – емкости чисел типа float недостаточно для выполнения операции! Вот примеры:
Код

float summ=1234.56;    //summ=1234.56
float summ=12345.67;    //summ=12345.70
float summ=123456.78;    //summ=123457

То есть если целая часть числа содержит больше 4 разрядов, начинается округление дробной/целой части числа…. Я вначале даже не поверил, заглядываю в книгу – написано: платформа Win32, диапазон float: 3.4 e-38 … 3.4 e+38. То есть, если я правильно понял, минимум 38 разрядов числа должно у меня храниться нормально, у меня же, получается, уже 7 разрядов числа вызывают искажение. Работаю на VC 6++, в чем дело?....

Автор: mr.Anderson 20.8.2005, 16:51
Как вы выводите результат на экран? Попробуйте вот такой код:
Код

//Тут вы создаете, предположим, переменную VAR, содержащую округленное значение.
...
//А теперь выводим результат:
printf("Результат: %.5f",VAR);

По-моему, так.

Автор: Mayk 20.8.2005, 17:11
Цитата
минимум 38 разрядов числа должно у меня храниться нормально

Не верно. Имей ты хоть трилиард знаков, ты не получишь 0.3 в точности:
(переводим 0,3 в двоичную):
0, 3|x2
0, 6|x2
1, 2|x2
0, 4|x2
0, 8|x2
1, 6|x2
период.
А вообще ну его этот флоат, юзай double. Или long double(80 бит).

Цитата(sim7 @ 20.8.2005, 20:51)
printf("Результат: %.5f",VAR);

То,что printf выводит 0.3 это исключительно заслуга printf'а smile

Автор: mr.Anderson 20.8.2005, 17:19
Неплохо... smile Только еще добавлю: чтобы double не выводилось как экспоненциальное число или с огромным количеством знаков после и/или до запятой, ограничивайте их через printf, как я описал в своем примере. Например, так:
Код

//Переменная VAR типа double, содержащая результат, объявляется тут. Где-то тут.
printf("Rezult: %.10f",VAR);


Автор: Волод 20.8.2005, 18:39
Я вообще на экран результат не вывожу. Стал через отладчик смотреть, где ошибся в алгоритме округления, а тут на тебе - такие искажения уже на этапе присвоения, а вообще то я это число просто передаю, как аргумент, в функцию окруления. Майк, а можно поподробнее про твои выкладки, я не совсем понял, при чем туту перевод в двоичную систему....

Автор: Mayk 20.8.2005, 19:48
Цитата
Майк, а можно поподробнее про твои выкладки, я не совсем понял, при чем туту перевод в двоичную систему....

Искажения происходят при переводе из десятичной системы счисления в двоичную и обратно. Процессор работает с двоичной арифметикой, а число 12345.67 невозможно перевести в двоичную сс, так как при переводе получается бесконечная периодическая дробь. Что-то типа того, что на обычном калькуляторе выполнить 10/3*3. После выполнения не получится 10.
Поэтому он вместо числа 12345.67 обрабатывает максимально приближенное к нему число.
В двоичной системе 12345,67 будет выглядеть как 11000000111001.101010111000010100011110101110000101001....
В флоате под мантиссу отводится 24 бита(при этом первый бит не записывается, он равен 1), а теперь считаем.
14 бит будут отведены под целую часть(11000000111001. вот она целая часть в 14 битах). На дробную остаются каких-то жалких 10 битов. Вот и отсутствие точности. Используй double, он точнее. Или long double - он еще точнее.

зы. Но всё равно странно. 12345.67 должно преобразоваться в 12345.669921875. Возможно отладчик округляет значение по своему усмотрению. Попробуй
Код

char s[50]; sprintf(s,"%.10f",summ); 

и посмтори чему равна s.

Автор: Волод 21.8.2005, 05:53
Спасибо за пояснения, видимо придется работать с double. Теперь я , по крайней мере, понимаю, почему стандартные функции округления типа ceil и floor тоже работают с double, а не float

Автор: RVN 13.9.2005, 14:39
Попробуй так
код C++
double X=123,455555555;
X=RoundTo(X,-2);// X=123,46
И по-моему все равно double или float

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)