sed*_*deh 24 java scientific-notation long-integer
我正在尝试编写一个代码来确定自1970年初以来的毫秒数何时将超过long的容量.以下代码似乎可以完成这项工作:
public class Y2K {
public static void main(String[] args) {
int year = 1970;
long cumSeconds = 0;
while (cumSeconds < Long.MAX_VALUE) {
// 31557600000 is the number of milliseconds in a year
cumSeconds += 3.15576E+10;
year++;
}
System.out.println(year);
}
}
Run Code Online (Sandbox Code Playgroud)
此代码在几秒钟内执行并打印292272992.如果不是使用科学记数法,我将cumSeconds写为31558000000L,程序似乎"永远"运行(我只是在10分钟左右后暂停).另请注意,以科学计数形式写入cumSeconds不需要指定数字最后为longL或l.
rge*_*man 41
它产生影响的原因是因为科学记数字3.1558E+10是double文字,而文字31558000000L当然是long文字.
这使得所有的差异的+=操作.
形式E1 op = E2的复合赋值表达式等效于E1 =(T)((E1)op(E2)),其中T是E1的类型,除了E1仅被评估一次.
基本上,long + = long产生一个long,但long + = double也产生一个long.
添加a时double,将初始值cumSeconds加宽为a double,然后进行加法.结果经历了缩小的原始转换回long.
将浮点数转换为整数类型T需要两个步骤:
- 在第一步中,如果T很长,则浮点数转换为long
(剪断)
否则,以下两种情况之一必须为真:
该值必须太小(大幅度或负无穷大的负值),第一步的结果是int或long类型的最小可表示值.
该值必须太大(大幅度或正无穷大的正值),第一步的结果是int或long类型的最大可表示值.
(大胆强调我的)
结果最终太大而无法在a中表示long,因此结果缩小到Long.MAX_VALUE,并且while循环结束.
但是,当您使用long文字时,您不断向偶数值添加偶数值,最终会溢出.这不会将值设置Long.MAX_VALUE为奇数,因此循环是无限的.
但是Long.MAX_VALUE,使用Java 1.8+,您可以明确地测试溢出,而不是依赖于最终产生的加法Math.addExact.
返回其参数的总和,如果结果溢出long则抛出异常.
抛出:
ArithmeticException- 如果结果溢出很长时间
关键的发现是,cumSeconds < Long.MAX_VALUE这里cumSeconds是一个long,如果只能是假的cumSeconds也正是Long.MAX_VALUE.
如果您使用长数进行计算,则需要相当长的时间才能准确地达到此值(如果达到此值),因为当您离开数字范围时,长算术会回绕.
当double值足够大时,使用双数进行算术将产生最大值.
@rgettman已经详细介绍了当你使用double而不是a long.时发生的围绕体操.但还有更多.
当你反复向a添加一个大数字时long,你最终会得到一个负面结果.例如,Long.MAX_VALUE + 1L = Long.MIN_VALUE.当发生这种情况时,您将无限期地重复该过程.
因此,如果您将代码更改为:
while (cumSeconds >= 0L) {
// 31557600000 is the number of milliseconds in a year
cumSeconds += 31557600000L;
Run Code Online (Sandbox Code Playgroud)
你会发现事情变得消极,因为cumSeconds滚了过来.
| 归档时间: |
|
| 查看次数: |
1263 次 |
| 最近记录: |