2012-01-29 76 views
9

更大。如果我有一个分配龙+长不超过Long.MAX_VALUE

Long c = a + b; 

有没有一种简单的方法来检查a + b并不是越大/比Long.MAX_VALUE/Long.MIN_VALUE小?

+0

请参阅问题文本框右侧的**如何格式**框以及它上方的** [?] **链接(以及其下方的预览)正确设置问题的格式。 – 2012-01-29 22:18:56

+0

在汇编,将有可能检查* *携带国旗? – 2012-01-29 22:22:08

+0

我删除了[功课]标签,作为OP的评论跟帖,这是只有在那里偶然提及。 – 2012-01-29 23:01:01

回答

17

使用Guava,它是那样简单

long c = LongMath.checkedAdd(a, b); // throws an ArithmeticException on overflow 

是,我想认为,可读性很强确实如此。 (LongMath Javadoc here。)

为了公平起见,我会提到Apache Commons提供了ArithmeticUtils.addAndCheck(long, long)

如果你想知道他们是如何工作的,那么,答案是位两轮牛车为番石榴的一行:结果不会溢出,如果(a^b) < 0 | (a^(a + b)) >= 0。这是基于技巧,两个数字的按位异或是非负当且仅当它们具有相同的符号。

所以(a^b) < 0是真的如果ab有不同的迹象,如果是这样的话,它永远不会溢出。或者,如果(a^(a + b)) >= 0,则a + b具有相同的符号为a,所以也没溢出,变为负值。

(有关更多的技巧是这样,调查可爱的书Hacker's Delight

Apache使用基础上的ab符号更复杂的个案。

+0

+1番石榴。即使比较(如我最初所建议的)可能有效(尽管我太困了,不能正确地考虑它),但愿意使用即用功能 – Bozho 2012-01-29 22:28:29

+0

完全披露:我是“LongMath”的作者,其余的番石榴的common.math包...但@Bozho是正确的,它通常更好地依赖库代码而不是滚动自己的实现。(特别是,这个代码已经经过测试*非常详尽,所以你不必!) – 2012-01-29 22:32:33

+0

非常酷。添加另一个完整的库可能会导致这样一个简单的情况(检测溢出在这种情况下是微不足道的),但如果你已经*使用番石榴... – 2012-01-29 22:34:32

0

一种选择是使用BigInteger类做精确的计算,然后检查结果是否比有问题的值大于或更小。例如:

if (BigInteger.valueOf(a).add(BigInteger.valueOf(b)).compareTo(BigInteger.valueOf(Long.MAX_VALUE) > 1) { 
    /* Overflow occurred. */ 
} else { 
    /* No overflow occurred. 
} 

希望这有助于!

+0

如果你打算继续使用全功能'BigInteger',你可以检查'myBigInt.bitLength() 2012-01-29 22:26:30

+0

@LouisWasserman正确,因为小于,否则它会被一个关闭。我不认为这两个选项中的任何一个都是可读的,并且其中一个答案只需要Long.MAX_VALUE,而不是Long.MIN_VALUE ... – 2012-01-29 22:42:24

+0

一致认为这比它的可读性差。作为参考,虽然我会说BigInteger方法是检查* multiplication *溢出的最可读方法,如果您不愿意使用库。 – 2012-01-29 22:44:29

0

简约路线:

if(a/2+b/2+(a&b&1)>long.MAX_VALUE/2||a/2+b/2<long.MIN_VALUE/2)... 

你只需要希望它不会优化(a+b)/2

+0

我不相信这是正确的。取a = Long.MAX_VALUE和b = 1。然后,如果添加两个值,那么显然会发生溢出,但是如果将它们减半,a/2 = Long.MAX_VALUE/2和b/2 = 0,那么a/2 + b/2 <= Long.MAX_VALUE。 – templatetypedef 2012-01-29 22:38:24

+0

@templatetypedef我修复了这个小技巧(增加了溢出) – 2012-01-29 23:20:04

13

这只是一个问题,如果它们具有相同的符号(和都!0)因为否则你是安全的溢出。如果发生溢出,结果的符号将会翻转。所以:

long r = a + b; 
if ((a < 0 && b < 0 && r >= 0) || 
    (a > 0 && b > 0 && r <= 0)) { 
    // Overflow occurred 
} 
+2

注册了,最简单,最易读和最好的方法。希望该课程不会采用更“优化”的数学方法。 – 2012-01-29 22:38:32

+0

@owlstead,如果编译器足够聪明,它可以使用CPU“携带”标志,所以解决方案就够用了。当天返回的唯一算法是通过进位完成的。 – bestsss 2012-01-29 22:42:54

+1

Upvoted为最适合家庭作业的解决方案。 – 2012-01-29 22:50:32