kb: как аккуратно работать с числами с плавающей точкой
Александр Петросян (PAF) 09.12.2005 16:21
/ 09.12.2005 16:23
судя по комментарию в коде
http://www.parser.ru/examples/int2str/его автор не разобрался в ключевом моменте.
он столкнулся с проблемой и ничего о ней не написал на форум/мне.
смотрим на его комментарий:
# Если сделать $cop(^math:trunc(^math:frac($amount)*100))
# по непонятной мне причине $amount = 123.21 дает $cop = 20
дальше автор не ищет совета -- увидев проблему он ставит на неё сверху пепельницу:
$cop(^math:frac($amount)*100) # Копейки - два знака после запятой
так работать с числами с плавающей точкой нельзя.
все знают, что компьютеры работают не с десятичным представлением числа, а вовсе даже с двоичным.
иными словами внутри хранится не набор степеней десятки, а набор степеней двойки.
иными словами, в частности, после десятичной точки число собирается не из кусочков
0.1
0.01
0.001
а из кусочков
1/2
1/4
1/8
причём лишь с известной конечной точностью.
вот проблема лицом:
$f(123.86-123)
#вышеобъявленный микроскоп
^f.format[%.20f]]
в зависимости от реализации системных библиотек это число выведется по-разному:
intel/sparc solaris, linux
0.85999999999999943157
0.85999999999999943157
win32
0.85999999999999943000
видно, что по-разному подбиваются
незначащие разряды.
но значащие 15 хранятся исправно:
0.859999999999999
в математике число
0.(9) << ноль целых, девять в периоде
это просто ещё одна запись числа
1 << один
они не отличаются ни на сколько.
поэтому числа с плавающей точкой всегда при выводе округляют (round).
объявляется конкурс на то, как правильно надо было написать это место в int2str.
мне вспоминается, что об этом уже тут писал.