Giá trị của i for (i == -i && i! = 0) trả về true trong Java


101

Tôi có một ifđiều kiện sau đây .

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

Giá trị nào của isẽ trả về truecho điều kiện này trong Java?

Tôi không thể nghĩ ra bất kỳ giá trị nào như vậy khi ixem xét ký hiệu bổ sung của hai trong Java.

Tôi cũng muốn có bằng chứng đại số cho bất kỳ câu trả lời nào mà điều kiện này có (trong ngữ cảnh với Java)?


2
làm thế nào về if (i = null!)
zxc

4
Lưu ý rằng -0.0cũng là== 0
Peter Lawrey

2
viết nó nhưif(i && i == -i)
Grijesh Chauhan

10
@GrijeshChauhan Trong Java? Bạn có chắc không ?
Denys Séguret

3
@harold Tôi đã hỏi trong các cuộc phỏng vấn nhiều lần trong bốn năm qua và rất ít người thực sự hiểu nó ngay cả khi có gợi ý.
Peter Lawrey

Câu trả lời:


126

intGiá trị duy nhất mà nó hoạt động là Integer.MIN_VALUE.

Đó là bởi vì các số nguyên bị phủ định bằng cách sử dụng cách bổ sung của cả hai .

Sử dụng

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

bạn thấy đó Integer.MIN_VALUE

10000000000000000000000000000000

Lấy giá trị âm được thực hiện bằng trao đổi đầu tiên 01, mang đến cho

01111111111111111111111111111111

và bằng cách thêm 1, điều này mang lại

10000000000000000000000000000000

Như bạn có thể thấy trong liên kết tôi đã cung cấp, Wikipedia đề cập đến vấn đề với nhiều số âm nhất và chỉ rõ đó là ngoại lệ duy nhất:

Số âm nhất trong phần bù của hai đôi khi được gọi là "số kỳ lạ", vì nó là ngoại lệ duy nhất.

Tất nhiên bạn có hiện tượng tương tự Long.Min_Valuenếu bạn lưu trữ nó trong một longbiến.

Lưu ý rằng điều này chỉ là do các lựa chọn đã được thực hiện liên quan đến việc lưu trữ nhị phân của int trong Java . Một giải pháp khác (không tốt) chẳng hạn có thể phủ định bằng cách đơn giản thay đổi bit quan trọng nhất và để các bit khác không thay đổi, điều này sẽ tránh được vấn đề này với MIN_VALUE nhưng sẽ tạo ra 2 0giá trị khác nhau và số học nhị phân phức tạp (bạn sẽ có tăng dần chẳng hạn?).


2
Cần lưu ý rằng các máy tính nhị phân ban đầu đã sử dụng triển khai dấu và độ lớn cho các số nguyên được mô tả trong đoạn cuối của bạn; số dấu phẩy động IEE754 cũng vậy. en.wikipedia.org/wiki/...
Dan là Fiddling Bằng ánh lửa

1
Re: "điều này chỉ liên quan đến các lựa chọn đã được thực hiện liên quan đến lưu trữ nhị phân của int": Và các lựa chọn về cách xử lý tràn. Quy tắc mà Java sử dụng không giống với quy tắc được sử dụng bởi (giả sử) C hoặc quy tắc được sử dụng bởi (giả sử) ML tiêu chuẩn, mặc dù tất cả những quy tắc này đều chạy trên nhiều loại hệ thống.
ruakh

2
Đáng nói là nó được ghi lại trên Java Spec : "Ngôn ngữ lập trình Java sử dụng biểu diễn phần bù của hai cho các số nguyên và phạm vi của các giá trị phần bù của hai không đối xứng, vì vậy việc phủ định số nguyên âm tối đa hoặc giá trị dài sẽ dẫn đến giá trị tối đa đó số âm."
chesterbr

25

Giá trị bạn đang tìm kiếm là Integer.MIN_VALUE.


Tôi cũng muốn có bằng chứng đại số cho bất kỳ câu trả lời nào mà điều kiện này có (trong ngữ cảnh với java)?

Đó là chủ đề đối với Stack Exchange. Nhưng bạn có thể làm điều đó bắt đầu từ định nghĩa về số nguyên Java ( JLS 4.2 )

"Các loại tích phân là byte, short, int và long, có giá trị là 8-bit, 16-bit, 32-bit và 64-bit là số nguyên bổ sung của hai dấu ..."

"Giá trị của các loại tích phân là số nguyên trong các phạm vi sau ... Đối với int, từ -2147483648 đến 2147483647, bao gồm"

và định nghĩa của toán tử Java một ngôi '-' ( JLS 15.15.4 ):

"Đối với các giá trị số nguyên, phủ định cũng giống như phép trừ từ 0. Ngôn ngữ lập trình Java sử dụng biểu diễn phần bù của hai cho các số nguyên và phạm vi của các giá trị phần bù của hai không đối xứng, vì vậy, việc phủ định số nguyên âm tối đa hoặc giá trị dài dẫn đến cùng một số âm tối đa. Tràn xảy ra trong trường hợp này, nhưng không có ngoại lệ nào được đưa ra. Đối với tất cả các giá trị nguyên x, -x bằng (~ x) +1. "


3
Dài.MIN_VALUE cũng vậy.
Juvanis

1
là 100000 .., và nếu tôi nhận được lời khen của 2 người về nó, thì nó lại là 011111 ... + 1 = 100000 ... nhưng bạn có biết nó nằm trên đầu bạn không hay chúng ta có thể áp dụng bất kỳ logic nào?
Sunny

