Java谜题1:表达式谜题
NO.2 找零时刻
public class Change{ public static void main(String args[]){ System.out.println(2.00 - 1.10); } }
打印结果:0.8999999999999999根据Double.toString 文档中所设定的将double 类型的值转换为字符串的规则,该程序打印出来的小数,是足以将double 类型的值与最靠近它的临近值区分出来的最短的小数,它在小数点之前和之后都至少有一位。因此,看起来,该程序应该打印0.9 是合理的。这么分析可能显得很合理,但是并不正确。
问题在于1.1 这个数字不能被精确表示成为一个double,因此它被表示成为最接近它的double 值。并不是所有的小数都可以用二进制浮点数来精确表示的。
解决该问题的一种方式是使用某种整数类型,例如int 或long,并且以分为单位来执行计算。解决该问题的另一种方式是使用执行精确小数运算的BigDecimal。它还可以通过JDBC 与SQL DECIMAL 类型进行互操作。这里要告诫你一点: 一定要用BigDecimal(String)构造器,而千万不要用BigDecimal(double)。
后一个构造器将用它的参数的“精确”值来创建一个实例:new BigDecimal(.1)将返回一个表示0.100000000000000055511151231257827021181583404541015625 的BigDecimal。
import java.math.BigDecimal; public class Change1{ public static void main(String args[]){ System.out.println(new BigDecimal("2.00"). subtract(new BigDecimal("1.10"))); } }
Java 并没有为BigDecimal 提供任何语言上的支持。使用BigDecimal 的计算很有可能比那些使用原始类型的计算要慢一些。
总之, 在需要精确答案的地方,要避免使用float 和double;对于货币计算,要使用int、long 或BigDecimal。
对于语言设计者来说,应该考虑对小数运算提供语言支持。
一种方式是提供对操作符重载的有限支持,以使得运算符可以被塑造为能够对数值引用类型起作用,例如BigDecimal。
另一种方式是提供原始的小数类型,就像COBOL 与PL/I 所作的一样。