IT Notes‎ > ‎Java‎ > ‎Java Language‎ > ‎《Java 解惑》笔记‎ > ‎

Puzzle 3: Long Division

长整数的除法——大数溢出问题

运行下面的代码片段:
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);

最后打印出来的应该是10吧,错!是5。小改一下便可得到正常的结果1000:
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000L;
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000L;
System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);

注意上面两个整数的右边都添加了一个字母L。

虽然等号的左边定义的是long,但如果所有乘数都是int型的,那么就都按int型来计算,包括结果,如果有溢出的话,并不报错——右边按照int的型运算结束了,溢出也发生了,在cast成long型,错误就带过去了;改后的代码明确了右边运算的范围在long的范围里,没有溢出。

Java Puzzle曰:“当用到大数的时候,要留心溢出问题——它是个温柔的杀手。”(When working with large number, watch out for overflow -- it's a silent killer.),JP亦针对语言设计者有N曰,大致说,为啥Java不能像Ada那样在这种情况下就抛个错呢?为啥不能像Lisp那样去自动转个型呢?为啥不能像Modula-3那么那么做呢?——问题是,无论是Ada, Lisp or Modula-3,sorry啦,我都没用过,这段,当对我弹琴了一番,skim之!




  1. JSL 5.1.2  Widening Primitive Conversion
  2. TODO: 文中只是泛泛说了溢出问题导致起先得到的结果是5,但并没有说明是怎么溢出导致结果是5的,这个是需要具体分析一下的。引用的JSL中有符号扩展和零扩展相关内容,需要再了解一下;同时还引用的IEEE的浮点数工业标准,这个标准是怎么规定的?也需要读一下。

Comments