双c ++的算术错误

时间:2015-02-14 19:45:58

标签: c++ double floating-accuracy double-precision atof

我注意到使用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。

你知道发生了什么吗?

1 个答案:

答案 0 :(得分:1)

问题在于,通常不可能使用二进制浮点数精确表示小数十进制值。例如,0.1在使用1.000000000000000055511151231257827021181583404541015625E-1时表示为double(您可以使用此online analyzer来确定值)。使用这些舍入值进行计算时,必要二进制数字的数量将超过可以表示的数字,并且值将进一步舍入,从而引入更多错误。当然,所有这些都在Ed Heal的评论所指出的Goldberg's paper中有所涉及。

您可以使用许多替代表示来精确计算十进制值。除非表示使用任意大小的表示,否则它将仅在某些值范围内。典型的选择是:

  1. 使用大整数表示以及合适的小数表缩放。
  2. 数字字符串(或BCD)。
  3. 一个固定点表示,它基本上只是一个整数和一个固定的十进制指数,其中指数隐含在固定点类型中(或者,例如,模板参数)。
  4. 您不使用二进制浮点,而是使用十进制浮点数。浮点只是符号有效数指数的表示,其值计算为(-1) 签名 * 有效数字 * base exponent double使用2的基数,但对于十进制计算,您使用基数10
  5. 使用两个大整数可以将值表示为有理数。
  6. 还有其他几种选择,但上面的列表是我认为的实用选项。
  7. 根据实施的选择,不同的操作或多或少易于实施,确切的操作也各不相同。例如,除了使用有理运算的表示之外,当除数不能表示为25的乘积时,除非总是四舍五入。

    哪种表示最适合您的应用程序取决于您的需求。如果您的交易价格仅为股票的典型范围,则定点表示可能有效。如果您需要涵盖财务中可能遇到的各种价值,例如国债和利率,您的固定点表示需要超过64位,十进制浮点表示可能是更好的表示。根据您是否需要传输和/或存储值,可能不需要固定大小的表示,在这种情况下,其他表示可能是合理的选择。