Использовать число с плавающей запятой или десятичное число для учета долларов США? - PullRequest
75 голосов
/ 15 сентября 2008

Мы переписываем нашу устаревшую систему учета в VB.NET и SQL Server. Мы привлекли новую команду программистов .NET / SQL для переписывания. Большая часть системы уже укомплектована суммами в долларах с использованием Float. У старого системного языка, который я запрограммировал, не было Float, поэтому я, вероятно, использовал бы десятичную дробь.

Какая ваша рекомендация?

Следует ли использовать тип данных Float или Decimal для сумм в долларах?

Каковы некоторые плюсы и минусы для любого из них?

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

Еще один кон - все показы, и напечатанные суммы должны иметь оператор формата, который показывает две десятичные позиции. Я заметил несколько раз, где это не было сделано, и суммы не выглядели правильными. (т.е. 10,2 или 10,2546)

Профи - это то, что Float занимает всего 8 байт на диске, тогда как десятичное число будет занимать 9 байтов (десятичное 12,2)

Ответы [ 24 ]

106 голосов
/ 16 сентября 2008

Следует ли использовать тип данных Float или Decimal для сумм в долларах?

Ответ прост. Никогда не плавает. НИКОГДА !

Числа с плавающей точкой были в соответствии с IEEE 754 всегда двоичными, только новый стандарт IEEE 754R определял десятичные форматы. Многие дробные двоичные части никогда не могут быть равны точному десятичному представлению.
Любое двоичное число может быть записано как m/2^n (m, n положительные целые числа), любое десятичное число как m/(2^n*5^n).
Поскольку в двоичных файлах нет простого числа factor 5, все двоичные числа могут быть точно представлены десятичными знаками, но не наоборот.

0.3 = 3/(2^1 * 5^1) = 0.3

0.3 = [0.25/0.5] [0.25/0.375] [0.25/3.125] [0.2825/3.125]

          1/4         1/8         1/16          1/32

Таким образом, вы получите число, большее или меньшее заданного десятичного числа. Всегда.

Почему это имеет значение? Округление.
Нормальное округление означает 0,4 вниз, 5,9 вверх. Так что имеет значение , если результат или 0.049999999999 .... или 0.0500000000 ... Возможно, вы знаете, что это означает 5 центов, но компьютер этого не знает и округляет 0.4999 ... вниз (неправильно) и 0.5000 .. вверх (справа).
Учитывая, что результат вычислений с плавающей запятой всегда содержит небольшие ошибки, решение - просто удача. Это становится безнадежным, если вам нужна десятичная округленная до четной обработка с двоичными числами.

Неубедительно? Вы настаиваете, что в вашей учетной записи все отлично?
Активы и пассивы равны? Хорошо, тогда возьмите каждое из заданных форматированных чисел каждой записи, проанализируйте их и суммируйте их с независимой десятичной системой! Сравните это с отформатированной суммой.
К сожалению, что-то не так, не так ли?

Для этого расчета требовалась предельная точность и точность (мы использовали Oracle FLOAT), чтобы мы могли записать "миллиардные пенни", которые были начислены.

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

41 голосов
22 голосов
/ 15 сентября 2008

Сначала вы должны прочитать это Что каждый ученый должен знать об арифметике с плавающей точкой . Тогда вам действительно стоит подумать об использовании какого-либо типа пакета с фиксированной точкой / числа произвольной точности (например, java BigNum, десятичный модуль python), иначе вы попадете в мир боли. Затем выясните, достаточно ли использовать собственный десятичный тип SQL.

Плавающие / двойные существуют (ред.), Чтобы выставить быстрый x87 fp, который сейчас в значительной степени устарел. Не используйте их, если вы заботитесь о точности вычислений и / или не полностью компенсируете их ограничения.

10 голосов
/ 15 сентября 2008

В качестве дополнительного предупреждения SQL Server и платформа .Net используют другой алгоритм округления по умолчанию. Убедитесь, что вы проверили параметр MidPointRounding в Math.Round (). .Net Framework по умолчанию использует алгоритм Банкерса, а SQL Server использует симметричное алгоритмическое округление. Проверьте статью в Википедии здесь

7 голосов
/ 15 сентября 2008

Спроси своих бухгалтеров! Они будут осуждать вас за использование поплавка. Как и ранее, используйте float ТОЛЬКО, если вам не нужна точность. Хотя я всегда был бы против этого, когда дело доходит до денег.

В бухгалтерии НЕ допускается использование поплавка. Используйте десятичную с 4 десятичными точками.

6 голосов
/ 15 сентября 2008

Плавающие точки имеют неожиданные иррациональные числа.

Например, вы не можете хранить 1/3 в виде десятичной дроби, это будет 0,3333333333 ... (и так далее)

Число с плавающей запятой фактически хранится в виде двоичного значения и степени 2.

Таким образом, 1,5 сохраняется как 3 x 2 до -1 (или 3/2)

Используя эти показатели степени 2, создайте несколько нечетных иррациональных чисел, например:

Конвертируйте 1.1 в число с плавающей точкой и затем снова конвертируйте его, ваш результат будет примерно таким: 1.0999999999989

Это потому, что двоичное представление 1.1 на самом деле 154811237190861 x 2 ^ -47, с чем может справиться больше, чем double.

Подробнее об этой проблеме можно узнать в моем блоге , но в основном для хранения лучше использовать десятичные дроби.

На сервере Microsoft SQL у вас есть тип данных money - обычно это лучше всего подходит для хранения финансовых данных. Точность до 4 знаков после запятой.

Для вычислений у вас есть большая проблема - неточность - крошечная доля, но поместите ее в степенную функцию, и она быстро становится существенной.

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

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

Использовать тип SQL Server десятичный .

Не используйте деньги или float .

деньги используют 4 знака после запятой, быстрее, чем использование десятичного знака НО страдает от некоторых очевидных и некоторых не столь очевидных проблем с округлением ( см. Эту проблему соединения )

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

Я бы порекомендовал использовать 64-битные целые числа, которые хранят все это в центах.

5 голосов
/ 09 февраля 2009

Здесь немного фона ...

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

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

Следовательно, для финансовых расчетов правильный ответ - это то, что дает тот же ответ, что и CPA, который хорош в арифметике. Это десятичная арифметика, а не с плавающей точкой IEEE.

4 голосов
/ 15 сентября 2008

За банковскую систему, которую я помогал развивать, я отвечал за «начисление процентов» в системе. Каждый день мой код вычислял, сколько процентов было начислено (заработано) на балансе в тот день.

Для этого расчета требовалась предельная точность и верность (мы использовали FLOAT от Oracle), чтобы мы могли записать накопленные «миллиардные доли пенни».

Когда дело дошло до "капитализации" процентов (т. Е. Возврата процентов на ваш счет), сумма была округлена до копейки. Тип данных для остатков на счетах был два десятичных знака. (На самом деле это было сложнее, так как это была мультивалютная система, которая могла работать во многих десятичных разрядах - но мы всегда округляли до «копейки» этой валюты). Да - там, где «доли» потерь и прибылей, но когда данные компьютеров были актуализированы (деньги выплачены или выплачены), это всегда были РЕАЛЬНЫЕ денежные ценности.

Это устраивает бухгалтеров, аудиторов и тестировщиков.

Итак, уточняйте у ваших клиентов. Они расскажут вам свои банковские / бухгалтерские правила и практики.

...