Двойник действительно не подходит для денег? - PullRequest
69 голосов
/ 25 ноября 2008

Я всегда говорю в c # переменная типа double не подходит для денег. Все странные вещи могут произойти. Но я не могу создать пример для демонстрации некоторых из этих проблем. Кто-нибудь может привести такой пример?

(изменить; этот пост был изначально помечен C #; некоторые ответы относятся к конкретным деталям decimal, что означает System.Decimal).

(правка 2: я специально просил какой-нибудь код на C #, поэтому не думаю, что это зависит только от языка)

Ответы [ 8 ]

115 голосов
/ 25 ноября 2008

Очень, очень не подходит. Использовать десятичное число.

double x = 3.65, y = 0.05, z = 3.7;
Console.WriteLine((x + y) == z); // false

(пример со страницы Джона здесь - рекомендуемое чтение ;-p)

34 голосов
/ 25 ноября 2008

Вы получите странные ошибки, эффективно вызванные округлением. Кроме того, сравнение с точными значениями чрезвычайно сложно - вам обычно нужно применить какой-то эпсилон, чтобы проверить, что фактическое значение «близко» к конкретному.

Вот конкретный пример:

using System;

class Test
{
    static void Main()
    {
        double x = 0.1;
        double y = x + x + x;
        Console.WriteLine(y == 0.3); // Prints False
    }
}
7 голосов
/ 25 ноября 2008

Да, это не подходит.

Если я правильно помню, double имеет около 17 значащих чисел, поэтому обычно ошибки округления будут иметь место далеко за десятичной точкой. Большая часть финансового программного обеспечения использует 4 десятичных знака после десятичной точки, что оставляет 13 десятичных знаков для работы, поэтому максимальное число, с которым вы можете работать для отдельных операций, все еще намного выше, чем национальный долг США. Но ошибки округления будут складываться со временем. Если ваше программное обеспечение работает долго, вы в конечном итоге начнете терять центы. Определенные операции усугубят это. Например, добавление большого количества к небольшому количеству приведет к значительной потере точности.

Вам нужны типы данных с фиксированной запятой для операций с деньгами, большинство людей не против, если вы теряете цент здесь и там, но бухгалтеры не такие, как большинство людей ..

редактировать
Согласно этому сайту http://msdn.microsoft.com/en-us/library/678hzkk9.aspx На самом деле двойные имеют от 15 до 16 значащих цифр вместо 17.

@ Jon Skeet десятичная дробь больше подходит, чем двойная, потому что имеет более высокую точность - 28 или 29 значащих десятичных знаков. Это означает меньшую вероятность того, что накопленные ошибки округления станут значительными. Типы данных с фиксированной точкой (т. Е. Целые числа, представляющие центы или сотые доли цента, как я видел ранее), такие как упоминания Бужума, на самом деле лучше подходят.

5 голосов
/ 25 ноября 2008

Поскольку decimal использует масштабный коэффициент, кратный 10, такие числа, как 0,1, могут быть представлены точно. По сути, десятичный тип представляет это как 1/10 ^ 1, тогда как double будет представлять это как 104857/2 ^ 20 (в действительности это будет больше похоже на действительно большое число / 2 ^ 1023).

A decimal может точно представлять любое базовое значение 10, содержащее до 28/29 значащих цифр (например, 0,1). A double не может.

4 голосов
/ 25 ноября 2008

Насколько я понимаю, большинство финансовых систем выражают валюту, используя целые числа, то есть считая все в центах.

IEEE двойной точности на самом деле может представлять все целые числа точно в диапазоне от -2 ^ 53 до + 2 ^ 53. (Восторг Хакера, стр. 262). Если вы используете только сложение, вычитание и умножение, и сохраняете все в целые числа в этом диапазоне, то вы не должны видеть потери точности. Однако я бы очень опасался деления или более сложных операций.

2 голосов
/ 23 января 2015

Использование двойного, когда вы не знаете, что делаете, не подходит.

«double» может представлять сумму в триллион долларов с ошибкой 1/90 цента. Таким образом, вы получите очень точные результаты. Хотите подсчитать, сколько стоит поставить человека на Марс и вернуть его живым? двойник подойдет просто отлично.

Но с деньгами часто бывают очень конкретные правила, согласно которым определенный расчет должен давать определенный результат, а не другой. Если вы рассчитываете сумму, очень очень очень близкую к 98,135 долл., То часто будет правило, определяющее, должен ли результат составлять 98,14 долл. Или 98,13 долл., И вы должны следовать этому правилу и получить требуемый результат.

В зависимости от того, где вы живете, использование 64-битных целых чисел для представления центов, копеек или копеек или любой наименьшей единицы в вашей стране обычно будет работать нормально. Например, 64-разрядные целые числа со знаком, представляющие центы, могут представлять значения до 92 223 триллионов долларов. 32-битные целые числа обычно не подходят.

0 голосов
/ 08 июня 2015

Фактически с плавающей точкой double идеально подходит для представления денежных сумм, пока вы выбираете подходящую единицу.

См. http://www.idinews.com/moneyRep.html

Так что с фиксированной точкой long . Любой из них потребляет 8 байт, что, безусловно, предпочтительнее, чем 16, потребляемых элементом десятичный .

Работает ли что-то или нет (то есть дает ожидаемый и правильный результат), не является вопросом голосования или индивидуального предпочтения. Техника либо работает, либо нет.

0 голосов
/ 25 ноября 2008

Нет, у двойника всегда будут ошибки округления, используйте "десятичное число", если вы на .Net ...

...