0

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

如您所见,两种计算都存在错误。差异 = 3.463 而不是 3.4628。并且 diff2 = 3.742 而不是 3.7416。

你知道怎么回事吗??

4

1 回答 1

1

问题是通常不可能使用二进制浮点数精确地表示小数。例如,0.1表示为1.000000000000000055511151231257827021181583404541015625E-1使用时double(您可以使用此在线分析器来确定值)。当使用这些四舍五入的值进行计算时,必要的二进制位数将超过可以表示的位数,并且该值将进一步四舍五入,从而引入更多错误。当然,所有这些都包含在Ed Heal 的评论所指出的Goldberg 的论文中。

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

  1. 使用大整数表示和适当的十进制缩放。
  2. 数字字符串(或 BCD)。
  3. 一种定点表示,它基本上只是一个整数和一个固定的十进制指数,其中指数隐含在定点类型(或,例如,模板参数)中。
  4. 您将使用十进制浮点数,而不是使用二进制浮点数。浮点数只是符号有效数字和指数的表示,其值被计算为 (-1)符号*有效数字* 基指数double使用 base ,2但对于十进制计算,您将使用 base 10
  5. 使用两个大整数,您可以将值表示为有理数。
  6. 还有其他几个选择,但上面的列表是我认为实用的选择。

根据实现的选择,不同的操作或多或少容易实现,并且确切的操作会有所不同。例如,除了使用有理运算的表示之外,当除数不能表示为 和 的乘积时,除数总是会2四舍五入5

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

于 2015-02-14T20:43:02.817 回答