我如何解释以下内容:
double o = 2.3;
int i = (int) (o * 100000.0);
double d = i / 100000.0;
System.out.println(d);
打印2.29999
double o = 2.3;
double i = o * 100000.0;
double d = i / 100000.0;
System.out.println(d);
打印2.3
将int除以double时,java首先将int转换为double,然后进行除法 - 如果是这样,两个代码块应该有效地打印相同的值吗?
似乎有一些我缺少的IEEE 754浮点精度规范和/或内联的jvm优化
double i = 2.3 * 100000.0;
double d = i / 100000.0;
如 double d = 2.3 * 100000.0 / 100000.0; 有效地取消了分裂并使其成为无操作。
思想?
答案 0 :(得分:9)
2.3在IEEE-754 64位二进制浮点中不能完全表示。您的第一个代码序列中会发生什么:
2.3
将转换为最接近的可表示值,2.29999999999999982236431605997495353221893310546875。int
时,转换会截断,产生229999。答案 1 :(得分:4)
似乎有一些我缺少的IEEE 754浮点精度规范
当你使用(int)
时,它会截断小数部分,无论它与下一个整数值有多接近。由于信息丢失,这是不可逆的,所以你不会得到相同的结果也就不足为奇了。
您可以做的是以下
double o = 2.3;
long l = Math.round(o * 100000.0);
double d = l / 100000.0;
System.out.println(d);
内联的jvm优化......使其成为无操作
JVM可能会对其进行优化,但不会更改结果。如果优化改变了结果,则它是优化器中的错误。
答案 2 :(得分:1)
double i = o * 100000.0;
此后i
的值为229999.99999999997
(您可以通过添加简单的打印声明自行查看;这是由于floating-point inaccuracies)。
int i = (int) (o * 100000.0);
此后i
的值为229999
(即由于int
演员而导致小数部分被截断的上述值。)
因此,在行
double d = i / 100000.0;
您在两个片段中使用两个数值不同的i
值(即它们相差约1),因此输出不同。
正确的说法是,当将int除以double时,int首先转换为double(这是通过字节码指令i2d
完成的)。