Java如何处理整数的下溢和溢出,您将如何检查它?

Java如何处理整数的下溢和溢出,您将如何检查它?

Java如何处理整数的下溢和溢出?

在此基础上,您将如何检查/测试是否正在发生这种情况?


慕的地6264312
浏览 1890回答 3
3回答

慕妹3242003

如果溢出,则返回到最小值然后继续下去。如果它在地下流动,它会返回到最大值然后继续下去。您可以按以下方式预先检查:public&nbsp;static&nbsp;boolean&nbsp;willAdditionOverflow(int&nbsp;left,&nbsp;int&nbsp;right)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(right&nbsp;<&nbsp;0&nbsp;&&&nbsp;right&nbsp;!=&nbsp;Integer.MIN_VALUE)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;willSubtractionOverflow(left,&nbsp;-right); &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(~(left&nbsp;^&nbsp;right)&nbsp;&&nbsp;(left&nbsp;^&nbsp;(left&nbsp;+&nbsp;right)))&nbsp;<&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;}}public&nbsp;static&nbsp;boolean&nbsp;willSubtractionOverflow(int&nbsp;left,&nbsp;int&nbsp;right)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(right&nbsp;<&nbsp;0)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;willAdditionOverflow(left,&nbsp;-right); &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;((left&nbsp;^&nbsp;right)&nbsp;&&nbsp;(left&nbsp;^&nbsp;(left&nbsp;-&nbsp;right)))&nbsp;<&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;}}(你可以代替int通过long执行相同的检查long)如果您认为这种情况可能会发生得更多,那么请考虑使用可以存储更大值的数据类型或对象。long或者也许java.math.BigInteger..最后一个没有溢出,实际上,可用的JVM内存是有限的。如果您碰巧已经使用了Java 8,那么您可以使用新的Math#addExact()和Math#subtractExact()方法,这些方法将引发ArithmeticException溢出。public&nbsp;static&nbsp;boolean&nbsp;willAdditionOverflow(int&nbsp;left,&nbsp;int&nbsp;right)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Math.addExact(left,&nbsp;right); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(ArithmeticException&nbsp;e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true; &nbsp;&nbsp;&nbsp;&nbsp;}}public&nbsp;static&nbsp;boolean&nbsp;willSubtractionOverflow(int&nbsp;left,&nbsp;int&nbsp;right)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Math.subtractExact(left,&nbsp;right); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(ArithmeticException&nbsp;e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true; &nbsp;&nbsp;&nbsp;&nbsp;}}源代码可以找到这里和这里分别。当然,您也可以立即使用它们,而不是将它们隐藏在boolean效用法

qq_花开花谢_0

