รหัสนี้:
System.out.println(Math.abs(Integer.MIN_VALUE));
ผลตอบแทน -2147483648
มันไม่ควรคืนค่าสัมบูรณ์เป็น2147483648
?
รหัสนี้:
System.out.println(Math.abs(Integer.MIN_VALUE));
ผลตอบแทน -2147483648
มันไม่ควรคืนค่าสัมบูรณ์เป็น2147483648
?
คำตอบ:
Integer.MIN_VALUE
เป็น-2147483648
แต่มูลค่าสูงสุด 32 +2147483647
บิตจำนวนเต็มสามารถมีคือ ความพยายามที่จะเป็นตัวแทน+2147483648
ใน int 32 บิตจะได้อย่างมีประสิทธิภาพ "เกลือกกลิ้ง" -2147483648
เพื่อ นี้เป็นเพราะเมื่อใช้ลงนามจำนวนเต็มสองของเสริมของเลขฐานสอง+2147483648
และ-2147483648
เหมือนกัน อย่างไรก็ตามนี่ไม่ใช่ปัญหา แต่+2147483648
ถือว่าอยู่นอกขอบเขต
สำหรับการอ่านน้อยมากเกี่ยวกับเรื่องนี้คุณอาจต้องการที่จะตรวจสอบบทความวิกิพีเดียเติมเต็มสองของ
พฤติกรรมที่คุณชี้ให้เห็นนั้นขัดแย้งกับธรรมชาติ อย่างไรก็ตามพฤติกรรมนี้เป็นลักษณะที่ระบุโดยjavadoc สำหรับMath.abs(int)
:
ถ้าอาร์กิวเมนต์ไม่เป็นลบอาร์กิวเมนต์จะถูกส่งกลับ ถ้าอาร์กิวเมนต์เป็นลบการปฏิเสธของอาร์กิวเมนต์จะถูกส่งกลับ
นั่นคือMath.abs(int)
ควรทำงานเหมือนโค้ด Java ต่อไปนี้:
public static int abs(int x){
if (x >= 0) {
return x;
}
return -x;
}
-x
นั่นคือในกรณีที่เชิงลบ
ตามที่ส่วน JLS 15.15.4ที่-x
เท่ากับ(~x)+1
ที่~
เป็นผู้ประกอบการระดับบิตสมบูรณ์
หากต้องการตรวจสอบว่าเสียงถูกต้องหรือไม่ลองใช้ -1 เป็นตัวอย่าง
ค่าจำนวนเต็ม-1
สามารถระบุได้เป็น0xFFFFFFFF
เลขฐานสิบหกใน Java (ตรวจสอบสิ่งนี้ด้วย a println
หรือวิธีการอื่น ๆ ) การดำเนินการดังกล่าว-(-1)
จะช่วยให้:
-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
ดังนั้นมันได้ผล
Integer.MIN_VALUE
ให้เราพยายามที่ตอนนี้มี เมื่อทราบว่าจำนวนเต็มต่ำสุดสามารถแสดงได้0x80000000
นั่นคือบิตแรกที่ตั้งค่าเป็น 1 และ 31 บิตที่เหลือตั้งค่าเป็น 0 เรามี:
-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1
= 0x80000000 = Integer.MIN_VALUE
และนี่คือเหตุผลที่Math.abs(Integer.MIN_VALUE)
กลับInteger.MIN_VALUE
มา นอกจากนี้ทราบว่าเป็น0x7FFFFFFF
Integer.MAX_VALUE
ที่กล่าวว่าเราจะหลีกเลี่ยงปัญหาอันเนื่องมาจากมูลค่าผลตอบแทนที่ตอบโต้ได้ง่ายในอนาคตได้อย่างไร
เราสามารถ, เป็นแหลมออกโดย @Bombeหล่อของเราint
ที่จะlong
ก่อน อย่างไรก็ตามเราต้องอย่างใดอย่างหนึ่ง
int
s
Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
ซึ่งไม่ได้เพราะlong
s อย่างใดหวังว่าเราจะไม่เรียกร้องMath.abs(long)
ที่มีค่าเท่ากับตั้งแต่เรายังมีLong.MIN_VALUE
Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
เราสามารถใช้BigInteger
s ได้ทุกที่เพราะBigInteger.abs()
จะคืนค่าเป็นบวกเสมอ นี่เป็นทางเลือกที่ดีแม้ว่าจะช้ากว่าการจัดการประเภทจำนวนเต็มดิบเล็กน้อย
เราสามารถเขียนกระดาษห่อของเราเองได้Math.abs(int)
ดังนี้:
/**
* Fail-fast wrapper for {@link Math#abs(int)}
* @param x
* @return the absolute value of x
* @throws ArithmeticException when a negative value would have been returned by {@link Math#abs(int)}
*/
public static int abs(int x) throws ArithmeticException {
if (x == Integer.MIN_VALUE) {
// fail instead of returning Integer.MAX_VALUE
// to prevent the occurrence of incorrect results in later computations
throw new ArithmeticException("Math.abs(Integer.MIN_VALUE)");
}
return Math.abs(x);
}
int positive = value & Integer.MAX_VALUE
(โดยพื้นฐานแล้วจะล้นจากInteger.MAX_VALUE
ถึง0
แทนที่จะเป็นInteger.MIN_VALUE
)ในท้ายที่สุดปัญหานี้ดูเหมือนจะเป็นที่ทราบกันดีอยู่แล้ว ดูตัวอย่างรายการนี้เกี่ยวกับกฎ findbugs ที่เกี่ยวข้อง
นี่คือสิ่งที่ Java doc พูดสำหรับ Math.abs () ในjavadoc :
โปรดสังเกตว่าถ้าอาร์กิวเมนต์เท่ากับค่า Integer.MIN_VALUE ซึ่งเป็นค่า int ที่เป็นค่าลบมากที่สุดผลลัพธ์จะเป็นค่าเดียวกันซึ่งเป็นค่าลบ
หากต้องการดูผลลัพธ์ที่คุณคาดหวังให้ส่งInteger.MIN_VALUE
ไปที่long
:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
Math.abs
ถูกต่อต้านโดยการคืนค่าจำนวนลบ:Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
ArithmeticException
? นอกจากนี้พฤติกรรมนี้ยังได้รับการบันทึกไว้อย่างชัดเจนในเอกสาร API
Math.abs(long)
ฉันแค่อยากจะชี้ให้เห็นว่าพฤติกรรมนี้ซึ่งเป็นแหล่งที่มาของข้อบกพร่องที่ไม่ได้รับการแก้ไขโดยการใช้งานของ ขออภัยในความผิดพลาดของฉันที่นี่: ฉันคิดว่าคุณเสนอให้ใช้Math.abs(long)
เพื่อแก้ไขเมื่อคุณแสดงให้เห็นว่าเป็นวิธีง่ายๆในการ "เห็นผลลัพธ์ที่ผู้ถามคาดหวัง" ขออภัย.
2147483648 ไม่สามารถเก็บเป็นจำนวนเต็มใน java ได้การแสดงไบนารีจะเหมือนกับ -2147483648
แต่(int) 2147483648L == -2147483648
มีจำนวนลบหนึ่งตัวที่ไม่มีค่าเทียบเท่าบวกดังนั้นจึงไม่มีค่าบวกสำหรับมัน คุณจะเห็นพฤติกรรมเดียวกันกับ Long.MAX_VALUE
มีการแก้ไขนี้ใน Java 15 จะเป็นวิธีการ int และยาว พวกเขาจะนำเสนอในชั้นเรียน
java.lang.Math and java.lang.StrictMath
วิธีการ
public static int absExact(int a)
public static long absExact(long a)
ถ้าคุณผ่าน
Integer.MIN_VALUE
หรือ
Long.MIN_VALUE
ข้อยกเว้นถูกโยนทิ้ง
https://bugs.openjdk.java.net/browse/JDK-8241805
ฉันต้องการดูว่า Long.MIN_VALUE หรือ Integer.MIN_VALUE ถูกส่งผ่านค่าบวกจะได้รับผลตอบแทนไม่ใช่ข้อยกเว้น แต่