【问题标题】:Java vs C floating point: "x * x" differs from "pow(x,2)"?Java vs C 浮点数:“x * x”与“pow(x,2)”不同?
【发布时间】:2012-04-29 08:25:32
【问题描述】:

为什么这是真的?与 C 甚至 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

C:

float a = 0.88276923;

double b = a * a;   // b becomes 0.7792815081874238
pow(a,2);           // b becomes 0.7792815081874238

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

【问题讨论】:

  • 啊,浮点运算。准确性和可靠性的纯粹堡垒。
  • 我知道浮点数并不精确。但是,我希望它们的不精确性是一致的。
  • 您没有使用 C++ 编译器编译 C 代码,因此使用了 float 的重载版本 pow 是吗? float pow(float base, float exponent)
  • 我使用 VS2005 进行了测试,C 结果是相同的(实际上是使用 C89 编译器)......直到我以 x64 为目标,在这种情况下,fld 指令被删除以支持@ 987654329@ 你得到了 java 行为。哦,编程的乐趣。

标签: java c floating-point floating-accuracy


【解决方案1】:

正如 pst 和真实性已经明智地指出的那样,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] 

FLD 指令

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


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

【讨论】:

  • +1。现在,在 C 标准中的什么位置(不要忘记指定哪个草案!)是否有一个可以解释为两个实现定义的行为的 vauge 声明...... ;-)
  • @pst:出于好奇尝试了它以 x64 为目标,您会看到 java 行为,因为不再使用 fld 指令(至少在我的设置中)。
  • 我想象了一些鬼鬼祟祟的东西,但不是这么鬼鬼祟祟。我希望我能再投一票。
【解决方案2】:

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 不需要数字的特定实现(就使用了多少位而言)......这是怎么回事?你的floats 是 64 位吗? (在 Java 中,float 始终为 32 位,double 始终为 64 位。

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

【讨论】:

  • 我想知道是否也发生了任何编译时评估(优化)?
  • (虽然我怀疑sizeof(float) == sizeof(double) 在现代机器/编译器上 ;-)
  • 在我的机器上,它们在被推入堆栈时会被提升。见:The FLD Instruction
猜你喜欢
  • 2021-05-14
  • 2017-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多