Bagaimana Java menangani integer underflow dan overflow dan bagaimana Anda memeriksanya?


226

Bagaimana Java menangani integer underflow dan overflow?

Mengarahinya, bagaimana Anda memeriksa / menguji apakah ini terjadi?


28
Sayang sekali Java tidak menyediakan akses tidak langsung ke flag overflow CPU , seperti yang dilakukan pada C # .
Drew Noakes

@DrewNoakes Dan sayang sekali C # tidak default checkedsejauh yang saya tahu. Saya tidak melihat itu banyak digunakan, dan mengetik checked { code; }adalah tentang sebanyak pekerjaan memanggil metode.
Maarten Bodewes

2
@ MaartenBodewes, Anda dapat mengaturnya sebagai default selama kompilasi majelis. csc /checked ...atau atur properti di panel properti proyek di Visual Studio.
Drew Noakes

@RewNoakes OK, menarik. Agak aneh bahwa itu adalah pengaturan di luar kode. Secara umum saya ingin memiliki perilaku yang sama dari suatu program terlepas dari pengaturan seperti itu (mungkin kecuali pernyataan).
Maarten Bodewes

@ MaartenBodewes, saya pikir alasannya adalah bahwa ada overhead non-sepele untuk memeriksa. Jadi mungkin Anda akan mengaktifkannya di debug build, lalu nonaktifkan di build rilis, sama seperti banyak jenis asersi lainnya.
Drew Noakes

Jawaban:


217

Jika meluap, itu akan kembali ke nilai minimum dan berlanjut dari sana. Jika underflow, kembali ke nilai maksimum dan berlanjut dari sana.

Anda dapat memeriksanya sebelumnya sebagai berikut:

public static boolean willAdditionOverflow(int left, int right) {
    if (right < 0 && right != Integer.MIN_VALUE) {
        return willSubtractionOverflow(left, -right);
    } else {
        return (~(left ^ right) & (left ^ (left + right))) < 0;
    }
}

public static boolean willSubtractionOverflow(int left, int right) {
    if (right < 0) {
        return willAdditionOverflow(left, -right);
    } else {
        return ((left ^ right) & (left ^ (left - right))) < 0;
    }
}

(Anda dapat menggantinya intdengan longmelakukan pemeriksaan yang sama untuk long)

Jika Anda berpikir bahwa ini dapat terjadi lebih dari sering, maka pertimbangkan untuk menggunakan tipe data atau objek yang dapat menyimpan nilai yang lebih besar, misalnya longatau mungkin java.math.BigInteger. Yang terakhir tidak meluap, praktis, memori JVM yang tersedia adalah batasnya.


Jika Anda sudah menggunakan Java8, maka Anda dapat menggunakan metode baru Math#addExact()dan Math#subtractExact()yang akan menyebabkan ArithmeticExceptionoverflow.

public static boolean willAdditionOverflow(int left, int right) {
    try {
        Math.addExact(left, right);
        return false;
    } catch (ArithmeticException e) {
        return true;
    }
}

public static boolean willSubtractionOverflow(int left, int right) {
    try {
        Math.subtractExact(left, right);
        return false;
    } catch (ArithmeticException e) {
        return true;
    }
}

Kode sumber dapat ditemukan di sini dan di sini masing-masing.

Tentu saja, Anda juga bisa langsung menggunakannya daripada menyembunyikannya dalam booleanmetode utilitas.


13
@ dhblah, Katakanlah nilai maksimum dan minimum yang diizinkan Java untuk int +100, -100, masing-masing. Jika Anda menambahkan satu ke integer Java, prosesnya akan terlihat seperti ini saat meluap. 98, 99, 100, -100, -99, -98, .... Apakah itu lebih masuk akal?
Austin A

6
Saya sarankan menggunakan metode utilitas daripada langsung menggunakan kode. Metode utilitas bersifat intrinsik dan akan diganti dengan kode khusus mesin. Tes cepat menunjukkan Math.addExact menjadi 30% lebih cepat daripada metode yang disalin (Java 1.8.0_40).
TilmannZ