1
Như tôi đã đọc.. int arithmetic của java là mod số học 2power32, vì vậy tôi đã suy nghĩ nếu chúng tôi có thể chứng minh giá trị này chỉ trong 1 hoặc 2 dòng..nếu nó là một bằng chứng lớn..thì không có vấn đề gì.
Sunny

2
@Sunny không thể quá khó để chứng minh. Trong phạm vi số nguyên, tất cả các số dương đều có phần đối âm (như vậy i != -i). Điều đó để lại hai số trong phạm vi: 0Integer.MIN_VALUE. Bởi vì i != 0trong if của bạn, chỉ MIN_VALUEcòn lại.
Vincent van der Weele

1
@Heuster - lý luận đó hoạt động ... nhưng nó phụ thuộc vào một hoặc hai giả định yêu cầu bằng chứng.
Stephen C

18

Ngoài các câu trả lời được đưa ra cho đến nay ...

Tổng cộng có bốn giá trị

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

Các giá trị được bao bọc được mở ra nên chúng cũng đúng với biểu thức này.

Lưu ý: Tài liệu Math.abs.

public static int abs (int a)

Trả về giá trị tuyệt đối của một giá trị int. Nếu đối số không phủ định, đối số được trả về. Nếu đối số là phủ định, thì phủ định của đối số được trả về.

Lưu ý rằng nếu đối số bằng với giá trị của Integer.MIN_VALUE, giá trị int có thể biểu diễn âm nhất, thì kết quả là cùng giá trị đó, giá trị này là số âm.

công tĩnh dài abs (dài a)

Trả về giá trị tuyệt đối của một giá trị dài. Nếu đối số không phủ định, đối số được trả về. Nếu đối số là phủ định, thì phủ định của đối số được trả về.

Lưu ý rằng nếu đối số bằng giá trị của Long.MIN_VALUE, giá trị dài có thể biểu diễn âm nhất, thì kết quả là cùng giá trị đó, là giá trị âm.

Điều đáng ngạc nhiên là Math.abs có thể trả về một số âm. Điều này xảy ra bởi vì a) không có giá trị dương nào cho -MIN_VALUE trong những trường hợp này b) thực hiện -phép tính dẫn đến tràn.

Điều quan tâm là tại sao Byte.MIN_VALUE, Short.MIN_VALUE không làm điều này. Điều này là do các -thay đổi kiểu intcho các và do đó không có tràn.

Character.MIN_VALUE không gặp sự cố vì nó bằng 0.

Float.MIN_VALUE và Double.MIN_VALUE có một ý nghĩa khác. Đây là giá trị nhỏ nhất có thể biểu diễn lớn hơn 0. Do đó chúng có các giá trị âm hợp lệ không phải là chính chúng.


1
Tôi đã tự hỏi về Byte.MIN_VALUE và các khả năng khác, câu trả lời của bạn cung cấp điều đó. Cảm ơn
Cengiz Can

14

Giống như những người khác đã đề cập, điều này chỉ được đáp ứng bởi Integer.MIN_VALUE. Đối với bằng chứng, hãy để tôi đưa ra một giải thích dễ hiểu hơn ngoài nhị phân (mặc dù nó vẫn bắt nguồn từ đó).

Lưu ý rằng Integer.MIN_VALUEbằng -2^31hoặc -2147483648Integer.MAX_VALUEbằng 2^31-1hoặc 2147483647. -Integer.MIN_VALUE2^31, hiện quá lớn đối với một Số nguyên (vì nó đã qua MAX_VALUE), do đó gây ra tràn Số nguyên, làm cho nó Integer.MIN_VALUEmột lần nữa. Đó là Số nguyên duy nhất thực hiện điều này vì MIN_VALUElà số duy nhất không có số tương đương âm ngoài 0.


2
@dystroy thực sự tôi đang tìm kiếm một số lời giải thích, theo Mark, không có số nào như +2147483648 trong dải int, vì vậy nghi ngờ đầu tiên nên là số này khác 0. Phạm vi là -2 ^ n đến 2 ^ n-1. Vì vậy, không có số đối dương với -2 ^ n. Đây chỉ là một giá trị int có thể có khác.
Nắng

1
Tôi đã không giải thích bằng hệ nhị phân vì nó đã bị người khác che mất rồi (về cơ bản int là giá trị 32 bit, đó là lý do tại sao nó có những giới hạn đó). Ngoài ra, phủ định của phủ định là dương, vì vậy các điều khoản vẫn có thể áp dụng.
Mark M

1
Thật kỳ lạ trong Java, số 2147483648có thể xuất hiện trong mã nguồn chỉ trong một trường hợp: như là toán hạng của toán tử trừ một bậc (JLS 3.10.1).
Eric Jablow

6

Chứng minh đại số dự kiến, sử dụng modulo 2^32số học:

i == -icó thể được viết lại thành 2 * i == 0(thêm ivào cả hai bên), hoặc i << 1 == 0.

Phương trình này có hai nghiệm ở dạng i == 0 >> 1, cụ thể là 0b10000000000000000000000000000000bnhận được bằng cách chuyển sang một trong hai 0hoặc 1bên trái.

Giải pháp i == 0được loại trừ, vẫn còn giải pháp i == 100000000000000000000000000000000b.


0

Có thể nó không quá giáo dục, nhưng thay vì nghĩ rằng bạn có thể chạy mã này:

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

để thấy rằng nó in

-2147483648
-2147483648

vô hạn :)


Làm thế nào để bạn hình dung nó là vô hạn?
JBelter

Bởi vì tôi <= Integer.MAX_VALUE sẽ không bao giờ sai
Kuba

1
Ahh rất đúng, suy nghĩ tôi thấy đúng<
JBelter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.