System.out.println(2.00-1.10)
和
System.out.println((double)(2.00-1.10))
两者输出相同的结果0.8999999999999999,但是
System.out.println((float)(2.00-1.10))
输出0.9.
也许默认情况下Java执行double计算,那么为什么向下转换会纠正结果?
如果将1.1转换为1.100000000000001,那么为什么呢
System.out.println((double)(1.10))仅输出1.1.
编辑:要了解为什么会发生这种情况,我们需要了解这两个答案.首先,规范表示在较低级别实际上是不同的.接下来如何更改/舍入/舍入toString的返回值与最接近的参数的double.
解决方法
Double.toString(double)
基本上在它产生的输出中执行一些舍入. Double.toString算法在整个Java SE中使用,包括例如System.out的PrintStream.println(double).文档说明了这一点:
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part,and beyond that as many,but only as many,more digits as are needed to uniquely distinguish the argument value from adjacent values of type
double
. That is,suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be thedouble
value nearest to x; or if twodouble
values are equally close to x,then d must be one of them and the least significant bit of the significand of d must be0
.
换句话说,它表示toString的返回值不一定是参数的精确十进制表示.唯一的保证是(粗略地说)参数比任何其他双值更接近返回值.
因此,当您执行类似System.out.println(1.10)和1.10的操作时,这并不意味着传入的值实际上等于基数10值1.10.相反,基本上会发生以下情况:
>首先,在编译期间,检查文字1.10并舍入以产生最接近的double值. (它在JLS here中说,对此的规则例如在Double.valueOf(String)
中详细说明为double.)
>其次,当程序运行时,Double.toString生成一个十进制值的字符串表示形式,上一步生成的double值比任何其他double值更接近.
恰好在第二步中转换为String通常会生成一个与第一步中的文字相同的String.我认为这是设计的.无论如何,文字,例如1.10不会产生一个精确等于1.10的双精度值.
您可以使用BigDecimal(double)
构造函数发现double(或float的实际值,因为它们总是可以放在double中):
When a
double
must be used as a source for aBigDecimal
,note that this constructor provides an exact conversion; it does not give the same result as converting thedouble
to aString
using theDouble.toString(double)
method and then using theBigDecimal(String)
constructor. To get that result,use thestatic
valueOf(double)
method.
// 0.899999999999999911182158029987476766109466552734375 System.out.println(new BigDecimal((double) ( 2.00 - 1.10 ))); // 0.89999997615814208984375 System.out.println(new BigDecimal((float) ( 2.00 - 1.10 )));
你可以看到,结果都不是0.9.在这种情况下,Float.toString恰好产生0.9而Double.toString则不然,这或多或少只是巧合.
作为旁注,(双)(2.00 – 1.10)是一个冗余演员. 2.00和1.10已经是双重文字,因此评估表达式的结果已经是双倍的.另外,要减去float,你需要转换两个操作数,如(float)2.00 – (float)1.10或使用浮动文字,如2.00f – 1.10f. (float)(2.00 – 1.10)仅将结果转换为float.