1
@ErikE Math#addExactadalah sintaks yang biasanya digunakan saat menulis javadocs - sementara biasanya itu akan dikonversi ke Math.addExact, kadang-kadang bentuk lain hanya bertahan
Pokechu22

1
If it underflows, it goes back to the maximum value and continues from there.- Anda tampaknya bingung dengan aliran bawah negatif. underflow dalam bilangan bulat terjadi setiap saat (ketika hasilnya adalah sebagian kecil).
nave

1
en.wikipedia.org/wiki/Arithmetic_underflow mengatakan bahwa Underflow adalah suatu kondisi dalam program komputer di mana hasil perhitungan adalah sejumlah nilai absolut yang lebih kecil daripada yang dapat ditunjukkan oleh komputer dalam memori pada CPU-nya. Jadi underflow tidak berlaku untuk Java Integers. @BalusC
Jingguo Yao

66

Nah, sejauh tipe integer primitif berjalan, Java tidak menangani Over / Underflow sama sekali (untuk float dan double behavior berbeda, ia akan menyiram ke +/- infinity seperti yang diamanatkan oleh IEEE-754).

Saat menambahkan dua int, Anda tidak akan mendapatkan indikasi kapan terjadi overflow. Metode sederhana untuk memeriksa overflow adalah dengan menggunakan tipe lebih besar berikutnya untuk benar-benar melakukan operasi dan memeriksa apakah hasilnya masih dalam kisaran untuk tipe sumber:

public int addWithOverflowCheck(int a, int b) {
    // the cast of a is required, to make the + work with long precision,
    // if we just added (a + b) the addition would use int precision and
    // the result would be cast to long afterwards!
    long result = ((long) a) + b;
    if (result > Integer.MAX_VALUE) {
         throw new RuntimeException("Overflow occured");
    } else if (result < Integer.MIN_VALUE) {
         throw new RuntimeException("Underflow occured");
    }
    // at this point we can safely cast back to int, we checked before
    // that the value will be withing int's limits
    return (int) result;
}

Apa yang akan Anda lakukan sebagai pengganti klausa throw, tergantung pada persyaratan aplikasi Anda (throw, flush to min / max atau hanya login apa saja). Jika Anda ingin mendeteksi kelebihan pada operasi yang lama, Anda kurang beruntung dengan primitif, gunakan BigInteger sebagai gantinya.


Sunting (2014-05-21): Karena pertanyaan ini tampaknya cukup sering dirujuk dan saya harus menyelesaikan masalah yang sama, cukup mudah untuk mengevaluasi kondisi overflow dengan metode yang sama CPU akan menghitung flag V-nya.

Pada dasarnya ini adalah ekspresi boolean yang melibatkan tanda dari kedua operan serta hasilnya:

/**
 * Add two int's with overflow detection (r = s + d)
 */
public static int add(final int s, final int d) throws ArithmeticException {
    int r = s + d;
    if (((s & d & ~r) | (~s & ~d & r)) < 0)
        throw new ArithmeticException("int overflow add(" + s + ", " + d + ")");    
    return r;
}

Dalam java lebih mudah untuk menerapkan ekspresi (dalam if) ke seluruh 32 bit, dan periksa hasilnya menggunakan <0 (ini akan secara efektif menguji bit tanda). Prinsip kerjanya persis sama untuk semua tipe primitif integer , mengubah semua deklarasi dalam metode di atas menjadi lama membuatnya bekerja lama.

Untuk jenis yang lebih kecil, karena konversi implisit ke int (lihat JLS untuk operasi bitwise untuk detail), alih-alih memeriksa <0, pemeriksaan perlu menutupi bit tanda secara eksplisit (0x8000 untuk operan pendek, 0x80 untuk operan byte, sesuaikan gips dan deklarasi parameter dengan tepat):

/**
 * Subtract two short's with overflow detection (r = d - s)
 */
