ค่าของ i สำหรับ (i == -i && i! = 0) เพื่อคืนค่าจริงใน Java


101

ฉันมีifเงื่อนไขดังต่อไปนี้

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

ค่าใดที่iจะคืนค่าtrueสำหรับเงื่อนไขนี้ใน Java

ฉันไม่สามารถนึกถึงคุณค่าของการiพิจารณาสัญกรณ์เสริมสองตัวใน Java ได้

ฉันชอบที่จะมีการพิสูจน์พีชคณิตของคำตอบใด ๆ ที่เงื่อนไขนี้มี (ในบริบทกับ Java)?


2
แล้วถ้า (i! = null)
zxc

4
ทราบว่า-0.0เป็นยัง== 0
ปีเตอร์ Lawrey

2
เขียนเป็นif(i && i == -i)
Grijesh Chauhan

10
@GrijeshChauhan ใน Java? คุณแน่ใจไหม ?
Denys Séguret

3
@harold ฉันเคยถามในการสัมภาษณ์หลายครั้งในช่วงสี่ปีที่ผ่านมาและมีเพียงไม่กี่คนที่ได้รับคำแนะนำอย่างแท้จริง
Peter Lawrey

คำตอบ:


126

เพียงค่าที่ใช้การทำงานคือint Integer.MIN_VALUE

มันเป็นเพราะจำนวนเต็มจะถูกทำให้ไร้ผลโดยใช้วิธีเติมเต็มสอง

การใช้

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

คุณเห็นว่าInteger.MIN_VALUEเป็น

10000000000000000000000000000000

การรับค่าลบทำได้โดยการสลับครั้งแรก0และ1ซึ่งให้

01111111111111111111111111111111

และโดยการเพิ่ม1ซึ่งให้

10000000000000000000000000000000

ดังที่คุณเห็นในลิงค์ที่ฉันให้ Wikipedia กล่าวถึงปัญหาเกี่ยวกับตัวเลขที่เป็นลบมากที่สุดและระบุว่าเป็นข้อยกเว้นเพียงประการเดียว:

จำนวนลบมากที่สุดในส่วนเติมเต็มของสองบางครั้งเรียกว่า "จำนวนประหลาด" เพราะเป็นเพียงข้อยกเว้นเท่านั้น

แน่นอนคุณมีปรากฏการณ์เดียวกันLong.Min_Valueถ้าคุณเก็บไว้ในlongตัวแปร

โปรดทราบว่านี้เป็นเพราะเพียงทางเลือกที่ทำเกี่ยวกับการจัดเก็บข้อมูลแบบไบนารีของ ints ในชวา อีกวิธีหนึ่ง (ไม่ดี) สามารถลบล้างได้โดยเพียงแค่เปลี่ยนบิตที่สำคัญที่สุดและปล่อยให้บิตอื่นไม่เปลี่ยนแปลงสิ่งนี้จะหลีกเลี่ยงปัญหานี้กับ MIN_VALUE ได้ แต่จะสร้าง0ค่าที่แตกต่างกัน 2 ค่าและเลขคณิตไบนารีที่ซับซ้อน (คุณจะมีได้อย่างไร เพิ่มขึ้นเช่น?)


2
เป็นที่น่าสังเกตว่าคอมพิวเตอร์ไบนารีในยุคแรกใช้เครื่องหมายและขนาดการใช้งานสำหรับจำนวนเต็มที่อธิบายไว้ในย่อหน้าสุดท้ายของคุณ เช่นเดียวกับตัวเลขจุดลอยตัว IEE754 en.wikipedia.org/wiki/…
Dan Is Fiddling By Firelight

1
Re: "สิ่งนี้เกี่ยวข้องกับตัวเลือกที่สร้างขึ้นเกี่ยวกับการจัดเก็บไบนารีของ ints เท่านั้น": และทางเลือกในการจัดการกับการล้น กฎที่ Java ใช้ไม่เหมือนกับกฎที่ใช้โดย (พูด) C หรือกฎที่ใช้โดย (พูด) Standard ML แม้ว่าทั้งหมดนี้จะทำงานบนระบบที่หลากหลาย
ruakh

2
ควรค่าแก่การกล่าวถึงว่ามีการบันทึกไว้ใน Java Spec : "ภาษาการเขียนโปรแกรม Java ใช้การแทนค่าสองส่วนเสริมสำหรับจำนวนเต็มและช่วงของค่าเสริมของทั้งสองไม่สมมาตรดังนั้นการปฏิเสธของค่า int เชิงลบสูงสุดหรือระยะยาวจะให้ผลลัพธ์สูงสุดเท่ากัน จำนวนลบ "
chesterbr

25

Integer.MIN_VALUEค่าที่คุณกำลังมองหา


ฉันชอบที่จะมีการพิสูจน์พีชคณิตของคำตอบใด ๆ ที่เงื่อนไขนี้มี (ในบริบทกับ java)?

นั่นไม่ใช่หัวข้อสำหรับ Stack Exchange แต่คุณสามารถทำได้โดยเริ่มจากนิยามของจำนวนเต็ม Java ( JLS 4.2 )

"ประเภทอินทิกรัล ได้แก่ ไบต์สั้น int และยาวซึ่งมีค่าคือ 8 บิต 16 บิต 32 บิตและ 64 บิตที่ลงนามสองจำนวนเต็มเสริม ... "