好吧,就原始整数类型而言,Java根本不处理过流/下溢(对于Float和Double行为是不同的,它将刷新到+/无穷大,就像IEEE-754所要求的那样)。当添加两个int‘s时,当发生溢出时,您将不会得到任何指示。检查溢出的一个简单方法是使用下一个更大的类型实际执行操作,并检查结果是否仍在源类型的范围内:public&nbsp;int&nbsp;addWithOverflowCheck(int&nbsp;a,&nbsp;int&nbsp;b)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;the&nbsp;cast&nbsp;of&nbsp;a&nbsp;is&nbsp;required,&nbsp;to&nbsp;make&nbsp;the&nbsp;+&nbsp;work&nbsp;with&nbsp;long&nbsp;precision, &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;if&nbsp;we&nbsp;just&nbsp;added&nbsp;(a&nbsp;+&nbsp;b)&nbsp;the&nbsp;addition&nbsp;would&nbsp;use&nbsp;int&nbsp;precision&nbsp;and &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;the&nbsp;result&nbsp;would&nbsp;be&nbsp;cast&nbsp;to&nbsp;long&nbsp;afterwards! &nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;result&nbsp;=&nbsp;((long)&nbsp;a)&nbsp;+&nbsp;b; &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(result&nbsp;>&nbsp;Integer.MAX_VALUE)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;RuntimeException("Overflow&nbsp;occured"); &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;if&nbsp;(result&nbsp;<&nbsp;Integer.MIN_VALUE)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;RuntimeException("Underflow&nbsp;occured"); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;at&nbsp;this&nbsp;point&nbsp;we&nbsp;can&nbsp;safely&nbsp;cast&nbsp;back&nbsp;to&nbsp;int,&nbsp;we&nbsp;checked&nbsp;before &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;that&nbsp;the&nbsp;value&nbsp;will&nbsp;be&nbsp;withing&nbsp;int's&nbsp;limits &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(int)&nbsp;result;}您将做什么来代替抛出子句,取决于您的应用程序需求(抛出、刷新到min/max或只记录任何内容)。如果希望在长操作中检测到溢出,则使用BigInteger替代原语。编辑(2014-05-21):由于这个问题似乎经常被提及,而且我不得不自己解决同样的问题,所以用CPU计算其V标志的相同方法很容易评估溢出状态。它基本上是一个布尔表达式,它涉及两个操作数的符号以及结果:/** &nbsp;*&nbsp;Add&nbsp;two&nbsp;int's&nbsp;with&nbsp;overflow&nbsp;detection&nbsp;(r&nbsp;=&nbsp;s&nbsp;+&nbsp;d) &nbsp;*/public&nbsp;static&nbsp;int&nbsp;add(final&nbsp;int&nbsp;s,&nbsp;final&nbsp;int&nbsp;d)&nbsp;throws&nbsp;ArithmeticException&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;r&nbsp;=&nbsp;s&nbsp;+&nbsp;d; &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(((s&nbsp;&&nbsp;d&nbsp;&&nbsp;~r)&nbsp;|&nbsp;(~s&nbsp;&&nbsp;~d&nbsp;&&nbsp;r))&nbsp;<&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;ArithmeticException("int&nbsp;overflow&nbsp;add("&nbsp;+&nbsp;s&nbsp;+&nbsp;",&nbsp;"&nbsp;+&nbsp;d&nbsp;+&nbsp;")");&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;r;}在java中,更简单的方法是将表达式(If)应用于整个32位,并使用<0检查结果(这将有效地测试符号位)。这一原则适用于所有整数基元类型,将上述方法中的所有声明更改为LONG使其工作时间很长。对于较小的类型,由于隐式转换为int(有关详细信息,请参见按位操作的JLS),而不是检查<0,检查需要显式地掩蔽符号位(对于短操作数为0x8000,对于字节操作数为0x80,调整转换和参数声明为接近):/** &nbsp;*&nbsp;Subtract&nbsp;two&nbsp;short's&nbsp;with&nbsp;overflow&nbsp;detection&nbsp;(r&nbsp;=&nbsp;d&nbsp;-&nbsp;s) &nbsp;*/public&nbsp;static&nbsp;short&nbsp;sub(final&nbsp;short&nbsp;d,&nbsp;final&nbsp;short&nbsp;s)&nbsp;throws&nbsp;ArithmeticException&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;r&nbsp;=&nbsp;d&nbsp;-&nbsp;s; &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((((~s&nbsp;&&nbsp;d&nbsp;&&nbsp;~r)&nbsp;|&nbsp;(s&nbsp;&&nbsp;~d&nbsp;&&nbsp;r))&nbsp;&&nbsp;0x8000)&nbsp;!=&nbsp;0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;ArithmeticException("short&nbsp;overflow&nbsp;sub("&nbsp;+&nbsp;s&nbsp;+&nbsp;",&nbsp;"&nbsp;+&nbsp;d&nbsp;+&nbsp;")"); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(short)&nbsp;r;}(请注意,上面的示例使用了减法溢出检测)那么,这些布尔表达式是如何/为什么工作的呢?首先,一些逻辑思维表明溢出可以只如果两个参数的符号相同,则会发生。因为,如果一个参数是否定的,另一个是肯定的,则结果(Add)必接近于零,或者在极端情况下,一个参数是零,与另一个参数相同。因为争论本身不能创建溢出条件,它们的和也不能创建溢出。那么,如果这两个论点都有相同的符号,会发生什么呢?让我们看一看两者都是正的情况:添加两个参数来创建一个大于MAX_value类型的和,总是会产生一个负值,所以会发生溢出。如果arg 1+arg 2>max_value。现在,可能产生的最大值是max_value+max_value(两个参数的极端情况都是MAX_value)。对于一个字节(例如),这意味着127+127=254。查看通过添加两个正值可以产生的所有值的位表示,一个发现溢出(128到254)的值都有位7集,而所有没有溢出(0到127)的值都清除了位7(最顶部,符号)。这正是表达式的第一个(右)部分检查的内容:if&nbsp;(((s&nbsp;&&nbsp;d&nbsp;&&nbsp;~r)&nbsp;|&nbsp;(~s&nbsp;&&nbsp;~d&nbsp;&&nbsp;r))&nbsp;<&nbsp;0)(~s&~d&r)成为事实,只有当,两个操作数(s,d)都是正的,结果(R)是负的(表达式在所有32位上都有效,但是我们感兴趣的唯一位是最上面的(符号)位,它是由<0检查的)。如果这两个参数都是负数,则它们的和永远不会比任何一个参数之和更接近于零。必接近负无穷远。我们能产生的最极端的值是min_value+min_value,它(同样在字节示例中)显示,对于任何范围内的值(-1到-128),符号位都被设置,而任何可能的溢出值(-129到-256)都清除了符号位。因此,结果的符号再次显示溢出情况。这就是左半部分(s&d&r)检查的情况,即两个参数(s,d)都是负数,结果是肯定的。逻辑在很大程度上等同于正数;所有因添加两个负值而产生的位模式都将清除符号位。当且仅当发生了地下水流。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java