public static short sub(final short d, final short s) throws ArithmeticException {
    int r = d - s;
    if ((((~s & d & ~r) | (s & ~d & r)) & 0x8000) != 0)
        throw new ArithmeticException("short overflow sub(" + s + ", " + d + ")");
    return (short) r;
}

(Perhatikan bahwa contoh di atas menggunakan kebutuhan ekspresi untuk mengurangi deteksi luapan)


Jadi bagaimana / mengapa ungkapan boolean ini bekerja? Pertama, beberapa pemikiran logis mengungkapkan bahwa luapan hanya dapat terjadi jika tanda-tanda dari kedua argumen itu sama. Karena, jika satu argumen negatif dan satu positif, hasil (dari tambah) harus mendekati nol, atau dalam kasus ekstrim satu argumen adalah nol, sama dengan argumen lainnya. Karena argumen sendiri tidak dapat membuat kondisi overflow, jumlah mereka juga tidak dapat membuat overflow.

Jadi apa yang terjadi jika kedua argumen memiliki tanda yang sama? Mari kita lihat kasus keduanya positif: menambahkan dua argumen yang membuat jumlah lebih besar dari jenis MAX_VALUE, akan selalu menghasilkan nilai negatif, sehingga terjadi overflow jika arg1 + arg2> MAX_VALUE. Sekarang nilai maksimum yang bisa dihasilkan adalah MAX_VALUE + MAX_VALUE (kasus ekstrem kedua argumen adalah MAX_VALUE). Untuk byte (contoh) yang berarti 127 + 127 = 254. Melihat representasi bit dari semua nilai yang dapat dihasilkan dari menambahkan dua nilai positif, orang menemukan bahwa yang overflow (128 hingga 254) semuanya memiliki bit 7 set, sementara semua yang tidak meluap (0 hingga 127) telah dihapus bit 7 (paling atas, tanda). Itulah tepatnya yang diperiksa bagian pertama (kanan) dari ekspresi:

if (((s & d & ~r) | (~s & ~d & r)) < 0)

(~ s & ~ d & r) menjadi benar, hanya jika , kedua operan (s, d) positif dan hasilnya (r) negatif (ekspresi bekerja pada semua 32 bit, tetapi hanya bit yang kami tertarik adalah bit paling atas (tanda), yang diperiksa terhadap <0).

Sekarang jika kedua argumen negatif, jumlah mereka tidak akan pernah bisa mendekati nol daripada argumen mana pun, jumlahnya harus lebih dekat ke minus tanpa batas. Nilai paling ekstrem yang dapat kami hasilkan adalah MIN_VALUE + MIN_VALUE, yang (sekali lagi sebagai contoh byte) menunjukkan bahwa untuk setiap nilai rentang (-1 hingga -128) bit tanda diatur, sementara kemungkinan nilai melimpah yang lain (-129 hingga -256 ) memiliki tanda sedikit dihapus. Jadi tanda hasil lagi mengungkapkan kondisi melimpah. Itulah yang setengah bagian kiri (s & d & r) memeriksa untuk kasus di mana kedua argumen (s, d) negatif dan hasil yang positif. Logikanya sebagian besar setara dengan kasus positif; semua pola bit yang dapat dihasilkan dari menambahkan dua nilai negatif akan memiliki bit tanda dihapus jika dan hanya jika terjadi underflow.


1
Anda dapat memeriksanya dengan operator bitwise, juga betterlogic.com/roger/2011/05/...
rogerdpack

1
Ini akan berhasil tetapi saya berasumsi ini akan memiliki kinerja yang buruk
chessofnerd

33

Secara default, matematika panjang dan int Java secara diam-diam membungkus overflow dan underflow. (Operasi integer pada tipe integer lain dilakukan dengan terlebih dahulu mempromosikan operan ke int atau panjang, sesuai JLS 4.2.2 .)

Sebagai Jawa 8, java.lang.Mathmenyediakan addExact, subtractExact, multiplyExact, incrementExact, decrementExactdan negateExactmetode statis untuk kedua int dan argumen panjang yang melakukan operasi bernama, melemparkan ArithmeticException overflow. (Tidak ada metode divideExact - Anda harus memeriksa sendiri satu case khusus ( MIN_VALUE / -1).)

