JAVA解惑--长整除

[size=medium][color=gray] 之所以称为长整除是因为它所涉及的程序是有关于两个long型数值整除的。被除数表示的是一天里的微秒数;而除数表示的是一天里的毫秒数。这个程序会打印出什么结果呢?[/color][/size]
public class LongDivision{
public static void main(String[] args){
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);
}
}

[size=medium][color=gray] 这个题看起来相当直观。每天的毫秒数和每天的微秒数都是常量。为清楚起见,它们都被表示成积的形式。毫秒数与微秒数的不同之处只是少了最后一个因子1000。
除数和被除数都是long类型的,long类型大到可以很容易地保存这两个乘积而不产生溢出。因此看起来程序打印的结果必定是1000.然而它打印的是5.这里面到底发生了什么?
问题在于常数MICROS_PER_DAY的计算“确实”溢出了。尽管计算的结果很适合放入long中,并且其空间还是有富余的,但是这个结果并不适合放入int中。这个计算完全是以int运算来执行的,并且只有在运算完成之后,其结果才被提升到long,而此时已经太迟了:计算已经溢出,它返回一个小于200倍的数值。从int提升到long是一种拓宽原始类型转换,它保留了不正确的数值,这个数值之后被MILLIS_PER_DAY整除,而MILLIS_PER_DAY的计算是正确的,这样整除的结果就得到了5。
为什么计算是以int运算来执行呢?因为所有的因子都是int数值。当两个int数值乘在一起,得到的还是int类型。Java不具有目标确定类型的特性,这是哟中语言特性,其含义是指存储结果的变量类型会影响到计算所使用的类型。
知道原因后我们很容易就可以更正这个程序,可以将每个语句的第一个因子转换成long再做其余运算。尽管这么做只在MICROS_PER_DAY表达式中是必需的,但是在两个乘积中都这么做是一个很好的方式。相似的,使用long作为乘积的“第一个”数值也并不是必须的,但是这么做也是一种很好的方式。下面的程序将打印出我们期望的结果:[/color][/size]
public class LongDivision{
public static void main(String[] args){
final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);
}
}

[size=medium][color=gray] 这个教训很简单:当你在操作很大的数字时,千万要提防溢出--它是一个缄默的杀手。即使用来保存结果的变量已经显得足够大,也并不意味着产生结果的计算具有正确的类型。当你拿不准时,就使用long来执行整个计算。[/color][/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值