Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > Помогите разобраться с float |
Автор: Волод 20.8.2005, 16:22 | ||
Братцы! Объясните дураку. Возникла у меня тут необходимость написать функцию округления чисел, и вдруг столнулся с проблемой – не округляет правильно некоторые числа и все тут! Стал копаться, и увидел неожиданную фишку – емкости чисел типа float недостаточно для выполнения операции! Вот примеры:
То есть если целая часть числа содержит больше 4 разрядов, начинается округление дробной/целой части числа…. Я вначале даже не поверил, заглядываю в книгу – написано: платформа Win32, диапазон float: 3.4 e-38 … 3.4 e+38. То есть, если я правильно понял, минимум 38 разрядов числа должно у меня храниться нормально, у меня же, получается, уже 7 разрядов числа вызывают искажение. Работаю на VC 6++, в чем дело?.... |
Автор: mr.Anderson 20.8.2005, 16:51 | ||
Как вы выводите результат на экран? Попробуйте вот такой код:
По-моему, так. |
Автор: Mayk 20.8.2005, 17:11 | ||||
Не верно. Имей ты хоть трилиард знаков, ты не получишь 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 бит).
То,что printf выводит 0.3 это исключительно заслуга printf'а ![]() |
Автор: mr.Anderson 20.8.2005, 17:19 | ||
Неплохо... ![]()
|
Автор: Волод 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. Возможно отладчик округляет значение по своему усмотрению. Попробуй
и посмтори чему равна 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 |