Java vs C浮点:"x*x"与"pow(x,2)"不同?

mar*_*ark 18 c java floating-point floating-accuracy

为什么这是真的?与C相比,Java甚至Java Math.pow方法将两个浮点数相乘时,Java似乎会产生一个小差异的结果.

Java的:

float a = 0.88276923;

double b = a * a;   // b becomes 0.779281497001648  <---- what???
b = Math.pow(a,2);  // b becomes 0.7792815081874238
Run Code Online (Sandbox Code Playgroud)

C:

float a = 0.88276923;

double b = a * a;   // b becomes 0.7792815081874238
pow(a,2);           // b becomes 0.7792815081874238
Run Code Online (Sandbox Code Playgroud)

更新:根据Ed S.的评论,我还发现C行为会根据编译器而改变.使用gcc似乎与Java行为相匹配.使用visual studio(取决于您的目标平台),它可以产生上面看到的结果或Java中看到的结果.啊.

Ed *_* S. 16

由于PST和trutheality已经明智地指出,C正在推进floatdouble 乘法.实际上,当它们被推入堆栈时,它们被提升为80位扩展精度值.这是汇编输出(VS2005 x86 C89)

    double b = a * a;
00411397  fld         dword ptr [a] 
0041139A  fmul        dword ptr [a] 
0041139D  fstp        qword ptr [b] 
Run Code Online (Sandbox Code Playgroud)

FLD指令

FLD指令将32位,64位或80位浮点值加载到堆栈中.在将值推入浮点堆栈之前,此指令将32位和64位操作数转换为80位扩展精度值.


有趣的是,如果我构建到目标x64,movss则使用该指令并获得一个值0.779281497001648作为结果,即您在java示例中看到的内容.试试看.

  • +1.现在,在C标准中(并且不要忘记指定哪个草稿!)是否存在可以被解释为实现定义的行为的vauge语句.... ;-) (2认同)

tru*_*ity 10

Java的用途

double b = a * a;
Run Code Online (Sandbox Code Playgroud)

首先乘以a * a(32位)float,并double在分配时将结果转换为(64位)b.

b = Math.pow(a,2);
Run Code Online (Sandbox Code Playgroud)

首先转换a为(64位)double(因为参数为Math.poware double, double)然后将其平方.

让我感到困惑的是,为什么C似乎把它a放到了double第一位

double b = a * a;
Run Code Online (Sandbox Code Playgroud)

这是标准吗?

编辑:我依稀记得C不需要特定的实现(就使用了多少位而言)数字......这是在发生什么?你float的64位?(在Java中,a float总是32位,a double总是64位).

编辑: Ed S.的回答和标记的评论,不同的编译器给出不同的结果表明C结果是实现和体系结构特定的.