Pada Java 8, java.lang.Math juga menyediakan toIntExactuntuk melemparkan panjang ke int, melempar ArithmeticException jika nilai long tidak cocok dengan int. Ini bisa berguna untuk misalnya menghitung jumlah int menggunakan matematika panjang yang tidak dicentang, kemudian menggunakan toIntExactuntuk melemparkan ke int pada akhirnya (tapi hati-hati jangan sampai jumlah Anda melimpah)

Jika Anda masih menggunakan versi Java yang lebih lama, Google Guava menyediakan metode statis IntMath dan LongMath untuk penambahan, pengurangan, penggandaan, dan eksponansi yang dicentang (melempar meluap). Kelas-kelas ini juga menyediakan metode untuk menghitung faktorial dan koefisien binomial yang kembali MAX_VALUEpada overflow (yang kurang nyaman untuk diperiksa). Kelas utilitas primitif jambu ini, SignedBytes, UnsignedBytes, Shortsdan Ints, menyediakan checkedCastmetode untuk mempersempit jenis yang lebih besar (melemparkan IllegalArgumentException di bawah / overflow, tidak ArithmeticException), serta saturatingCastmetode yang kembali MIN_VALUEatau MAX_VALUEoverflow.


32

Java tidak melakukan apa pun dengan integer overflow untuk tipe primitif int atau panjang dan mengabaikan overflow dengan integer positif dan negatif.

Jawaban ini pertama menggambarkan bilangan bulat bilangan bulat, memberikan contoh bagaimana hal itu bisa terjadi, bahkan dengan nilai-nilai menengah dalam evaluasi ekspresi, dan kemudian memberikan tautan ke sumber daya yang memberikan teknik terperinci untuk mencegah dan mendeteksi bilangan bulat bilangan bulat.

Aritmatika dan ekspresi integer yang menghasilkan limpahan yang tidak terduga atau tidak terdeteksi adalah kesalahan pemrograman yang umum. Overflow integer yang tidak terduga atau tidak terdeteksi juga merupakan masalah keamanan yang dapat dieksploitasi yang terkenal, terutama karena memengaruhi objek array, stack, dan daftar.

Overflow dapat terjadi dalam arah positif atau negatif di mana nilai positif atau negatif akan melampaui nilai maksimum atau minimum untuk tipe primitif yang bersangkutan. Overflow dapat terjadi dalam nilai menengah selama ekspresi atau evaluasi operasi dan memengaruhi hasil ekspresi atau operasi di mana nilai akhir diharapkan berada dalam kisaran.

Kadang-kadang overflow negatif secara keliru disebut underflow. Underflow adalah apa yang terjadi ketika suatu nilai lebih dekat ke nol daripada yang diizinkan oleh representasi. Underflow terjadi dalam bilangan bulat aritmatika dan diharapkan. Underflow integer terjadi ketika evaluasi integer antara -1 dan 0 atau 0 dan 1. Apa yang akan menjadi hasil fraksional terpotong menjadi 0. Ini normal dan diharapkan dengan bilangan aritmatika integer dan tidak dianggap sebagai kesalahan. Namun, hal itu dapat menyebabkan pelemparan kode pengecualian. Salah satu contoh adalah pengecualian "ArithmeticException: / by nol" jika hasil dari integer underflow digunakan sebagai pembagi dalam ekspresi.

Pertimbangkan kode berikut:

int bigValue = Integer.MAX_VALUE;
int x = bigValue * 2 / 5;
int y = bigValue / x;

yang menghasilkan x ditugaskan 0 dan evaluasi selanjutnya dari bigValue / x melempar pengecualian, "ArithmeticException: / by zero" (yaitu, bagi dengan nol), alih-alih Anda ditugaskan nilai 2.

