为什么std :: put_money()的分数?

时间:2018-05-22 19:29:00

标签: c++ locale money-format

我想知道为什么std::put_money()函数接受美分而不是美元。同样looking at the definition on cppreference,它没有说输入数字应该是什么。

我们必须在所述货币的最低十进制值处使用十进制数,这是真的吗? (即* 1.0* 100.0* 1000.0视情况而定?)因为这似乎包含了与当前语言环境相对的货币的知识...

1 个答案:

答案 0 :(得分:3)

一般的想法是你不想使用带货币的浮点数,因为具有有限数字的十进制数字的值可以是二进制的周期性的,并且假设浮点值具有有限的精度,这在求和时会导致意外他们;通常的例子是

#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

处理问题的一个简单方法是使用"the smallest non-fractional units of the currency"的积分值(感谢@Justin的引用);这可以确保当用户输入0.10美元时,它就是精确表示的,并且不会导致任何舍入意外,至少只要我们处理预期精确精度的值。

这很好,并解释了分数,但为什么long double而不是某种整体类型?在这里我猜测,但我看到两个合理的动机:

  • 货币的分数是存在的,通常是单一价格(例如每升汽油的价格);精度通常不会出现问题 - 无论如何你要将它乘以另一个浮点值 - 但你希望能够读取这些值;
  • 但最重要的是,历史上浮点值在广泛的平台上具有最佳精度,即使对于整数值也是如此。 long long(保证至少为64位)是标准的最新成员,而long通常是32位宽:它将货币价值上限限制在2100万美元左右。

    OTOH,即使是大多数平台上的普通double都有一个53位数的尾数,这意味着它可以代表高达9007199254740991的完全积分值 - 所以,就像9万亿美元;这足以将美国的公共债务精确地表示为美分,因此对于其他任何东西而言,它可能足够精确。他们可能选择 long double作为“他们可以解决问题的最大锤子”(即使现在它通常与普通double一样大)。

  

因为这似乎包含了与当前语言环境相对的货币的知识......

是和否;我认为这个想法是,只要您使用相关的区域设置方面进行输入和输出,您根本就不应该关心 - 图书馆应该为您进行转换,而您只需使用精确幅度的数字对你来说真的不重要。

这就是理论;但正如评论中所说,C和C ++语言环境是一个设计糟糕的软件,设计过于复杂,但在测试实际使用时却不尽如人意。

老实说,我绝不会将这些东西用于“真实”:

  • 你永远无法确定标准库的更新程度,它是多么破碎(我曾经让VC ++无法进行意大利本地化数字的往返),如果它实际上支持你关心的货币。 / LI> 如果您需要以图书馆期望的格式与文本IO之外的任何内容进行交谈,那么
  • 需要关心“最小的非分数单位货币”的概念 - 比如说,您必须从Web服务获取股票的价格,或者如果您有内置数据与用户输入结合;
  • 以机器可读格式进行序列化;您不希望在存储用户数据时暴露自己的C运行时和操作系统配置的变幻莫测,特别是如果要与其他应用程序交换它们,特别是如果所述应用程序在不同的C运行时运行(甚至可能是为不同的操作系统编译的自己的应用程序!)或其他语言。