std :: pow在32位和64位应用程序中产生不同的结果

Raj*_*hDA 6 c++ x86-64 c++11

我发现一些复杂计算的结果不匹配.当我彻底观察到中间结果时,它的std :: pow函数会产生不匹配.以下是输入/输出.

long double dvalue = 2.7182818284589998;
long double dexp = -0.21074699576017999;
long double result = std::powl( dvalue, dexp); 
Run Code Online (Sandbox Code Playgroud)

64位 - >结果= 0.80997896907296496和32位 - >结果= 0.80997896907296507

我正在使用VS2008.我已尝试过其他功能的pow功能,需要很长的双倍并返回长双,但仍然看到相同的差异.

double pow( double base, double exponent );

long double powl( long double base, long double exponent );

我已经阅读了一些关于此的信息:

Intel x86处理器内部使用80位扩展精度,而double通常是64位宽.不同的优化级别会影响来自CPU的浮点值保存到内存中的频率,从而将80位精度舍入为64位精度.或者,使用long double类型,通常在gcc上为80位宽,以避免从80位到64位精度的舍入.

有人能让我清楚地了解差异和克服这种差异的方法.

Adr*_*thy 5

可能发生的情况是,32 位构建使用 80 位 FPU 寄存器进行计算,而 64 位构建使用 64 位值的 SIMD 操作,从而导致轻微的差异。请注意,两个答案都同意 14 位小数,这大约是您对 64 位浮点值所能期望的最佳值。

Visual C++ 提供了编译器选项,让您可以选择在浮点运算方面您更喜欢速度、一致性还是精度。使用这些选项(例如/fp:strict),如果这对您很重要,您可能可以在两个版本之间获得一致的值。

另请注意,VC++2008 相当旧。新版本修复了许多错误,包括一些与浮点相关的错误。(自 2008 年以来,开源软件中的流行实现strtod已检测到并修复了错误。)除了 80 位和 64 位操作之间的精度差异之外,您还可能会遇到解析和显示错误。尽管如此,浮点还是很困难,而且错误仍然存​​在


小智 2

关于浮点计算要理解的最重要的一点是它们(几乎总是)不精确。大多数数字不能精确地表示为浮点数。即使计算结果可以准确表示,实际计算的结果仍然可能不完全正确。

处理这个问题的方法是编写不依赖于获得准确结果的代码。例如,您几乎不应该测试浮点数的相等性。或者,如果您需要测试一个数字是否为正数,您的程序可能需要拒绝极小的正数(它们近似为负数)或接受极小的负数(它们近似为正数)。

同样,您应该尽量避免数值不稳定的算法,因为这些小错误很快就会爆发;相反,您应该尝试使用数值稳定的算法,因为它们是容错的。

如何做好数值计算是一门完整的研究领域!

  • 这个答案与问题无关。浮点计算可能不精确,但它们需要是确定性的(IEEE 标准)。问题是为什么相同的计算、相同的数据类型、不同的架构上存在差异。您将舍入误差与确定性行为混淆了。 (5认同)