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正在推进float到double 前乘法.实际上,当它们被推入堆栈时,它们被提升为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示例中看到的内容.试试看.
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结果是实现和体系结构特定的.