我注意到使用double的一些算术计算有一个小错误。这真的很奇怪,总是一个小错误和/或一个额外的重要数字。
首先我使用atof来转换一个有两个有效数字的数字,我正在从一个文本文件中读取(然后我将它们记录在一个向量上):
// Puts into vector
double ask_file, bid_file; // Values of ask and bid from file
double cur_conversion = 0.16;
ask_file = cur_conversion*atof(values[0].c_str());
bid_file = cur_conversion*atof(values[1].c_str());
然后我正在做算术(来自其他类,两个不同的对象):
diff = OKC->bid_val() - BV->ask_val(); // diff
diff2 = OKC->ask_val() - BV->bid_val(); // diff2
这是输出:
BV Askfile: 245.267 Bidfile: 245.078
OKC Askfile: 248.82 Bidfile: 248.73
diff: 3.4628 diff2: 3.7416
如您所见,两次计算都有错误。 diff = 3.463而不是3.4628。并且diff2 = 3.742而不是3.7416。
你知道发生了什么吗?
答案 0 :(得分:1)
问题在于,通常不可能使用二进制浮点数精确表示小数十进制值。例如,0.1
在使用1.000000000000000055511151231257827021181583404541015625E-1
时表示为double
(您可以使用此online analyzer来确定值)。使用这些舍入值进行计算时,必要二进制数字的数量将超过可以表示的数字,并且值将进一步舍入,从而引入更多错误。当然,所有这些都在Ed Heal的评论所指出的Goldberg's paper中有所涉及。
您可以使用许多替代表示来精确计算十进制值。除非表示使用任意大小的表示,否则它将仅在某些值范围内。典型的选择是:
double
使用2
的基数,但对于十进制计算,您使用基数10
。根据实施的选择,不同的操作或多或少易于实施,确切的操作也各不相同。例如,除了使用有理运算的表示之外,当除数不能表示为2
和5
的乘积时,除非总是四舍五入。
哪种表示最适合您的应用程序取决于您的需求。如果您的交易价格仅为股票的典型范围,则定点表示可能有效。如果您需要涵盖财务中可能遇到的各种价值,例如国债和利率,您的固定点表示需要超过64位,十进制浮点表示可能是更好的表示。根据您是否需要传输和/或存储值,可能不需要固定大小的表示,在这种情况下,其他表示可能是合理的选择。