【问题标题】:Java 8 Unsigned Integer Addition and Potential OverflowJava 8 无符号整数加法和潜在溢出
【发布时间】:2015-01-13 16:28:34
【问题描述】:

我正在练习 Cay S. Horstmann 所著的“真正不耐烦的 Java SE 8”一书。一项基于Number 课程改进的练习要求:

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

问题是,如果添加 2 个无符号整数,总和可能会超出整数限制。如果不使用 long 来存储总和并检查它是否大于Integer.MAX_VALUE,我看不到防止这种情况发生的方法。是否可以仅使用整数来做到这一点?

【问题讨论】:

    标签: numbers java-8 addition integer-overflow unsigned-integer


    【解决方案1】:

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

    因此,即使在 CPU 级别,也没有用于加/减有符号或无符号数字的不同指令。一切都是为了解释。

    因此,当您使用有符号int 类型对两个无符号数进行加减运算时,结果可能会在有符号int 范围内溢出。但是当使用Integer.toUnsignedString 打印现在的负数时,结果将是正确的无符号值,假设该操作甚至没有在无符号整数值范围内溢出。

    这就是为什么 java.lang.Integer 类仅在必要时提供特殊的无符号运算,即比较两个无符号值、除法和余数以及从和到 String 的转换(以及到 long,而类型转换从longint 对于另一个方向已经足够了)。

    【讨论】:

    • 感谢您的回复。我不确定问题是否仅与打印有关。如果溢出值被返回并用于其他操作,那将是不正确的。 Java 8 中引入的“精确”操作,intValueExact 在这种情况下会抛出异常。
    • 由于该练习要求使用int 进行计算,因此无法绕过它。当然,您可以以安全的方式定义计算的 API,即您可以使用 Integer.toUnsignedLong 以不会被误解的形式返回值(您使用 int 计算的值)。当然,如果您使用toUnsignedString“计算”!=“返回类型”将结果返回为String,情况也是如此。
    • 我希望它不止于此。如果您阅读该问题,它会显示“使用int 值和无符号操作”。如果创建一个使用 + 运算符添加 2 个整数的方法似乎非常简单。除非我们遗漏了什么,否则练习不会增加任何价值。
    • 也许你应该关注练习的最后一句话:“说明为什么divideUnsignedremainderUnsigned 是必要的”。这意味着您应该深入挖掘 2 的补码以了解为什么它适用于 +-*,但不适用于 /%,因此您将了解为 Java 8 添加这两种支持方法但没有 addUnsigned 等的 API 设计决策。
    【解决方案2】:

    为了获得无符号整数,您需要使用Integer.parseUnsignedInt() 函数或进行手动计算。请记住,Java 实际上没有无符号整数,Java8 只是提供了将 int 视为无符号的能力,以便允许更大范围的正数。

    根据Java 8 Doc for the Integer class

    无符号整数映射通常与负相关的值 数转换为大于 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 值视为无符号。

    【讨论】:

      猜你喜欢
      • 2019-02-27
      • 2012-02-29
      • 2013-04-10
      • 1970-01-01
      • 1970-01-01
      • 2014-12-09
      • 2021-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多