i的值(i == -i && i!= 0)在Java中返回true


101

我有以下if情况。

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

在Java中,此条件i将返回什么值true

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

我也想对这种情况的答案有代数证明(在Java中)?


2
怎么样(i!= null)
zxc

4
请注意,这-0.0也是== 0
Peter Lawrey

2
写为if(i && i == -i)
Grijesh Chauhan

10
@GrijeshChauhan在Java中?你确定吗 ?
DenysSéguret13年

3
在过去四年中,我多次在访谈中询问@harold,即使有提示,也很少有人真正得到它。
彼得·劳瑞

Answers:


126

int它起作用的唯一值是 Integer.MIN_VALUE

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

使用

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

你看那Integer.MIN_VALUE

10000000000000000000000000000000

取负值的方法是先交换01,然后得出

01111111111111111111111111111111

并通过添加1

10000000000000000000000000000000

正如您在我给的链接中看到的那样,Wikipedia提到了负数最多的问题,并指出这是唯一的例外:

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

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

请注意,这仅是由于在Java中对ints的二进制存储所做的选择。另一个(错误的)解决方案例如可以通过简单地更改最高有效位并使其他位保持不变来求反,这样可以避免MIN_VALUE出现此问题,但是会产生2个不同的0值和复杂的二进制算术(您将如何例如增加?)。


2
值得注意的是,早期的二进制计算机确实对上一段中描述的整数使用了符号和幅度实现。IEE754浮点数也是如此。 en.wikipedia.org/wiki/...
丹摆弄心火

1
回复:“这仅与对整数的二进制存储所做的选择有关”:以及如何处理溢出的选择。Java使用的规则与(例如)C使用的规则或(例如)标准ML使用的规则不同,即使所有这些规则都在各种各样的系统上运行。
ruakh

2
值得一提的是,它已在Java Spec上进行了记录:“ Java编程语言对整数使用二进制补码表示形式,并且二进制补码值的范围不是对称的,因此,对负整数int或long求反会导致相同的最大值负数。”
切斯特布雷

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编程语言对整数使用二进制补码表示形式,并且二进制补码值的范围不是对称的,因此对最大负整数或长整数取负会导致整数取反。相同的最大负数。在这种情况下会发生溢出,但不会引发异常。对于所有整数x,-x等于(〜x)+1。”


3
长度也MIN_VALUE
Juvanis

1
这是100000 ..,如果我得到2的称赞,它又是011111 ... + 1 = 100000 ...,但是您知道它的重要性,还是我们可以采用任何逻辑?
2013年

1
如我所读..java的int算术是算术mod 2power32,所以我在想我们是否可以仅在1或2行中证明这个值。
2013年

2
@Sunny很难证明。在整数范围内,所有正数都有一个负数(so i != -i)。剩下两个数字:0Integer.MIN_VALUE。因为i != 0在您的情况下,仅MIN_VALUE剩下。
文森特·范·德·韦勒

1
@Heuster-推理起作用了……但是它取决于一个或两个需要证明的假设。
斯蒂芬·C

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值),则结果是相同的值,该值为负。

公共静态长ABS(长A)

返回一个long值的绝对值。如果参数不是负数,则返回参数。如果参数为负,则返回参数取反。

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

令人惊讶的是Math.abs可能返回负数。这可能是由于a)在这些情况下-MIN_VALUE没有正值b)执行-计算导致溢出。

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

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

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


1
我想知道Byte.MIN_VALUE和其他可能性,您的回答提供了这一点。谢谢
Cengiz Can

14

就像其他人提到的那样,这只能通过实现Integer.MIN_VALUE。至于证明,除了二进制以外,让我提供一个更容易理解的解释(尽管它仍然植根于该解释中)。

需要注意的是Integer.MIN_VALUE等于-2^31-2147483648Integer.MAX_VALUE等于2^31-12147483647-Integer.MIN_VALUE2^31,现在对于Integer而言太大(因为它过去了MAX_VALUE),从而导致Integer溢出,Integer.MIN_VALUE再次出现。这是唯一执行此操作的Integer,因为MIN_VALUE它是唯一一个除了0以外都没有负等价的数字。


2
@dystroy实际上我正在寻找一些解释,根据Mark的说明,在int范围内没有+2147483648这样的数字,因此首先怀疑的应该是该数字,而不是0。范围是-2 ^ n至2 ^ n-1。因此,没有与-2 ^ n对应的正数。这只是另一个可能的int值。
2013年

1
我没有用二进制解释,因为它已经被其他人所覆盖(基本上int是32位值,这就是为什么有这些限制的原因)。同样,负数的负数也是正数,因此这些条款仍然适用。
Mark M

1
在Java中,奇怪的是,该数字2147483648可能仅在以下情况下出现在源代码中:作为一元减运算符(JLS 3.10.1)的操作数。
Eric Jablow

6

初步的代数证明,使用modulo 2^32算术:

i == -i可以改写为2 * i == 0i两面都加),或i << 1 == 0

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

解决方案i == 0被排除在外,剩下的就是解决方案i == 100000000000000000000000000000000b


0

也许它不是太有教育意义,但与其认为可以运行以下代码,不如说:

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

看到它打印

-2147483648
-2147483648

无限地 :)


您如何看待它是无限的?
JBelter 2013年

因为我<= Integer.MAX_VALUE永远不会为假
库巴(Kuba)

1
<
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.