Hasil yang diharapkan untuk x akan menjadi 858.993.458 yang kurang dari nilai int maksimum 2.147.483.647. Namun, hasil antara dari mengevaluasi Integer.MAX_Value * 2, akan menjadi 4.294.967.294, yang melebihi nilai int maksimum dan -2 sesuai dengan representasi integer komplemen 2s. Evaluasi selanjutnya dari -2 / 5 mengevaluasi ke 0 yang ditugaskan ke x.

Menyusun ulang ekspresi untuk komputasi x ke ekspresi yang, ketika dievaluasi, membagi sebelum mengalikan, kode berikut:

int bigValue = Integer.MAX_VALUE;
int x = bigValue / 5 * 2;
int y = bigValue / x;

hasil dalam x ditugaskan 858.993.458 dan y ditugaskan 2, yang diharapkan.

Hasil antara dari bigValue / 5 adalah 429.496.729 yang tidak melebihi nilai maksimum untuk int. Evaluasi selanjutnya dari 429.496.729 * 2 tidak melebihi nilai maksimum untuk int dan hasil yang diharapkan ditugaskan ke x. Evaluasi untuk y kemudian tidak dibagi dengan nol. Evaluasi untuk x dan y berfungsi seperti yang diharapkan.

Nilai integer Java disimpan sebagai dan berperilaku sesuai dengan representasi bilangan bulat bertanda tangan 2s yang melengkapi. Ketika nilai yang dihasilkan akan lebih besar atau lebih kecil dari nilai integer maksimum atau minimum, nilai integer komplemen 2 akan menghasilkan. Dalam situasi yang tidak secara khusus dirancang untuk menggunakan perilaku komplemen 2s, yang merupakan situasi aritmatika integer paling umum, nilai komplemen 2s yang dihasilkan akan menyebabkan logika pemrograman atau kesalahan komputasi seperti yang ditunjukkan pada contoh di atas. Artikel Wikipedia yang sangat bagus menjelaskan 2s bilangan bulat biner di sini: Pelengkap dua - Wikipedia

Ada teknik untuk menghindari overflow bilangan bulat yang tidak disengaja. Teknologi dapat dikategorikan sebagai menggunakan pengujian pra-kondisi, upcasting dan BigInteger.

Pengujian pra-kondisi terdiri dari memeriksa nilai-nilai yang masuk ke operasi aritmatika atau ekspresi untuk memastikan bahwa tidak terjadi overflow dengan nilai-nilai tersebut. Pemrograman dan desain perlu membuat pengujian yang memastikan nilai input tidak akan menyebabkan overflow dan kemudian menentukan apa yang harus dilakukan jika nilai input terjadi yang akan menyebabkan overflow.

Upcasting terdiri dari penggunaan tipe primitif yang lebih besar untuk melakukan operasi atau ekspresi aritmatika dan kemudian menentukan apakah nilai yang dihasilkan di luar nilai maksimum atau minimum untuk integer. Bahkan dengan upcasting, masih mungkin bahwa nilai atau beberapa nilai menengah dalam operasi atau ekspresi akan melampaui nilai maksimum atau minimum untuk jenis upcast dan menyebabkan overflow, yang juga tidak akan terdeteksi dan akan menyebabkan hasil yang tidak diharapkan dan tidak diinginkan. Melalui analisis atau pra-kondisi, dimungkinkan untuk mencegah kelebihan dengan upcasting ketika pencegahan tanpa upcasting tidak mungkin atau praktis. Jika bilangan bulat yang dimaksud adalah tipe primitif yang panjang, maka upcasting tidak dimungkinkan dengan tipe primitif di Jawa.

Teknik BigInteger terdiri dari menggunakan BigInteger untuk operasi aritmatika atau ekspresi menggunakan metode pustaka yang menggunakan BigInteger. BigInteger tidak meluap. Ini akan menggunakan semua memori yang tersedia, jika perlu. Metode hitungnya biasanya hanya sedikit kurang efisien daripada operasi bilangan bulat. Mungkin saja hasil yang menggunakan BigInteger mungkin melampaui nilai maksimum atau minimum untuk bilangan bulat, namun, luapan tidak akan terjadi dalam aritmatika yang mengarah ke hasil. Pemrograman dan desain masih perlu menentukan apa yang harus dilakukan jika hasil BigInteger melampaui nilai maksimum atau minimum untuk tipe hasil primitif yang diinginkan, mis. Int atau panjang.

