Почему приложения обычно не используют int для внутреннего представления значений валюты?

Почему приложения обычно не используют целочисленный тип данных (например, int или long в C ++ / Java / C #) для внутреннего представления значений валюты, в отличие от использования типа данных с плавающей запятой (float, double) или чего-то вроде BigDecimal в Java?

Например, если я пишу приложение Java и у меня есть переменная, фактическое значение которой я хочу представить в долларах США (не нужно представлять доли грошей), я мог бы объявить значение int, представляющее количество центов. Например, значение «$ 1,00» будет представлено как 100. Это кажется хорошей альтернативой использованию double (см. Вопрос Почему бы не использовать Double или Float для представления валюты?) или BigDecimal (который является более тяжелым объектом, чем простой примитив int).

Очевидно, что целочисленное значение необходимо «преобразовать» (то есть из 100 в «1 доллар» или «1 доллар») перед его отображением пользователю или после ввода пользователем значения валюты, но это не кажется существенным более обременительным, чем форматирование double или BigDecimal для отображения.

Почему этот подход не является лучшей практикой для приложений, которые не должны представлять доли центов (или эквивалент в других типах валюты)?


person Jon Schneider    schedule 18.03.2011    source источник
comment
Или, может быть, лучше: почему приложения не используют тип данных, специально разработанный для работы с денежными единицами? (ЙЕНА и доллар США имеют разные наименьшие номиналы, и молчаливое присвоение между валютами, скорее всего, неверно.) Я предполагаю, что это та же причина, по которой используются числа с плавающей запятой / удвоения: они обеспечивают точность и операции (хотя и со всеми присущими им проблемами) без необходимо использовать [правильный] тип, зависящий от домена. Кроме того, иногда (например, биржевые тикеры) это просто не имеет значения.   -  person    schedule 18.03.2011


Ответы (3)


Почему приложения обычно не используют [целые числа] для внутреннего представления значений валюты?

  1. Это не способствует простому кодированию. 1,10 доллара - это 110 центов. Хорошо, но как насчет того, когда вам нужно рассчитать налог (например, 1,10 доллара * 4,225% - налоговая ставка Миссури, которая дает 0,046475 доллара). Чтобы сохранить все деньги в целых числах, вам также необходимо преобразовать налог с продаж в целое число (4225), что потребует дальнейшего преобразования 110 ¢ в 11000000. Тогда математика может быть 11000000 * 4225/100000 = 464750. Это проблема, так как теперь у нас есть значения в долях цента (11000000 и 464750 соответственно). Все это для хранения денег целыми числами.

  2. Следовательно, проще думать и кодировать в терминах национальной валюты. В Соединенных Штатах это будет в долларах с десятичной дробью в центах (т. Е. 1,10 доллара). Кодировать в терминах 110 ¢ не так естественно. Использование чисел с плавающей запятой base-10 (таких как BigDecimal в Java и Decimal в .NET) обычно достаточно точное для денежных значений (по сравнению с числами с плавающей запятой base-2, такими как Float и Double).

Почему этот подход не является наилучшей практикой для приложений, в которых не требуется представлять доли центов (или их эквивалент в других типах валюты)?

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

person Matt    schedule 18.03.2011
comment
+1, потому что он говорит о том, что голые целые числа не встроены в поддержку многих требуемых операций. «1,10 доллара» - это отображаемая валюта. Милы равны 1/1000 $. Кроме того, BigDecimal является точным (для определенного подмножества операций / желаемого расхода памяти и предлагает настраиваемые режимы округления), в то время как decimal (.NET) - это просто действительно огромное 128-битное число относительной точности < / i>, который может просто перебрать ряд проблем, но все же страдает от того, что не является фиксированной точностью :) - person ; 18.03.2011
comment
Мэтт, не могли бы вы прояснить свою точку зрения относительно хранения всех денег целыми числами? Я бы представил ставку налога как значение с плавающей запятой (поскольку ставка налога не является значением валюты); тогда я умножу свое целочисленное значение валюты на двойное значение с плавающей запятой, чтобы найти свой результат, и приму любую потерю точности как доли пенни, которые я могу отбросить. Предполагая, что у нас нет требования отслеживать доли пенни для целей налога с продаж, подлежащего перечислению государству - это может быть проблемой, но предположим, что есть жизнеспособные обходные пути - есть ли другие недостатки этого подхода? - person Jon Schneider; 19.03.2011
comment
@Jon, я просто пытался привести пример того, как это может быть не всегда просто, и что вам придется пройти, чтобы никогда не потерять точность (если это желательно, поскольку использование float обычно не рекомендуется из-за потери точности) . Однако выполнение промежуточных вычислений с помощью чисел с плавающей запятой имеет смысл для расчета налога с продаж и, вероятно, будет более распространенным явлением. - person Matt; 19.03.2011

