Kode ini:
System.out.println(Math.abs(Integer.MIN_VALUE));
Kembali -2147483648
Haruskah itu tidak mengembalikan nilai absolut sebagai 2147483648
?
java
absolute-value
pengguna665319
sumber
sumber
Perilaku yang Anda tunjukkan memang kontra-intuitif. Namun, perilaku ini adalah perilaku yang ditentukan oleh javadoc untuk
Math.abs(int)
:Artinya,
Math.abs(int)
harus berperilaku seperti kode Java berikut:public static int abs(int x){ if (x >= 0) { return x; } return -x; }
Artinya, dalam kasus negatif
-x
,.Menurut JLS bagian 15.15.4 ,
-x
adalah sama dengan(~x)+1
, di mana~
operator pelengkap bitwise.Untuk memeriksa apakah ini terdengar benar, mari kita ambil -1 sebagai contoh.
Nilai integer
-1
dapat dicatat seperti0xFFFFFFFF
dalam heksadesimal di Java (lihat ini dengan aprintln
atau metode lain). Mengambil-(-1)
demikian memberi:-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
Jadi, itu berhasil.
Mari kita coba sekarang dengan
Integer.MIN_VALUE
. Mengetahui bahwa bilangan bulat terendah dapat diwakili oleh0x80000000
, yaitu, bit pertama disetel ke 1 dan 31 bit tersisa disetel ke 0, kami memiliki:-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1 = 0x80000000 = Integer.MIN_VALUE
Dan inilah mengapa
Math.abs(Integer.MIN_VALUE)
kembaliInteger.MIN_VALUE
. Juga mencatat bahwa0x7FFFFFFF
adalahInteger.MAX_VALUE
.Karena itu, bagaimana kita dapat menghindari masalah karena nilai pengembalian kontra-intuitif ini di masa mendatang?
Kita bisa, seperti yang keluar menunjuk oleh @Bombe , cor kami
int
s untuklong
sebelumnya. Kami, bagaimanapun, harus baikint
s, yang tidak berfungsi karenaInteger.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
.long
berharap bahwa kita tidak akan pernah meneleponMath.abs(long)
dengan nilai yang samaLong.MIN_VALUE
, karena kita juga punyaMath.abs(Long.MIN_VALUE) == Long.MIN_VALUE
.Kita bisa menggunakan
BigInteger
s dimana saja, karenaBigInteger.abs()
memang selalu mengembalikan nilai positif. Ini adalah alternatif yang baik, meskipun sedikit lebih lambat daripada memanipulasi tipe integer mentah.Kita dapat menulis pembungkus kita sendiri untuk
Math.abs(int)
, seperti ini:/** * 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
(pada dasarnya meluap dariInteger.MAX_VALUE
ke0
alih-alihInteger.MIN_VALUE
)Sebagai catatan terakhir, masalah ini sepertinya sudah diketahui beberapa waktu lalu. Lihat misalnya entri ini tentang aturan findbugs yang sesuai .
sumber
Inilah yang dikatakan oleh dokumen Java untuk Math.abs () di javadoc :
sumber
Untuk melihat hasil yang Anda harapkan, transmisikan
Integer.MIN_VALUE
kelong
:System.out.println(Math.abs((long) Integer.MIN_VALUE));
sumber
Math.abs
berlawanan dengan intuisi dengan mengembalikan angka negatif:Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
ArithmeticException
? Selain itu, perilaku tersebut didokumentasikan dengan jelas dalam dokumentasi API.Math.abs(long)
. Saya minta maaf atas kesalahan saya di sini: Saya mengira Anda mengusulkan penggunaanMath.abs(long)
sebagai perbaikan, ketika Anda menunjukkannya sebagai cara sederhana untuk "melihat hasil yang diharapkan penanya". Maaf.2147483648 tidak dapat disimpan dalam integer di java, representasi binernya sama dengan -2147483648.
sumber
Tetapi
(int) 2147483648L == -2147483648
ada satu bilangan negatif yang tidak memiliki padanan positif sehingga tidak ada nilai positif untuk itu. Anda akan melihat perilaku yang sama dengan Long.MAX_VALUE.sumber
Ada perbaikan ini di Jawa 15 akan menjadi metode int dan panjang. Mereka akan hadir di kelas
Metodenya.
public static int absExact(int a) public static long absExact(long a)
Jika Anda lulus
ATAU
Pengecualian dilemparkan.
https://bugs.openjdk.java.net/browse/JDK-8241805
Saya ingin melihat apakah Long.MIN_VALUE atau Integer.MIN_VALUE dilewatkan, nilai positif akan dikembalikan dan bukan pengecualian tetapi.
sumber
Math.abs tidak bekerja sepanjang waktu dengan angka-angka besar. Saya menggunakan logika kode kecil ini yang saya pelajari ketika saya berusia 7 tahun!
if(Num < 0){ Num = -(Num); }
sumber
s
disini?Num
sama denganInteger.MIN_VALUE
sebelum cuplikan?