具有常数乘法/除法的Java双精度

时间:2012-07-16 11:41:05

标签: java double bytecode

  

可能重复:
  Retain precision with Doubles in java

你知道Java中这两个操作之间的区别吗?

final double m1 = 11d / 1e9; // gives 1.1e-8
final double m2 = 11d * 1e-9; // gives 1.1000000000000001e-8

我在生成的字节码中看到m2的预编译结果已经不是我预期的了 在javap -verbose -c的输出中,我可以看到以下值:

const #3 = double   1.1E-8d;
[...]
const #6 = double   1.1000000000000001E-8d;

当我在其他表达式中使用m1或m2时,我的结果并不相同。

当我在C中尝试相同的事情时,m1和m2严格来说是1.1e-8

我认为我的问题在于java处理双精度计算的方式,但我无法解释自己错过的内容。

3 个答案:

答案 0 :(得分:3)

Java和C之间没有区别,两者都遵循IEEE浮点标准。唯一的区别可能是你打印它的方式。确切的数字1.1e-8不能表示为double。输出的差异可能归因于如何累积表示错误的细节,以及用于打印结果的舍入。

答案 1 :(得分:1)

你所拥有的不同之处在于1e9是完全可以表示的,1e-9是不完全可表示的。小的表示错误会导致算术错误,您可以看到。

System.out.println(new BigDecimal(1e9));
System.out.println(new BigDecimal(1e-9));

打印

1000000000
1.0000000000000000622815914577798564188970686927859787829220294952392578125E-9

区别不在于您是否使用过*/,而是在一种情况下使用了整数而在另一种情况下使用了一小部分。

System.out.println(11 * 1e9);
System.out.println(11 * 1e-9);

打印

1.1E10
1.1000000000000001E-8

答案 2 :(得分:0)

如果您使用BigDecimal,如下所示:

BigDecimal a=new BigDecimal(1e-9);
BigDecimal b=new BigDecimal(11);
System.out.println(a.multiply(b).toString());

你会看到你的号码是

1.10000000000000006850975060355784206078677556206457666121423244476318359375E-8

JVM汇总您的号码并将其更改为:

1.1000000000000001e-8