我知道由于舍入错误,浮点数不适合存储货币值.有没有一种标准的方式来代表C++中的钱?
我查看过boost库并没有发现它.在java中,似乎BigInteger就是这样,但我找不到C++中的等价物.我可以写自己的钱类,但如果有测试的话,我宁愿不这样做.
不要将它存储为美分,因为当税收和利息快速增加时,你会积累错误.至少,保留额外的两位有效数字:12.45美元将存储为124,500.如果你将它保存在一个带符号的32位整数中,你将有200,000美元可以使用(正面或负面).如果您需要更大的数字或更高的精度,签名的64位整数可能会为您提供长时间所需的所有空间.
将此值包装在类中可能会有所帮助,为您提供一个位置来创建这些值,对它们进行算术运算以及格式化它们以供显示.这也将为您提供一个中心位置来携带它所存储的货币(美元,加元,欧元等).
在实际的金融系统中处理过这个问题后,我可以告诉你,你可能想要使用一个至少有6位小数位数的数字(假设为美元).希望既然你在谈论货币价值,你就不会在这里摆脱困境.有关于向C++添加小数类型的建议,但我不知道其中有任何实际存在.
在这里使用的最好的本机C++类型将是long double.
使用int的其他方法的问题是你必须存储的不仅仅是你的分数.通常情况下,金融交易会乘以非整数值,这会让您遇到麻烦,因为100.25美元转换为10025*0.000123523(例如APR)会导致问题.你最终将最终进入浮点土地并且转换将花费你很多.
现在问题不会发生在大多数简单的情况下.我会给你一个确切的例子:
给定几千个货币值,如果您将每个货币值乘以一个百分比然后将它们相加,那么如果您没有保留足够的小数位,则最终会得到一个不同的数字.现在这可能在某些情况下起作用,但是你很快就会有几便士.根据我的一般经验,确保您保持最多6位小数的精度(确保剩余的精度可用于整个数字部分).
还要明白,如果以不太精确的方式进行数学运算,那么存储它的类型并不重要.如果你的数学是在单精度的土地上完成的,那么你是否以双精度存储它并不重要.您的精度对于最不精确的计算是正确的.
现在说,如果除了简单的加法或减法之外你没有数学然后存储数字那么你就没事了,但只要出现比这更复杂的东西,你就会遇到麻烦.
查看相对较新的Intelr十进制浮点数学库.它专门用于财务应用程序,并实现了二进制浮点运算(IEEE 754r)的一些新标准.
最大的问题是四舍五入!
42,50€中的19%= 8,075€.由于德国的四舍五入规则,这是8,08欧元.问题是,(至少在我的机器上)8,075不能表示为double.即使我将调试器中的变量更改为此值,我最终得到8,0749999 ....
这就是我的舍入函数(以及我能想到的任何其他浮点逻辑)失败的地方,因为它产生了8,07€.有效数字为4,因此值向下舍入.这是完全错误的,除非您尽可能避免使用浮点值,否则您无法做任何事情.
如果您代表42,50€作为Integer 42500000,它会很有效.
42500000*19/100 = 8075000.现在您可以应用8080000以上的舍入规则.出于显示原因,可以很容易地将其转换为货币值.8,08€.
但是我总是将它包含在课堂上.
我建议你保留一个变量,而不是美元.这应该删除舍入错误.以标准美元/美分格式显示它应该是一个视图问题.
无论你决定使用哪种类型,我都建议将其包装在"typedef"中,这样你就可以在不同的时间更改它.
了解您的数据范围.
浮点数仅适用于6到7位精度,因此这意味着最大值约为+ -9999.99而不进行舍入.对大多数金融应用来说都没用.
双倍适用于13位数,因此:+ -99,999,999,999.99,使用大数字时仍要小心.认识到减去两个相似的结果带走了大部分精度(参见有关潜在问题的数值分析书).
32位整数好到+ -2亿(缩小到便士将下降2位小数)
64位整数将处理任何金钱,但再次,转换时要小心,并乘以您的应用程序中可能是浮动/双倍的各种费率.
关键是要了解您的问题域.您对准确性有哪些法律要求?你将如何显示这些值?转换的频率如何?你需要国际化吗?在做出决定之前,请确保您可以回答这些问题.
您可以尝试十进制数据类型:
https://github.com/vpiotr/decimal_for_cpp
旨在存储以货币为导向的价值(货币余额,货币汇率,利率),用户定义的精确度.最多19位数.
它是C++的仅限标头的解决方案.
您说您已经查看了boost库,但是在那儿什么也没找到。但是这里有multiprecision / cpp_dec_float,它表示:
此类型的基数为10。因此,其行为可能与base-2类型略有不同。
因此,如果您已经在使用Boost,那么这对于货币值和操作应该是有利的,因为它的基数为10,数字精度为50或100位(很多)。
看到:
#include#include #include int main() { float bogus = 1.0 / 3.0; boost::multiprecision::cpp_dec_float_50 correct = 1.0 / 3.0; std::cout << std::setprecision(16) << std::fixed << "float: " << bogus << std::endl << "cpp_dec_float: " << correct << std::endl; return 0; }
输出:
浮动:0.3333333432674408
cpp_dec_float:0.3333333333333333
*我并不是说float(以2为底)是不好的,而十进制(以10为底)是好的。他们只是表现不同...
**我知道这是一个古老的文章,并且boost :: multiprecision是在2013年推出的,因此想在这里进行评论。