และ

"ค่าของชนิดปริพันธ์คือจำนวนเต็มในช่วงต่อไปนี้ ... สำหรับ int ตั้งแต่ -2147483648 ถึง 2147483647 รวม"

และนิยามของตัวดำเนินการ Java unary '-' ( JLS 15.15.4 ):

"สำหรับค่าจำนวนเต็มการลบจะเหมือนกับการลบออกจากศูนย์ภาษาการเขียนโปรแกรม Java ใช้การแทนค่าสองส่วนเสริมสำหรับจำนวนเต็มและช่วงของค่าเสริมของทั้งสองไม่สมมาตรดังนั้นการปฏิเสธของ int เชิงลบสูงสุดหรือระยะยาวจะส่งผลให้ จำนวนลบสูงสุดเท่ากันการล้นเกิดขึ้นในกรณีนี้ แต่จะไม่มีข้อยกเว้นสำหรับค่าจำนวนเต็มทั้งหมด x, -x เท่ากับ (~ x) +1 "


3
Long.MIN_VALUEเช่นกัน
Juvanis

1
ซึ่งเท่ากับ 100000 .. และถ้าฉันได้รับคำชมเชยจาก 2 มันก็เป็นอีกครั้ง 011111 ... + 1 = 100000 ... แต่คุณรู้หรือไม่ว่ามันอยู่เหนือหัวของคุณหรือเราสามารถใช้ตรรกะใดก็ได้?
ซันนี่

1
จากที่ฉันได้อ่าน.. int arithmetic ของ java คือเลขคณิต mod 2power32 ดังนั้นฉันจึงคิดว่าถ้าเราพิสูจน์ค่านี้ได้ใน 1 หรือ 2 บรรทัด .. ถ้าเป็นหลักฐานที่ยิ่งใหญ่ .. ก็ไม่มีปัญหา
ซันนี่

2
@ ซันนี่มันไม่ยากเกินไปที่จะพิสูจน์ ในช่วงจำนวนเต็มจำนวนบวกทั้งหมดจะมีค่าลบ (so i != -i) ที่ตัวเลขสองใบในช่วง: และ0 Integer.MIN_VALUEเพราะi != 0ในของคุณหากเท่านั้นMIN_VALUEที่เหลืออยู่
Vincent van der Weele

1
@Heuster - เหตุผลนั้นใช้ได้ผล ... แต่ขึ้นอยู่กับข้อสันนิษฐานหรือสองข้อที่ต้องการการพิสูจน์
Stephen 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.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หรือ-2147483648และInteger.MAX_VALUEจะมีค่าเท่ากับหรือ2^31-1 คือซึ่งตอนนี้มีขนาดใหญ่เกินไปสำหรับจำนวนเต็ม (เนื่องจากเป็นอดีต) จึงทำให้จำนวนเต็มล้นทำให้อีกครั้ง เป็นจำนวนเต็มเดียวที่ทำเช่นนี้เนื่องจากเป็นจำนวนเดียวที่ไม่มีค่าเท่ากับลบนอกเหนือจาก 02147483647-Integer.MIN_VALUE2^31MAX_VALUEInteger.MIN_VALUEMIN_VALUE


2
@dystroy จริง ๆ แล้วฉันกำลังมองหาคำอธิบายบางอย่างตามที่ Mark ไม่มีตัวเลขเช่น +2147483648 ในช่วง int ดังนั้นผู้ต้องสงสัยรายแรกควรเป็นหมายเลขนี้นอกเหนือจาก 0 ช่วงคือ -2 ^ n ถึง 2 ^ n-1 ดังนั้นจึงไม่มีผลบวกกับ -2 ^ n นี่เป็นเพียงค่า int อื่นที่เป็นไปได้
ซันนี่

1
ฉันไม่ได้อธิบายเป็นไบนารีเนื่องจากมีคนอื่นครอบคลุมอยู่แล้ว (โดยทั่วไป int คือค่า 32 บิตนั่นคือสาเหตุที่มีขีด จำกัด เหล่านั้น) นอกจากนี้ค่าลบของค่าลบยังเป็นค่าบวกดังนั้นข้อกำหนดยังคงใช้บังคับ
Mark M

1
ผิดปกติมากพอใน Java ตัวเลข2147483648อาจปรากฏในซอร์สโค้ดในกรณีเดียวเท่านั้น: เป็นตัวถูกดำเนินการของตัวดำเนินการลบ unary (JLS 3.10.1)
Eric Jablow

6

การพิสูจน์พีชคณิตเบื้องต้นโดยใช้modulo 2^32เลขคณิต:

i == -iสามารถเขียนใหม่เป็น2 * i == 0(เพิ่มiทั้งสองด้าน) หรือi << 1 == 0.

สมการนี้มีคำตอบสองแบบของรูปแบบi == 0 >> 1กล่าวคือ0bและ10000000000000000000000000000000bได้มาจากการเลื่อนไปทางใดทางหนึ่ง0หรือ1ทางซ้าย

แก้ปัญหาถูกกีดกันยังคงมีการแก้ปัญหาi == 0i == 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

เพราะ i <= Integer.MAX_VALUE จะไม่เป็นเท็จ
Kuba

1
<
โอ้
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.