2015-01-13 35 views
1

我正在为Cay S. Horstmann编写的书籍“真正不耐烦的Java SE 8”进行练习。之一的基于Number类的改进的练习问:Java 8无符号整数加法和潜在溢出

编写一个程序,加,减,除,以及0和2 之间进行比较的数字 - 1,使用int值和无符号 操作。说明为什么divideUnsignedremainderUnsigned是 必要的。

问题是,如果您添加2个无符号整数,总和可能溢出整数限制。我没有看到一种方法来避免这种情况,而不用长时间存储总和并检查它是否大于Integer.MAX_VALUE。是否有可能只使用ints来做到这一点?

回答

3

用于整数值的Two's complement具有整洁的属性,对于添加和减去它是无关紧要的,无论您将值解释为有符号还是无符号。

因此,即使在CPU级别,也没有用于添加/减少带符号或无符号数字的独特指令。这完全是关于解释。

因此,当使用带符号的int类型添加或减去两个无符号数字时,结果可能会在签名的int范围内溢出。但是,使用Integer.toUnsignedString打印当前为负的数字时,结果将是正确的无符号值,假定该操作甚至在无符号整数值范围内甚至没有溢出。

这就是为什么类java.lang.Integer只在必要时提供了特殊的无符号的操作,即用于比较两个无符号值,除法和余数,并从和String(和long转换,而A型投从longint是已经足够用于其他方向)。

+0

感谢您的回复。我不确定问题是否仅限于打印。如果溢出值被返回并在其他操作中使用,则会出错。在Java 8中引入的“确切”操作[intValueExact](http://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html#intValueExact--)将异常这种情况。 –

+1

由于练习要求使用'int'进行计算,因此无法绕过它。当然,你可以用安全的方式定义计算的API,也就是说你可以使用['Integer.toUnsignedLong'](http://docs.oracle.com/javase/8/docs/api/java/lang/ Integer.html#toUnsignedLong-int-)以不能被误解的形式返回值(使用int计算)。当然,如果你使用['toUnsignedString']返回结果作为'String',那么同样的结果会持续(http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#toUnsignedString -int-)“计算”'!='“返回类型” – Holger

+0

我希望除此之外还有更多。如果你读到这个问题,它说“使用int值和未签名的操作”。如果看起来不是微不足道的,可以创建一个使用'+'运算符添加2个整数的方法。除非我们错过了一些东西,否则练习不会增加任何价值。 –

1

为了获得一个无符号整数,你需要使用Integer.parseUnsignedInt()函数或做一个手动计算。请记住,Java实际上并不具有无符号整数,Java8只是提供了将int作为无符号对待的能力,以便允许更大范围的正数值。

按照Java 8 Doc for the Integer class

的无符号整数映射通常与负 编号,以正数比MAX_VALUE较大相关联的值

所以一个无符号的int和一个签署一个之间的转换如果数字大于或等于零且小于或等于Integer.MAX_VALUE,则它保持不变。如果它大于Integer.MAX_VALUE但仍在无符号范围内,那么要将其存储在int中,则需要将2^31添加到它,由于添加溢出被定义为的方式将其转换为正确的值一个手术。除了像int这样的二进制基元外,溢出和下溢只会导致计数器复位并继续计数。

int min = Integer.MIN_VALUE;   // -2147483648 
int max = Integer.MAX_VALUE;   // 2147483647 
int overByOne = Integer.MAX_VALUE + 1; // -2147483648 : same as Integer.MIN_VALUE 
int underByOne = Integer.MIN_VALUE - 1; // 2147483647 : same as Integer.MAX_VALUE 

他们行使只是要求你看看Integer类和测试出无符号运算的各种(新中Java8)方法。 Java没有无符号整数原语,但为了Integer类中的某些新方法的目的,可以将int值视为无符号。