Saya ingin menangani kasus khusus di mana mengalikan dua angka bersama-sama menyebabkan luapan. Kode tersebut terlihat seperti ini:
int a = 20;
long b = 30;
// if a or b are big enough, this result will silently overflow
long c = a * b;
Itu versi yang disederhanakan. Dalam program nyata a
dan b
bersumber dari tempat lain saat runtime. Yang ingin saya capai adalah seperti ini:
long c;
if (a * b will overflow) {
c = Long.MAX_VALUE;
} else {
c = a * b;
}
Bagaimana saran Anda agar saya membuat kode terbaik ini?
Perbarui: a
dan b
selalu tidak negatif dalam skenario saya.
java
math
long-integer
integer-overflow
Steve McLeod
sumber
sumber
Jawaban:
Java 8 memiliki
Math.multiplyExact
,Math.addExact
dll. Untuk int dan long. Ini membuang centangArithmeticException
pada overflow.sumber
Jika
a
danb
keduanya positif maka Anda dapat menggunakan:Jika Anda perlu berurusan dengan bilangan positif dan negatif maka ini lebih rumit:
Berikut tabel kecil yang saya siapkan untuk memeriksanya, berpura-pura bahwa luapan terjadi pada -10 atau +10:
sumber
n
,n > x
sama dengann > floor(x)
. Untuk pembagian bilangan bulat positif melakukan lantai implisit. (Untuk angka negatif malah dibulatkan)a = -1
danb = 10
, lihat jawaban saya di bawah.Ada pustaka Java yang menyediakan operasi aritmatika yang aman, yang memeriksa long overflow / underflow. Misalnya, Guava's LongMath.checkedMultiply (long a, long b) mengembalikan produk dari
a
danb
, asalkan tidak meluap, dan melemparArithmeticException
jikaa * b
meluap dalamlong
aritmatika bertanda tangan .sumber
Anda dapat menggunakan java.math.BigInteger sebagai gantinya dan memeriksa ukuran hasilnya (belum menguji kode):
sumber
Gunakan logaritma untuk memeriksa ukuran hasil.
sumber
ceil(log(a)) + ceil(log(b)) > log(Long.MAX)
?Apakah Java memiliki sesuatu seperti int.MaxValue? Jika ya, cobalah
edit: terlihat Long.MAX_VALUE yang dimaksud
sumber
Math.Abs(a)
tidak berfungsi jikaa
adaLong.MIN_VALUE
.Inilah cara paling sederhana yang dapat saya pikirkan
sumber
Dicuri dari jruby
UPDATE: Kode ini pendek dan berfungsi dengan baik; Namun, gagal untuk a = -1, b = Long.MIN_VALUE.
Satu peningkatan yang mungkin:
Perhatikan bahwa ini akan menangkap beberapa luapan tanpa pembagian apa pun.
sumber
Seperti yang telah ditunjukkan, Java 8 memiliki metode Math.xxxExact yang memunculkan pengecualian saat overflow.
Jika Anda tidak menggunakan Java 8 untuk proyek Anda, Anda masih dapat "meminjam" implementasinya yang cukup ringkas.
Berikut adalah beberapa link ke implementasi ini dalam repositori kode sumber JDK, tidak ada jaminan apakah ini akan tetap valid, tetapi bagaimanapun juga Anda harus dapat mendownload sumber JDK dan melihat bagaimana mereka melakukan keajaibannya di dalam
java.lang.Math
kelas.Math.multiplyExact(long, long)
http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/lang/Math.java#l925Math.addExact(long, long)
http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/lang/Math.java#l830dll, dll.
DIPERBARUI: mengalihkan tautan tidak valid ke situs web pihak ketiga ke tautan ke repositori Mercurial dari Open JDK.
sumber
Saya tidak yakin mengapa tidak ada yang melihat solusi seperti:
Pilih a menjadi lebih besar dari dua angka.
sumber
a
lebih besar atau lebih kecil?Saya ingin mengembangkan jawaban John Kugelman tanpa menggantinya dengan mengeditnya secara langsung. Ini bekerja untuk kasus uji (
MIN_VALUE = -10
,MAX_VALUE = 10
) karena kesimetrisannyaMIN_VALUE == -MAX_VALUE
, yang bukan kasus untuk bilangan bulat komplemen dua. SebenarnyaMIN_VALUE == -MAX_VALUE - 1
,.Ketika diterapkan pada true
MIN_VALUE
andMAX_VALUE
, jawaban John Kugelman menghasilkan kasus overflow kapana == -1
danb ==
lainnya (poin pertama kali dikemukakan oleh Kyle). Berikut cara untuk memperbaikinya:Ini bukan solusi umum untuk
MIN_VALUE
danMAX_VALUE
, tetapi umum untuk JavaLong
danInteger
dan nilai apa pun daria
danb
.sumber
MIN_VALUE = -MAX_VALUE - 1
, bukan kasus lain (termasuk contoh kasus uji Anda). Saya harus banyak berubah.Mungkin:
Tidak yakin dengan "solusi" ini.
Edit: Menambahkan b! = 0.
Sebelum Anda memberi suara negatif : a * b / b tidak akan dioptimalkan. Ini akan menjadi bug kompilator. Saya masih tidak melihat kasus di mana bug luapan dapat ditutup-tutupi.
sumber
a * b / b
kemungkinan akan dioptimalkan hanyaa
dalam banyak konteks lain.mungkin ini akan membantu Anda:
sumber
long
.c / c ++ (panjang * panjang):
java (int * int, maaf saya tidak menemukan int64 di java):
1. simpan hasilnya dalam tipe besar (int * int letakkan hasilnya ke long, long * long put ke int64)
2. hasil cmp >> bit dan hasil >> (bit - 1)
sumber