Program CERT Carnegie Mellon Software Engineering Institute dan Oracle telah menciptakan serangkaian standar untuk pemrograman Java yang aman. Termasuk dalam standar adalah teknik untuk mencegah dan mendeteksi integer overflow. Standar ini diterbitkan sebagai sumber daya online yang dapat diakses secara bebas di sini: The CERT Oracle Secure Coding Standard untuk Java

Bagian standar yang menggambarkan dan berisi contoh praktis teknik pengkodean untuk mencegah atau mendeteksi bilangan bulat bilangan bulat ada di sini: NUM00-J. Deteksi atau cegah integer overflow

Formulir buku dan formulir PDF dari CERT Oracle Secure Coding Standard untuk Java juga tersedia.


ini adalah jawaban terbaik di sini karena secara jelas menyatakan apa itu underflow (jawaban yang diterima tidak) dan juga mencantumkan teknik untuk menangani overflow / underflow
nave

12

Baru saja mengalami masalah ini sendiri, inilah solusi saya (untuk perkalian dan penambahan):

static boolean wouldOverflowOccurwhenMultiplying(int a, int b) {
    // If either a or b are Integer.MIN_VALUE, then multiplying by anything other than 0 or 1 will result in overflow
    if (a == 0 || b == 0) {
        return false;
    } else if (a > 0 && b > 0) { // both positive, non zero
        return a > Integer.MAX_VALUE / b;
    } else if (b < 0 && a < 0) { // both negative, non zero
        return a < Integer.MAX_VALUE / b;
    } else { // exactly one of a,b is negative and one is positive, neither are zero
        if (b > 0) { // this last if statements protects against Integer.MIN_VALUE / -1, which in itself causes overflow.
            return a < Integer.MIN_VALUE / b;
        } else { // a > 0
            return b < Integer.MIN_VALUE / a;
        }
    }
}

boolean wouldOverflowOccurWhenAdding(int a, int b) {
    if (a > 0 && b > 0) {
        return a > Integer.MAX_VALUE - b;
    } else if (a < 0 && b < 0) {
        return a < Integer.MIN_VALUE - b;
    }
    return false;
}

jangan ragu untuk memperbaiki jika salah atau jika dapat disederhanakan. Saya telah melakukan beberapa pengujian dengan metode multiplikasi, sebagian besar kasus tepi, tetapi masih bisa salah.


Division cenderung lambat dibandingkan dengan multiplikasi. Karena int*int, saya pikir cukup casting longdan melihat apakah hasilnya cocok intakan menjadi pendekatan tercepat. Karena long*long, jika seseorang menormalkan operan menjadi positif, satu dapat membagi masing-masing menjadi bagian atas dan bawah 32-bit, mempromosikan setiap setengah hingga panjang (hati-hati tentang ekstensi tanda!), Dan kemudian menghitung dua produk parsial [salah satu bagian atas harus menjadi nol].
supercat

Ketika Anda mengatakan "Lama * lama, jika seseorang menormalkan operan menjadi positif ...", bagaimana Anda akan menormalkan Long.MIN_VALUE?
fragorl

Metode ini mungkin menarik jika diperlukan untuk menguji apakah ada sesuatu yang meluap sebelum benar-benar melakukan perhitungan. Ini bisa bagus untuk pengujian misalnya input pengguna yang digunakan untuk perhitungan seperti itu, daripada menangkap pengecualian ketika itu terjadi.
Maarten Bodewes

8

Ada perpustakaan yang menyediakan operasi aritmatika yang aman, yang memeriksa bilangan bulat overflow / underflow. Misalnya, IntMath.checkedAdd Guava (int a, int b) mengembalikan jumlah adan b, asalkan tidak meluap, dan melempar ArithmeticExceptionjika a + bmeluap dalam intaritmatika yang ditandatangani .


