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

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

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

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

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

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

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

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

Ответы [ 24 ]

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

Единственная причина использовать Float для денег, если вы не заботитесь о точных ответах.

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

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

Для пояснения, десятичный тип 12,2 будет точно хранить эти 14 цифр, тогда как float не будет, так как он использует двоичное представление внутри. Например, 0,01 не может быть точно представлено числом с плавающей запятой - самое близкое представление фактически 0,0099999998

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

Даже лучше, чем использование десятичных чисел, это использование простых старых целых чисел (или, возможно, какого-то типа bigint). Таким образом, вы всегда имеете максимально возможную точность, но точность можно указать. Например, число 100 может означать 1.00, которое имеет следующий формат:

int cents = num % 100;
int dollars = (num - cents) / 100;
printf("%d.%02d", dollars, cents);

Если вы хотите повысить точность, вы можете изменить значение 100 на большее, например: 10 ^ n, где n - количество десятичных знаков.

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

Еще одна вещь, о которой вы должны знать в системах бухгалтерского учета, это то, что никто не должен иметь прямой доступ к таблицам. Это означает, что весь доступ к системе учета должен осуществляться через хранимые процедуры. Это предотвращает мошенничество, а не только инъекции SQl. Внутренний пользователь, который хочет совершить мошенничество, не должен иметь возможности напрямую изменять данные в таблицах базы данных. Это критический внутренний контроль в вашей системе. Вы действительно хотите, чтобы какой-то недовольный сотрудник пошел в бэкэнд вашей базы данных и начал писать им чеки? Или скрыть, что они утвердили расходы неавторизованному поставщику, если у них нет полномочий на утверждение? Только два человека во всей вашей организации должны иметь прямой доступ к данным в вашей финансовой базе данных, вашей базе данных и его резервной копии. Если у вас много dbas, только два из них должны иметь этот доступ.

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

2 голосов
/ 22 октября 2010

Из 100 дробей n / 100, где n - натуральное число, такое, что 0 <= n и n <100, только четыре могут быть представлены как числа с плавающей запятой. Посмотрите на вывод этой программы на C: </p>

#include <stdio.h>

int main()
{
    printf("Mapping 100 numbers between 0 and 1 ");
    printf("to their hexadecimal exponential form (HEF).\n");
    printf("Most of them do not equal their HEFs. That means ");
    printf("that their representations as floats ");
    printf("differ from their actual values.\n");
    double f = 0.01;
    int i;
    for (i = 0; i < 100; i++) {
        printf("%1.2f -> %a\n",f*i,f*i);
    }
    printf("Printing 128 'float-compatible' numbers ");
    printf("together with their HEFs for comparison.\n");
    f = 0x1p-7; // ==0.0071825
    for (i = 0; i < 0x80; i++) {
        printf("%1.7f -> %a\n",f*i,f*i);
    }
    return 0;
}
2 голосов
/ 09 февраля 2009

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

2 голосов
/ 21 сентября 2008

Вы всегда можете написать что-то вроде типа Money для .Net.

Посмотрите на эту статью: Тип денег для CLR - Автор сделал отличную работу, на мой взгляд.

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

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

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

Возможно, вы захотите использовать некоторую форму представления с фиксированной точкой для значений валюты. Вы также захотите исследовать округление Банкира (также известное как «округление до половины». Это позволяет избежать смещения, существующего в обычном методе «округление до половины».

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

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

Что касается Con, что десятичная дробь занимает еще один байт, я бы сказал, что это не волнует. В 1 млн. Строк вы будете использовать только 1 МБ, а хранилище очень дешево в наши дни.

...