Size: a a a

2021 April 28

AT

Artem Tepponen in Modern::Perl
Да проблема-то понятна. Флоаты - "замечательная" вещь. Как решить? Есть какой-нибудь Math::Decimal?
источник

R

Roman in Modern::Perl
Для чего?
источник

AT

Artem Tepponen in Modern::Perl
Для бабла. Вот хочу в перле аналог из Ады:
type Bablo is delta 0.01 range 0.0 .. 99999.99;
источник

SZ

Sergey Zhmylove in Modern::Perl
Откуда такая информация? У меня информация от томсонс&рёйтерс
источник

YK

Yegor K in Modern::Perl
как вариант Math::BigFloat
источник

AT

Artem Tepponen in Modern::Perl
Не, вроде не годится. Точность больше, но?
источник

YK

Yegor K in Modern::Perl
там есть precision(-2)
источник

AT

Artem Tepponen in Modern::Perl
Вот Float все равно совсем мимо. Или надо внимательно доки курить
источник

VO

Vyacheslav Olkhovche... in Modern::Perl
Рубли в интах считать медленно (не по перловвм меркам наверное и норм), а вот копейки в интах быстро. Хотя нам ведь квадратные рубли-копейки не нужны? Тогда одинаково должно быть. Вопрос только в умножении на всякике 1.1
источник

a

allter in Modern::Perl
Проблемы с необходимостью округлений всё равно вылезут, как бы ни хранили циферки (т.к. 2 на 3 не делится, как ни старайся).

А по теме - обычно делают спецкласс для нужной предметной области (в данном случае - сумм в некой валюте). Раньше еще оверлоады для таких классов добавляли, но сейчас вопрос дискуссионный.
источник

R

Roman in Modern::Perl
Не надо ссылаться на кого-то, достаточно доказать математически и проверить практически.
Во-первых, точности double (53 бита мантисы) хватит на 17 полных десятичных знаков. С копейками, выходит 15 целых и 2 копеечных. Сомневаюсь, что вы такими суммами оперируете, т.ч. даже с погрешностями перевода 2<->10 вам хватит.
Во-вторых, как я уже писал, после вычислений нужно округлить. Биллинговые системы тоже считают на FPU, только особо упоротые будут BCD или целые вычисления делать.
Где это может подвести? При суммировании очень большого количества double без округления возможно накопление достаточной ошибки, чтобы она проявилась в младшем разряде. Предположим, числа используются от 0.00 до 10000000.00, для их хранения достаточно 30 двоичных разрядов, чтобы оставшиеся 23 разряда мантисы double накопили ошибку на 1 копейку, нужно более 8 млн чисел сложить. Отсюда: либо не суммируем по столько, либо округляем после вычисления формулы, как это делают биллинговые системы.
Демонстрация получения ошибки:
perl -wE 'my $f = 0.0; for (1 .. 250) { for (1 .. 1_000_000) { $f += 0.01 } printf("$_ %.2f %.18f\n", $f, $f) }'

240 млн раз добавил по копейке и ошибка еще в переделах погрешности, на 241-м миллионе сбой.
А теперь добавим округление на каждое миллионное суммирование:
perl -wE 'my $f = 0.0; for (1 .. 100_000) { for (1 .. 1_000_000) { $f += 0.01 } printf("$_ %.2f %.18f\n", $f, $f); $f = int($f * 100 + 0.5) / 100 }'

3.355 млрд суммирований без сбоя.
Для гарантии надо округлять после вычисления формулы.
Если производится суммирование очень большого количества чисел, то после каждого суммирования. Для оптимизации можно округлять, скажем, каждые 1000 суммирований. Для проверки, последний однострочник поменяем и внутренний цикл ограничим 100к. Без сбоев пройдет 214.7483 млрд суммирований!
источник

R

Roman in Modern::Perl
Ну и не сравнивайте double на равенство и неравенство, это детская ошибка. Напишите себе функцию, например
sub double_eq { abs($_[0] - $_[1]) < $_[2] }
double_eq(100, 100, 0.001); # два числа и допустимая точность сравнения
источник

VT

Vasily Terkin in Modern::Perl
Можно перл пропатчить, чтобы оператор сравнения учитывал точность
источник

VT

Vasily Terkin in Modern::Perl
Но явное лучше неявного
источник

VG

Vadim Goncharov in Modern::Perl
оператор "примерно равно" из unreal ? :)
источник

YS

Yevhen Sabodash in Modern::Perl
Схема от @RomanChernyshov рабочая, но все операции с числами приходится покрывать округлениями, бесит невероятно
источник

SZ

Sergey Zhmylove in Modern::Perl
Она рабочая до тех пор, пока это в рамках одного компьютера всё
источник

R

Roman in Modern::Perl
"все операции" — это все формулы, а не операции. Это более чем достаточно.
источник

R

Roman in Modern::Perl
В рамках чего она не рабочая. Приведите пример!
источник

SZ

Sergey Zhmylove in Modern::Perl
Ты знаешь что-нибудь про передачу данных по сети? И про представление данных, например, в е25к и ему подобных железках, на которых часто делают финансовые расчеты? htond/htonf ещё не изобрели
источник