Каков реалистичный пример, показывающий необходимость в классе денег? - PullRequest
0 голосов
/ 12 июня 2018

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

Мой язык программирования - Python.Чтобы проверить, отличается ли результат от ожидаемого, я использую:

expected = '1.23'
result = '{:0.2f}'.format(result)
assert expected == result

Таким образом, хотя следующий пример является хорошим примером погрешности с плавающей запятой, он НЕ является примером необходимости использования денежного класса с использованиемкласс рациональных чисел (например, дроби Питона) для большинства случаев использования:

a = 10.0
b = 1.2
assert a + b - a == b

Лучшее, что я могу придумать, это

result = (a + b - a) * 10**14 - b * 10**14
expected = 0

, но умножение чего-либо, связанного с деньгами, на 10**14 кажется действительно выдуманным.

Теперь мне интересно, есть ли какие-нибудь реалистичные примеры, показывающие необходимость денежного класса, или все "захвачено" простым округлением до двух цифр.

1 Ответ

0 голосов
/ 13 июня 2018

Удивительно трудно найти какой-либо пример, когда неточность с плавающей запятой на самом деле приводит к неверному результату.

Я бы не сказал, что это удивительно сложно.Известный пример из реальной жизни, хотя и не связанный с деньгами, заключался в том, что код ракетной системы Patriot накапливал ошибку округления с плавающей запятой 0,000000095 секунд в секунду;если система не будет перезагружаться каждые пять дней, она будет отключена на долю секунды.Поскольку ракеты, которые он перехватывает, могут перемещаться на несколько тысяч метров в секунду, он пропустит

По меньшей мере 28 человек погибли в результате этой ошибки с плавающей запятой.

Мы можем продемонстрировать ошибку Патриота, не подвергая риску больше жизней.Вот небольшая программа на C #.Предположим, мы добавляем десять центов;сколько мы должны добавить, прежде чем получим значительную ошибку?

    double sum = 0.0;
    long k = 0;
    long report = 1;
    while (true) {
        k += 1;
        sum += 0.1;
        if (k == report) {
            Console.WriteLine($"{k} {k / 10.0 - sum}");
            report *= 10;
        }
    }

Пусть она будет работать столько, сколько вам нужно.Вывод на моей машине начался:

1 0
10 1.11022302462516E-16
100 1.95399252334028E-14
1000 1.406874616805E-12
10000 -1.58820512297098E-10
100000 -1.88483681995422E-08
1000000 -1.33288267534226E-06
10000000 0.00016102462541312
100000000 0.0188705492764711
1000000000 1.25458218157291
10000000000 -163.12445807457

После всего лишь ста миллионов вычислений - итак, 10 миллионов долларов - мы уже на два цента.По десяти миллиардам вычислений у нас 163,12 доллара.Конечно, это крошечная ошибка на транзакцию, и, возможно, 163,12 доллара - это не много денег в общей схеме, по сравнению с миллиардом долларов, но , если мы не можем правильно вычислить 100 миллионов раз 0,1 , тогда у нас нетпричина иметь уверенность в любом вычислении, которое выходит из этой системы.

Ошибка может быть гарантированно равной нулю ;почему вы не хотите, чтобы ошибка была равна нулю?

Упражнение. Вы подразумеваете, что знаете, куда следует поместить округления, чтобы устранить эту ошибку.Итак: куда они идут?


Некоторые дополнительные мысли, вдохновленные вашим комментарием:

, хотя я думаю, что для денежного класса, безусловно, требуется десятичный тип данных, яне думаю, что этого достаточно.Я думаю, что денежный класс должен также (1) предотвращать добавление неденежных чисел (2) предотвращать добавление двух разных валют (3) не позволять брать власть / корни.

Если то, что вы хотите, реальноПримеры мировых ошибок денег, в которых единицы измерения не попадают в систему типов , таких примеров очень много.

Я работал в компании, которая пишет программное обеспечение, которое обнаруживаетпрограммные дефекты.Одним из самых волшебных средств проверки дефектов является детектор «ошибки вырезания и вставки», который обнаружил дефект в коде реального мира, например

dollarTot = (euros1 + euros2) * dollarEuroRate;
pesoTot = (euros3 + euros4) * pesoEuroRate;
... dozens more like this...

, а затем в коде

dollarTot = (yen1 + yen2) * yenDollarRate;
pesoTot = (yen3 + yen4) * pesoEuroRate;
...

Упс.

Крупный международный торговый дом 1047 *, у которого был этот дефект, позвонил нам и сказал, что пиво будет на них в следующий раз, когда мы будем в Швейцарии.

Примерыкак это показывает, почему финансовые дома так интересуются такими языками, как F #, которые супер просто позволяют отслеживать свойства в системе типов.

Несколько лет назад я написал в своем блоге серию статей об использовании системы типов ML для поиска ошибок при реализации виртуальных машин, где целое число может означать адрес десятка различных структур данных или смещение этих структур.,Он быстро находит ошибки и накладные расходы минимальны.Единицы измерения типов являются отличными, даже для простых задач, таких как убедиться, что вы не путаете доллары с иеной.

...