Yap, itu ide yang bagus, kecuali Anda Java 8 atau lebih tinggi, dalam hal ini Mathkelas berisi kode yang sama.
Maarten Bodewes

6

Itu membungkus.

misalnya:

public class Test {

    public static void main(String[] args) {
        int i = Integer.MAX_VALUE;
        int j = Integer.MIN_VALUE;

        System.out.println(i+1);
        System.out.println(j-1);
    }
}

cetakan

-2147483648
2147483647

Baik! Dan sekarang, dapatkah Anda menjawab, bagaimana cara mendeteksinya ke dalam kalkulus yang rumit?
Aubin

5

Saya pikir Anda harus menggunakan sesuatu seperti ini dan itu disebut Upcasting:

public int multiplyBy2(int x) throws ArithmeticException {
    long result = 2 * (long) x;    
    if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE){
        throw new ArithmeticException("Integer overflow");
    }
    return (int) result;
}

Anda dapat membaca lebih lanjut di sini: Mendeteksi atau mencegah integer overflow

Sumbernya cukup andal.


3

Itu tidak melakukan apa-apa - under / overflow terjadi begitu saja.

"-1" yang merupakan hasil perhitungan yang meluap tidak berbeda dengan "-1" yang dihasilkan dari informasi lainnya. Jadi, Anda tidak dapat memberi tahu melalui beberapa status atau hanya dengan memeriksa nilai apakah itu meluap.

Tetapi Anda bisa pintar tentang perhitungan Anda untuk menghindari luapan, jika itu penting, atau setidaknya tahu kapan itu akan terjadi. Apa situasimu


Ini sebenarnya bukan situasi, hanya sesuatu yang membuat saya penasaran dan membuat saya berpikir. Jika Anda memerlukan contoh use-case, ini salah satunya: Saya punya kelas dengan variabel internal sendiri yang disebut 'detik'. Saya punya dua metode yang mengambil integer sebagai parameter dan akan menambah atau mengurangi (masing-masing) 'detik' sebanyak itu. Bagaimana Anda menguji unit apakah terjadi underflow / overflow dan bagaimana Anda mencegahnya terjadi?
KushalP

1
static final int safeAdd(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left > Integer.MAX_VALUE - right
                : left < Integer.MIN_VALUE - right) {
    throw new ArithmeticException("Integer overflow");
  }
  return left + right;
}

static final int safeSubtract(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left < Integer.MIN_VALUE + right
                : left > Integer.MAX_VALUE + right) {
    throw new ArithmeticException("Integer overflow");
  }
  return left - right;
}

static final int safeMultiply(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left > Integer.MAX_VALUE/right
                  || left < Integer.MIN_VALUE/right
                : (right < -1 ? left > Integer.MIN_VALUE/right
                                || left < Integer.MAX_VALUE/right
                              : right == -1
                                && left == Integer.MIN_VALUE) ) {
    throw new ArithmeticException("Integer overflow");
  }
  return left * right;
}

static final int safeDivide(int left, int right)
                 throws ArithmeticException {
  if ((left == Integer.MIN_VALUE) && (right == -1)) {
    throw new ArithmeticException("Integer overflow");
  }
  return left / right;
}

static final int safeNegate(int a) throws ArithmeticException {
  if (a == Integer.MIN_VALUE) {
    throw new ArithmeticException("Integer overflow");
  }
  return -a;
}
static final int safeAbs(int a) throws ArithmeticException {
  if (a == Integer.MIN_VALUE) {
    throw new ArithmeticException("Integer overflow");
  }
  return Math.abs(a);
}

2
Ini menangani pengujian. Meskipun tidak menjelaskan bagaimana Java menangani integer underflow dan overflows (tambahkan beberapa teks untuk menjelaskan).
Spencer Wieczorek

1

Saya pikir ini harus baik-baik saja.

static boolean addWillOverFlow(int a, int b) {
    return (Integer.signum(a) == Integer.signum(b)) && 
            (Integer.signum(a) != Integer.signum(a+b)); 
}

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.