简单的浮点计算产生不同的结果

时间:2017-08-25 21:30:17

标签: c++ visual-c++

我正在使用Visual Studio 2008并遇到过这样一种情况,即同一类库的两个不同版本中的相同代码显然会产生不同的答案。

以下代码反映了我重现问题的尝试。它只需要两对数字(cx,cy)和(rx,ry),减去它们,并以十进制和十六进制格式显示结果(tx,ty)。

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>

using namespace std;

string dhex(double x) {    // double to hex
   union {
      unsigned  long long n;
      double    d;
      } value;
   value.d = x;
   std::ostringstream buf;
   buf <<  "0x" << std::hex << std::setfill('0') << std::setw(16) << value.n;
   return buf.str();
   }
double i64tod(unsigned long long n) {  // hex to double
   double *DP = (double *) &n;
   return *DP;
   }
int main(int argc, char **argv) {
   double tx, ty, cx, cy, rx, ry;
   cx   = i64tod(0x3fb63f141205bc02); cy = i64tod(0x40019eb851eb851f);
   rx   = i64tod(0x3fa222fa84a5161c); ry = i64tod(0x40011f8441720667);
   tx   = cx - rx;
   ty   = cy - ry;
   cout << setprecision(22);
   cout << "  cx = " << setw(22) << cx << ", cy = " << setw(22) << cy
        << " (" << dhex(cx) << ", " << dhex(cy) << ")" << endl;
   cout << "  rx = " << setw(22) << rx << ", ry = " << setw(22) << ry 
        << " (" << dhex(rx) << ", " << dhex(ry) << ")" << endl;
   cout << "  tx = " << setw(22) << tx << ", ty = " << setw(22) << ty 
        << " (" << dhex(tx) << ", " << dhex(ty) << ")" << endl;
   return 0;
   }

此代码的输出为:

  cx =   0.086900000000000005, cy =   2.2025000000000001   (0x3fb63f141205bc02, 0x40019eb851eb851f)
  rx =   0.035423115436554492, ry =   2.1403889763758346   (0x3fa222fa84a5161c, 0x40011f8441720667)
  tx =   0.051476884563445513, ty =   0.06211102362416554  (0x3faa5b2d9f6661e8, 0x3fafcd041e5fae00)

有问题的应用程序有一个类库,它是一个“池引擎”,即。它模拟了水池/斯诺克投篮的物理特性。

最近对该库进行的一系列更改导致验证测试失败,其中涉及应生成特定表状态的特定镜头序列。

我将其追踪到那个简单的减法操作。当新版本执行减法时,它会产生:

  cx =   0.086900000000000005, cy =   2.2025000000000001   (0x3fb63f141205bc02, 0x40019eb851eb851f)
  rx =   0.035423115436554492, ry =   2.1403889763758346   (0x3fa222fa84a5161c, 0x40011f8441720667)
  tx =   0.051476884563445513, ty =  ?0.062111023624165547 (0x3faa5b2d9f6661e8, 0x3fafcd041e5fae01)

正如你所看到的,区别在于最低位(ty),但有时甚至更多。这是另一对点值的结果:

  cx =  1.0641,                cy =  -0.0545               (0x3ff1068db8bac711, 0xbfabe76c8b439581)
  rx =  1.0878512271746064,    ry =   0.022594280641953058 (0x3ff167d6b03a0dee, 0x3f9722f481bc3f0d)
  tx = -0.023751227174606315,  ty =  -0.077094280641953061 (0xbf98523ddfd1b740, 0xbfb3bc736610da84)

上面的程序和较旧的库版本也同意这个案例,但在这种情况下,新的库版本给出了不同的答案(对于tx):

 tx = -0.023751227174606343,  ty =  -0.077094280641953061 (0xbf98523ddfd1b748, 0xbfb3bc736610da84)

这两个版本的库都有相同的编译器选项,并且所讨论的函数(碰撞处理程序)没有被更改所改变(我只是通过替换没有带结构的方法的类来简化库)。

我应该补充一点,当新版本获得不同的结果时,至少它是一致的,即。它总是会产生不同的答案。

我可以简单地接受新版本并将验证测试替换为匹配的版本,但我真的想知道为什么会发生这种情况。

为了记录,我试图通过改变编译器选项等来获得上面的独立程序以提供“替代”答案,但没有运气。它只能在新的库版本中原位失败。

0 个答案:

没有答案