2013-09-05 116 views
2

我想这是一个相当基本的问题,但我不知道为什么这两个代码给出不同的结果。 Pentium是否处理变量Divider与中间值(256.0 /(double)k)不同?这两个简单的代码为什么会给出不同的结果?

int j=64, k=20; 
double x, y, Divider; 

Divider = 256.0/(double)k; 
x = (double)j/Divider - 5.0; 
y = (double)j/(256.0/(double)k) - 5.0; 

结果: X = -2.77555756156289E-16 Y = 0.0

作为参考,我使用Embarcadero公司XE3 C++生成器,其给出作为生成器相同的结果6.我使用的默认编译器设置。

+0

一些编译器保证他们总是将x和y的计算编译为等效的指令。有些编译器保证它们不会生成相同的指令,因为将'double'类型的中间计算分配给'double'左值具有影响。有些编译器甚至不知道有什么区别。如果没有关于编译器的信息,很难说更多,但查找'FLT_EVAL_METHOD'(在C99中引入)以获取更多信息。 –

回答

2

问题是,当您不使用SSE指令时,编译器可能会选择使用本机387浮点单位进行中间计算,该单位将执行所有80位值的计算。

在计算x时,通过将中间值存储在Divisor中,强制中间值被截断为64位。然后下一个分部使用一个已经舍入的除数;由于分工的精度足够高,所以结果与5.0略有不同。

y的计算中,除法以80位精度完成,因此结果更接近5.0(足够接近以至截断为64位使其为0)。

如果您使用SSE(只有64位寄存器),您还可以获得两个0值,否则强制编译器以64位精度执行所有计算。

0

也许是优化器。在第二个

y = (double)j/(256.0/(double)k) 

是相同的数学上

y = (double)j * (double)k/256.0 

此只做一次除法(巧合干净划分),并且受以下的舍入误差。对于x它被迫做两个师。

+0

括号强制首先执行“256.0 /(double)k”。从其他角度来看,由于'j'和'256'是2的幂,并且如果编译器忽略了括号,'j/256'将被精确计算。 –

+0

是的,但我已经读过一些英特尔编译器会默认使用'-fp model fast = 1',这可能会导致不太精确的结果。编译器不会忽略括号,但它可能知道足以将“j”和“k”相乘。海报并没有说他使用了什么编译器,所以这只是一个猜测。 – dseiple

+0

我正在使用Embarcadero的C++ Builder –

相关问题