Целочисленные типы

Использовать большинство целочисленных типов данных для представления валют - плохая идея по следующим причинам:

  • очень ограниченный допустимый диапазон значений диапазона для общих приложений;
  • что создает дополнительную нагрузку на обработку дробных значений.

В частности, ограниченный диапазон значений может быть серьезной проблемой с более коротким целочисленным типом. Давайте рассмотрим обычное 32-битное целое число со знаком (обычно int):

  • диапазон значений от прибл. От -2,15 миллиарда до +2,15 миллиарда - это само по себе не вариант для любого бухгалтерского / банковского / серьезного финансового использования;
  • когда для представления дробной части используются только две последние цифры, диапазон сокращается с -21,5 миллиона до +21,5 миллиона;
  • в случае, если умножение работает (не говоря уже о вычислениях со смешанной точностью), диапазон уменьшается еще больше.

С помощью 64-битного целого числа со знаком (обычно long) вы можете сосчитать до 92 тысяч триллионов. Когда мы думаем о мировой экономике, деньги считаются триллионами, поэтому это не самый разумный вариант.

Типы с плавающей точкой

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

Подходящие типы данных

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

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

И последнее, но не менее важное: подходящий тип данных сильно зависит от языка и его возможностей.

Другие проблемы

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

Мультивалютные программы также должны учитывать тот факт, что разные валюты имеют разную точность. Округление может быть предписано стандартами бухгалтерского учета.

person Ondrej Tucny    schedule 18.03.2011
comment
Ондрей, хорошее замечание по поводу промежуточных вычислений. С целым числом, представляющим валюту, вы фактически заставляете округлять до ближайшего пенни после каждого шага многоэтапного вычисления, что может не требоваться. Не могли бы вы прояснить / уточнить ваш другой момент, касающийся очень ограниченного представимого диапазона? - person Jon Schneider; 19.03.2011
comment
Отредактировал свой ответ, чтобы объяснить больше. - person Ondrej Tucny; 19.03.2011
comment
Если программа будет использоваться для расчета мировых экономических данных с точностью до копейки, 64-битного целого числа может оказаться недостаточно, но сколько программ будет использоваться для этого? В большинстве финансовых расчетов даже 32-битных целых чисел было бы достаточно для хранения большинства значений, если бы можно было приспособить промежуточные вычисления к 64-битным перед их уменьшением. - person supercat; 18.11.2012
comment
@supercat То есть 640 Кб хватит на всякую логику :-) - person Ondrej Tucny; 21.11.2012
comment
@OndrejTucny: я не выступал за использование 32-битных значений для финансовых расчетов (так как они едва ли адекватны), а скорее предлагал, если 32-битные значения находятся в правильном приближении к тому, что требуется, 64-битные переменные, которые могут обрабатывать числа, которые в четыре миллиарда раз больше, должно хватить. Между прочим, что касается примечания 640 КБ, даже если г-н Гейтс действительно это сказал, стоит отметить, что (1) инженеры ПК стояли перед выбором не между 640 КБ или неограниченным объемом памяти с прямым доступом; вероятно, это было между 512 КБ, 640 КБ или 768 КБ. На самом деле особой разницы нет. - person supercat; 21.11.2012
comment
(2) Как только память стала доступной, Microsoft максимально эффективно преодолела этот барьер. Что касается хранения денежных сумм, если валюта деградирует до такой степени, что бизнес, для которого подходит неоптимизированная база данных, будет вести бизнес на сумму более триллиона долларов (предел для 64-битных типов, если базовая единица 0,000001 доллара США), способность бухгалтерского программного обеспечения обрабатывать такие числа будет наименьшей проблемой для бизнеса. - person supercat; 21.11.2012

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

person Andy    schedule 18.03.2011