我正在从Cay S. Horstmann的"真正不耐烦的Java SE 8"一书中进行练习。 基于Number类的改进的一项练习要求:
Write a program that adds, subtracts, divides, and compares numbers
between 0 and 232 - 1, using int values and unsigned
operations. Show why divideUnsigned and remainderUnsigned are
necessary.
问题是,如果您添加2个无符号整数,则总和可能会超出整数限制。 我看不出有一种方法可以避免这种情况,而无需花费很长的时间来存储总和并检查它是否大于Integer.MAX_VALUE。 是否可以仅使用int做到这一点?
用于整数值的二进制补码具有整洁的属性,即将值解释为带符号还是无符号,与加减运算无关。
因此,即使在CPU级别上,也没有用于添加/减去带符号或无符号数字的明确指令。这一切都与解释有关。
因此,当您使用带符号的int类型添加或减去两个无符号的数字时,结果可能会在带符号的int范围内溢出。但是,当使用Integer.toUnsignedString打印负数时,结果将是正确的无符号值,前提是该操作甚至没有在无符号整数值范围内溢出。
这就是为什么类java.lang.Integer仅在必要时提供特殊的无符号操作的原因,即,用于比较两个无符号值,除法和余数以及从和向String(以及向long的转换),而从到int已经足以用于另一个方向)。
感谢您的答复。我不确定问题是否仅与打印有关。如果返回了溢出值,并且将其用于其他操作,则它将是错误的。在这种情况下,Java 8中引入的"精确"操作intValueExact会引发异常。
由于练习要求使用int进行计算,因此无法解决。当然,您可以以安全的方式定义计算的API,即可以使用Integer.toUnsignedLong以不会被误解的形式返回值(使用int计算出的值)。当然,如果使用toUnsignedString"计算" !="返回类型"将结果作为String返回,则结果相同。
我希望有更多的东西。如果您阅读该问题,它将说"使用int值和无符号操作"。如果创建一个使用+运算符添加2个整数的方法似乎很简单。除非缺少某些内容,否则练习不会增加任何价值。
也许您应该专注于练习的最后一句话:"说明为什么需要divideUnsigned和remainderUnsigned"。这意味着您应该深入研究2的补数,以了解为什么它适用于+,-和*,但不适用于和%,因此您将了解为Java 8添加了这两种支持方法,但没有addUnsigned等。
为了获取无符号的int,您需要使用Integer.parseUnsignedInt()函数或进行手动计算。请记住,Java实际上并没有无符号整数,Java8只是提供了将int视为无符号整数的功能,以便允许更大范围的正数值。
根据Java 8 Doc for Integer类,
An unsigned integer maps the values usually associated with negative
numbers to positive numbers larger than MAX_VALUE
因此,无符号整数和有符号整数之间的转换是,如果数字大于或等于零且小于或等于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值视为无符号的。