101

我有以下if情况。

if (i == -i && i != 0)

在 Java 中这个条件i会返回什么值?true

我无法想到在 Java中i考虑二进制补码表示法的任何价值。

我也很想得到这个条件有什么答案的代数证明(在Java的上下文中)?

4

6 回答 6

126

它适用的唯一int值是 Integer.MIN_VALUE.

这是因为使用二进制补码方式对整数求反。

使用

System.out.println(Integer.toBinaryString(Integer.MIN_VALUE));

你看那Integer.MIN_VALUE

10000000000000000000000000000000

取负值是通过首先交换0and来完成的1,这给出了

01111111111111111111111111111111

并通过添加1,这给出

10000000000000000000000000000000

正如您在我提供的链接中看到的那样,维基百科提到了负数最多的问题,并指定它是唯一的例外:

二进制补码中最大的负数有时被称为“怪数”,因为它是唯一的例外。

当然,Long.Min_Value如果将其存储在long变量中,也会出现同样的现象。

请注意,这仅是由于对 Java 中整数的二进制存储所做的选择。例如,另一个(坏)解决方案可能是通过简单地更改最高有效位并让其他位保持不变来否定,这可以避免使用 MIN_VALUE 的这个问题,但会产生 2 个不同的0值和复杂的二进制算术(你怎么会有例如增加?)。

于 2013-07-22T06:26:52.023 回答
25

您正在寻找的价值是Integer.MIN_VALUE.


我也很想得到这个条件有什么答案的代数证明(在java的上下文中)?

这对于 Stack Exchange 来说是题外话。但是您可以从 Java 整数的定义开始(JLS 4.2

“整数类型有 byte、short、int 和 long,其值为 8 位、16 位、32 位和 64 位有符号二进制补码整数……”

“整数类型的值是以下范围内的整数......对于int,从-2147483648到2147483647,包括在内”

以及 Java 一元“-”运算符(JLS 15.15.4)的定义:

“对于整数值,取反与从零减法相同。Java 编程语言对整数使用二进制补码表示,二进制补码值的范围不是对称的,因此对最大负 int 或 long 取反会导致相同的最大负数。在这种情况下会发生溢出,但不会抛出异常。对于所有整数值 x,-x 等于 (~x)+1。

于 2013-07-22T06:25:51.757 回答
18

除了到目前为止给出的答案...

一共有四个值

int i = Integer.MIN_VALUE;
long i = Long.MIN_VALUE;
Integer i = Integer.valueOf(Integer.MIN_VALUE);
Long i = Long.valueOf(Long.MIN_VALUE);

被包装的值被解包,所以它们也适用于这个表达式。

注意:Math.abs 文件。

公共静态 int abs(int a)

返回 int 值的绝对值。如果参数不是负数,则返回参数。如果参数是否定的,则返回参数的否定。

请注意,如果参数等于 Integer.MIN_VALUE 的值,即最负的可表示 int 值,则结果是相同的值,即为负。

public static long abs(long a)

返回长值的绝对值。如果参数不是负数,则返回参数。如果参数是否定的,则返回参数的否定。

请注意,如果参数等于 Long.MIN_VALUE 的值(可表示的最负的 long 值),则结果是相同的值,即为负。

令人惊讶的是 Math.abs 可能会返回一个负数。发生这种情况的原因可能是 a) 在这些情况下 -MIN_VALUE 没有正值 b) 执行-计算会导致溢出。

同样有趣的是为什么 Byte.MIN_VALUE、Short.MIN_VALUE 不这样做。这是因为将-类型更改int为这些,因此不会溢出。

Character.MIN_VALUE 没有问题,因为它是 0。

Float.MIN_VALUE 和 Double.MIN_VALUE 有不同的含义。这些是大于零的最小可表示值。因此,它们具有不是它们自身的有效负值。

于 2013-07-22T07:03:03.373 回答
14

就像其他人提到的那样,这仅由Integer.MIN_VALUE. 至于证明,让我提供一个比二进制更容易理解的解释(尽管它仍然植根于此)。

注意Integer.MIN_VALUE等于-2^31or-2147483648Integer.MAX_VALUE等于2^31-1or 2147483647-Integer.MIN_VALUEis 2^31,现在对于 Integer 来说太大了(因为它已经过去了MAX_VALUE),从而导致 Integer 溢出,Integer.MIN_VALUE再次发生。它是唯一一个这样做的整数,因为MIN_VALUE它是唯一一个除了 0 之外没有负等价的数字。

于 2013-07-22T06:40:43.967 回答
6

暂定代数证明,使用modulo 2^32算术:

i == -i可以改写为(两边2 * i == 0相加),或.ii << 1 == 0

这个方程有两个形式的解i == 0 >> 1,即0b10000000000000000000000000000000b通过左移01左移获得。

解决方案i == 0被排除,仍然存在解决方案i == 100000000000000000000000000000000b

于 2013-07-24T08:36:10.167 回答
0

也许它不太有教育意义,但不要认为你可以运行这段代码:

    for (int i = Integer.MIN_VALUE; i <= Integer.MAX_VALUE; i++)
    {
        if (i == -i && i != 0)
        {
            System.out.println(i);
        }
    }

看到它打印

-2147483648
-2147483648

无限地 :)

于 2013-07-26T12:54:13.763 回答