双C++的算术错误

Arithmetic error with double c++

我注意到在一些使用 double 的算术计算中有一个小错误。真的很奇怪,总是有一个小错误and/or一个额外的有效数字。

首先,我使用 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()); 

然后我在做算术(来自其他class,两个不同的对象):

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。

你知道这是怎么回事吗??

问题在于,通常不可能使用二进制浮点数来精确表示小数值。比如0.1在使用double时表示为1.000000000000000055511151231257827021181583404541015625E-1(可以用Ed Heal的注释指向的这个online analyzer to determine the values). When computing with these rounded values the number of necessary binary digits will exceed those which can be represented and the value will be further rounded, introducing more error. Of course, all this is covered in Goldberg's paper

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

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

根据实现的选择,不同的操作或多或少容易实现,具体的操作也会有所不同。例如,除了使用有理运算的表示之外,当除数不能表示为 25.

的乘积时,除法将始终四舍五入

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