Java vs C浮点;x*x";不同于;pow(x,2)“;?

Java vs C浮点;x*x";不同于;pow(x,2)“;?,java,c,floating-point,floating-accuracy,Java,C,Floating Point,Floating Accuracy,为什么这是真的?与C甚至Java Math.pow方法相比,Java在乘以两个浮点值时似乎产生了一个差异很小的结果 爪哇: 更新:根据Ed S.的评论,我还发现C的行为会随着编译器的不同而变化。使用gcc,它似乎与Java行为相匹配。使用VisualStudio(取决于您的目标平台),它可以生成上面看到的结果或Java中看到的结果。啊。Java做什么 double b = a * a; 首先将a*a乘以(32位)float,并在分配给b时将结果转换为(64位)double b = Math.p

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

爪哇:

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

Java做什么

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

b = Math.pow(a,2);
首先将
a
转换为(64位)
double
(因为
Math.pow
的参数是
double,double
),然后将其平方

(对我来说)令人不解的是,为什么C似乎将
a
转换为
double

double b = a * a;
这在标准中吗

编辑:我模模糊糊地记得C不需要特定的数字实现(就使用的位数而言)。。。这是怎么回事?您的
浮点值是64位吗?(在Java中,
float
始终为32位,
double
始终为64位)


编辑:Ed S.的回答和mark关于不同编译器给出不同结果的评论都表明C结果是特定于实现和架构的。

正如pst和trutheality已经明智地指出的那样,C在乘法之前将
浮点
提升为
。实际上,当它们被推到堆栈上时,它们被提升为80位扩展精度值。以下是汇编程序输出(VS2005 x86 C89)

FLD指令

FLD指令将32位、64位或80位浮点值加载到堆栈中此指令将32位和64位操作数转换为80位扩展精度值,然后将该值推送到浮点堆栈上



有趣的是,如果我构建的目标是x64,那么将使用
movss
指令,结果得到
0.779281497001648
,即您在java示例中看到的值。试试看。

啊,浮点运算。一个纯粹的精确性和可靠性的堡垒。我知道浮动并不精确。不过,我希望它们的不精确性是一致的。你不是用C++编译器编译C代码,因此使用<代码>浮点< /C> >超载版本<代码> POW我使用VS2005进行了测试,C结果是相同的(实际上使用的是C89编译器)。。。直到我以x64为目标,在这种情况下,
fld
指令将被丢弃,转而支持
movss
,您将获得java行为。哦,编程的乐趣。我想知道是否有编译时计算(优化)也在发生?(尽管我怀疑在现代机器/编译器上
sizeof(float)==sizeof(double)
;-)在我的机器上,它们被推到堆栈上时会被提升。见:+1。现在,在C标准中(别忘了指定哪一个草案!)有一个vauge语句,可以解释为两个上的实现定义行为…;-)@pst:出于好奇尝试了针对x64的攻击,您看到java行为不再使用
fld
指令(至少在我的设置中)。我想象了一些鬼鬼祟祟的东西,但不是这个鬼鬼祟祟的东西。我希望我能再投一票。
b = Math.pow(a,2);
double b = a * a;
    double b = a * a;
00411397  fld         dword ptr [a] 
0041139A  fmul        dword ptr [a] 
0041139D  fstp        qword ptr [b]