Общая идея заключается в том, что вы не хотите использовать плавающую точку с валютой, потому что значения с конечным числом десятичных цифр могут быть периодическими в двоичном формате, а учитывая, что значения с плавающей точкой имеют конечную точность, это приводит к неожиданностям при суммированииих;обычный пример -
#include <stdio.h>
int main(void) {
double v = 0.;
for(int i=0; i<10; ++i) v+=0.1;
printf("%0.18g\n", v-1.0f);
return 0;
}
, который печатает -1.11022302462515654e-16
.
. Простой подход к решению проблемы - использовать интегральные значения для "наименьшегодробные единицы валюты " (спасибо @Justin за цитату);это гарантирует, что когда пользователь вводит $ 0,10, он точно представлен и не приводит к неожиданности округления, по крайней мере, пока мы имеем дело со значениями, где ожидается точная точность.
Это хорошо и объясняетценты, но почему long double
, а не какой-то целочисленный тип?Здесь я размышляю, но вижу две разумные мотивы:
- дробные суммы валюты - это то, что существует, как правило, для унитарных цен (например, цена за литр бензина);точность, как правило, не так важна - вы все равно умножите ее на другое значение с плавающей запятой - но вы хотите иметь возможность читать такие значения;
, но самое главное, исторически с плавающей запятойзначения имели лучшую точность по широкому спектру платформ, даже для интегральных значений.long long
(гарантированно не менее 64 бит) является недавним дополнением к стандарту, а long
, как правило, имеет ширину 32 бита: его денежные значения будут ограничены до скудных ~ 21 миллиона долларов.
OTOH, даже обычный double
на большинстве платформ имеет 53-значную мантиссу, что означает, что он может представлять в точности целые значения вплоть до 9007199254740991 - так, что-то вроде 90 тысяч миллиардов долларов;этого достаточно, чтобы точно представить государственный долг США в центах, так что, вероятно, достаточно точно для всего остального.Вероятно, они выбрали long
double
как «самый большой молот, который они могут бросить в задачу» (даже если в настоящее время он обычно такой же большой, как равнина double
).
Потому что это, кажется, включает в себя знание валюты, противоположной текущей локали ...
Да и нет;Я думаю, что идея состояла в том, что, пока вы используете соответствующие фасеты локали как для ввода, так и для вывода, вам просто не нужно заботиться - библиотека должна делать преобразования за вас, и вы просто работаете с числами, точная величина которыхне должно иметь большого значения для вас.
Это теория;но, как сказано в комментариях, локали C и C ++ являются плохо разработанным программным обеспечением с чрезмерно сложным дизайном, который, тем не менее, не подходит для тестирования в реальных условиях.
Честно говоря, я бы никогда не использовал этот материал«по-настоящему»:
- вы никогда не можете быть уверены в том, насколько обновлена стандартная библиотека, насколько она сломана (у меня когда-то был VC ++, когда я не мог выполнить обход италически локализованных чисел),если он на самом деле поддерживает валюты, которые вас интересуют.
- вам нужно нужно позаботиться о том, каково его понятие «наименьшей нефракционной единицы валюты», если вам нужно говорить с чем-либокроме текстового ввода-вывода в формате, ожидаемом библиотекой - скажем, вы должны получить цену акции из веб-службы или если у вас есть встроенные данные для объединения с пользовательским вводом;
- то же самое длясериализация в машиночитаемом формате;Вы не хотите подвергать себя капризам своей среды выполнения C и конфигурации ОС при хранении пользовательских данных, особенно если они должны обмениваться с другими приложениями, особенно если указанные приложения работают в другой среде выполнения C (это может дажебыть вашим собственным приложением, скомпилированным для другой операционной системы!) или другого языка.