Bu kod:
System.out.println(Math.abs(Integer.MIN_VALUE));
İadeler -2147483648
Mutlak değeri olarak döndürmemeli 2147483648mi?
Bu kod:
System.out.println(Math.abs(Integer.MIN_VALUE));
İadeler -2147483648
Mutlak değeri olarak döndürmemeli 2147483648mi?
Yanıtlar:
Integer.MIN_VALUEolduğu -2147483648, ancak 32 bitlik tamsayı içerebilir yüksek değerdir +2147483647. +214748364832 bitlik bir int içinde temsil etmeye çalışmak , etkin bir şekilde "dönecektir" -2147483648. Bunun nedeni, işaretli tamsayılar kullanıldığında, ikisinin tamamlayıcı ikili gösterimlerinin +2147483648ve -2147483648aynı olmasıdır. Ancak, +2147483648menzil dışında kabul edildiği için bu bir sorun değildir .
Bu konuyla ilgili biraz daha okumak için , İki'nin tamamlayıcısı hakkındaki Wikipedia makalesine göz atmak isteyebilirsiniz .
Gösterdiğiniz davranış gerçekten de sezgiseldir. Ancak, bu davranış javadocMath.abs(int) tarafından şunlar için belirtilmiştir :
Argüman negatif değilse, argüman döndürülür. Bağımsız değişken negatifse, bağımsız değişkenin olumsuzluğu döndürülür.
Yani, Math.abs(int)aşağıdaki Java kodu gibi davranmalıdır:
public static int abs(int x){
if (x >= 0) {
return x;
}
return -x;
}
Yani, olumsuz durumda -x.
Göre JLS bölümüne 15.15.4 , -xeşit olduğu (~x)+1durumlarda, ~bit seviyesinde tamamlayıcı bir operatördür.
Bunun kulağa doğru gelip gelmediğini kontrol etmek için, örnek olarak -1'i alalım.
Tamsayı değeri -1, 0xFFFFFFFFJava'da onaltılık olarak not edilebilir (bunu bir printlnveya başka bir yöntemle kontrol edin ). -(-1)Böylece almak :
-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
Yani işe yarıyor.
Şimdi deneyelim Integer.MIN_VALUE. En düşük tamsayının 0x80000000, yani ilk bitin 1'e ve kalan 31 bitin 0'a ayarlanmasıyla temsil edilebileceğini bilerek , elimizde:
-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1
= 0x80000000 = Integer.MIN_VALUE
Ve bu yüzden Math.abs(Integer.MIN_VALUE)geri döner Integer.MIN_VALUE. Ayrıca unutmayınız 0x7FFFFFFFolduğunu Integer.MAX_VALUE.
Bununla birlikte, gelecekte bu karşı-sezgisel geri dönüş değeri nedeniyle sorunlardan nasıl kaçınabiliriz?
Bunu yapabilirdik @Bombe tarafından sivri out gibi , bizim dökme intiçin s longönce. Ancak biz de
ints'ye çevirin, bu işe yaramıyor çünkü
Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE).longşekilde asla Math.abs(long)eşit bir değerle çağırmayacağımızı umarak devam edin Long.MIN_VALUE, çünkü bizde de var Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.Her BigIntegeryerde s kullanabiliriz , çünkü BigInteger.abs()gerçekten her zaman pozitif bir değer döndürür. Bu, ham tam sayı türlerini değiştirmekten biraz daha yavaş olsa da iyi bir alternatiftir.
Bunun için kendi paketleyicimizi yazabiliriz 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(esas olarak taşan Integer.MAX_VALUEiçin 0yerine Integer.MIN_VALUE)Son bir not olarak, bu sorun bir süredir biliniyor gibi görünüyor. Örneğin , ilgili bulma hataları kuralı hakkındaki bu girişe bakın .
Beklediğiniz sonucu görmek için şunlara Integer.MIN_VALUEgönderin long:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
Math.absnegatif bir sayı döndürerek mantığa aykırı olduğu gerçeğini çözmez :Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
ArithmeticException? Ayrıca, davranış, API belgelerinde açıkça belgelenmiştir.
Math.abs(long). Buradaki hatam için özür dilerim: "Soruyu soranın Math.abs(long)beklediği sonucu görmenin" basit bir yolu olarak gösterdiğiniz zaman, bir düzeltme olarak kullanımını önerdiğinizi anladım. Afedersiniz.
Fakat (int) 2147483648L == -2147483648 pozitif karşılığı olmayan bir negatif sayı vardır, dolayısıyla pozitif değeri yoktur. Long.MAX_VALUE ile aynı davranışı göreceksiniz.
Java 15'te bunun için bir düzeltme var, int ve long için bir yöntem olacak. Sınıflarda bulunacaklar
java.lang.Math and java.lang.StrictMath
Metodlar.
public static int absExact(int a)
public static long absExact(long a)
Eğer geçersen
Integer.MIN_VALUE
VEYA
Long.MIN_VALUE
Bir İstisna atılır.
https://bugs.openjdk.java.net/browse/JDK-8241805
Long.MIN_VALUE veya Integer.MIN_VALUE değerinin pozitif bir değer geçirilip geçirilmediğini görmek istiyorum, bir istisna değil, döndürür.