Java tamsayı taşma ve taşmalarını nasıl işler ve nasıl kontrol edersiniz?


226

Java tamsayı taşmalarını ve taşmalarını nasıl işler?

Bundan yola çıkarak, bunun olup olmadığını nasıl kontrol edersiniz / test edersiniz?


28
C # ' da olduğu gibi Java'nın CPU'nun taşma bayrağına dolaylı erişim sağlamaması çok kötü .
Drew Noakes

@DrewNoakes Ve C # 'ın checkedbildiğim kadarıyla varsayılan olmaması çok kötü . Çok fazla kullanıldığını görmüyorum ve yazmak checked { code; }bir yöntemi çağırmak kadar çok iş.
Maarten Bodewes

2
@MaartenBodewes, bir derlemenin derlenmesi sırasında varsayılan olarak ayarlayabilirsiniz. csc /checked ...veya özelliği, Visual Studio'daki projenin özellikler bölmesinde ayarlayın.
Drew Noakes

@DrewNoakes Tamam, ilginç. Gerçi kod dışında bir ayar olsa biraz garip. Genel olarak, bu ayarlardan bağımsız olarak bir programın aynı davranışına sahip olmak istiyorum (muhtemelen iddialar hariç).
Maarten Bodewes

@MaartenBodewes, bence akıl yürütme, kontrol etmek için önemsiz olmayan bir genel yük var. Belki de hata ayıklama derlemelerinde etkinleştirebilir, daha sonra diğer birçok iddia gibi, sürüm derlemelerinde devre dışı bırakabilirsiniz.
Drew Noakes

Yanıtlar:


217

Taşarsa, minimum değere geri döner ve oradan devam eder. Taşarsa, maksimum değere geri döner ve oradan devam eder.

Bunu önceden aşağıdaki gibi kontrol edebilirsiniz:

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;
    }
}

(Eğer yerini alabilir inttarafından longaynı denetimleri gerçekleştirmek için long)

Bunun daha sık meydana gelebileceğini düşünüyorsanız, daha büyük değerleri (ör. longVeya belki) depolayabilen bir veri türü veya nesne kullanmayı düşünün java.math.BigInteger. Sonuncusu taşmıyor, pratik olarak, mevcut JVM belleği sınırdır.


Zaten Java8'de bulunuyorsanız , taşmaya neden olacak yeni Math#addExact()ve Math#subtractExact()yöntemleri kullanabilirsiniz ArithmeticException.

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;
    }
}

Kaynak kodu sırasıyla burada ve burada bulunabilir .

Tabii ki, bunları bir booleanyardımcı yöntemde gizlemek yerine hemen kullanabilirsiniz .


13
@dhblah, Diyelim ki Java bir int için izin verilen maksimum ve minimum değerler +100, -100. Bir Java tamsayısına bir tane ekliyorsanız, işlem taşmış gibi görünecektir. 98, 99, 100, -100, -99, -98, .... Bu daha mantıklı mı?
Austin A

6
Kodu hemen kullanmak yerine yardımcı yöntemleri kullanmanızı öneririm. Yardımcı yöntemler içseldir ve makineye özel kod ile değiştirilecektir. Hızlı bir test Math.addExact'ın kopyalanan bir yöntemden (Java 1.8.0_40)% 30 daha hızlı olduğunu gösterdi.
TilmannZ

1
@ErikE Math#addExactjavadocs yazarken normalde kullanılan sözdizimi - normalde dönüştürülebilir ediyorum iken Math.addExact, bazen başka bir biçimde öylece yapışır
Pokechu22

1
If it underflows, it goes back to the maximum value and continues from there.- düşük akışı olumsuz taşma ile karıştırmış gibi görünüyorsunuz. tamsayılarda alt akış her zaman olur (sonuç bir kesir olduğunda).
nefli

1
en.wikipedia.org/wiki/Arithmetic_underflow , Underflow'un bir bilgisayar programında, bir hesaplama sonucunun, bilgisayarın CPU'sundaki bellekte gösterebileceğinden daha küçük bir mutlak değer olduğu bir durum olduğunu söylüyor. Dolayısıyla underflow Java Tamsayıları için geçerli değildir. @BalusC
Jingguo Yao

66

İlkel tamsayı türleri gittikçe, Java Aşırı / Düşük Akışı hiç ele almaz (şamandıra ve çift davranış için farklıdır, tıpkı IEEE-754'ün zorunlu kıldığı gibi +/- sonsuza kadar akar).

İki int eklerken, taşma meydana geldiğinde hiçbir belirti almazsınız. Taşmayı kontrol etmenin basit bir yöntemi, işlemi gerçekten gerçekleştirmek için bir sonraki daha büyük türü kullanmak ve sonucun kaynak türü için hala aralıkta olup olmadığını kontrol etmektir:

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;
}

Atma maddeleri yerine ne yapacağınız, uygulama gereksinimlerinize bağlıdır (atış, min. / Maks. Veya sadece ne olursa olsun kayıt yapın). Uzun işlemlerde taşmayı tespit etmek istiyorsanız, ilkellerle şansınız kalmaz, bunun yerine BigInteger kullanın.


Edit (2014-05-21): Bu soru oldukça sık atıfta göründüğü ve aynı sorunu kendim çözmek zorunda olduğum için, bir CPU'nun V bayrağını hesaplayacağı yöntemle taşma durumunu değerlendirmek oldukça kolaydır.

Temel olarak, her iki işlenenin de sonucunu içeren bir boole ifadesi:

/**
 * 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;
}

Java'da ifadeyi (if içinde) 32 bitin tamamına uygulamak daha basittir ve sonucu <0 kullanarak kontrol edin (bu, işaret bitini etkili bir şekilde test edecektir). İlke, tüm tamsayı ilkel tipler için aynı şekilde çalışır , yukarıdaki yöntemdeki tüm bildirimleri uzun süre değiştirir.

Daha küçük türler için, int'e dolaylı dönüştürme nedeniyle (ayrıntılar için bitsel işlemler için JLS'ye bakın), <0 kontrol etmek yerine, kontrolün işaret bitini açıkça maskelemesi gerekir (kısa işlenenler için 0x8000, bayt işlenenleri için 0x80, dökümleri ayarlayın) ve parametre bildirimi uygun şekilde):

/**
 * 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;
}

(Not Yukarıdaki örnek için ekspresyon ihtiyaç kullandığı çıkarma taşma tespiti)


Peki bu boole ifadeleri nasıl / neden çalışır? İlk olarak, bazı mantıksal düşünme taşmanın ancak her iki argümanın da işaretleri aynı olduğunda meydana gelebileceğini ortaya çıkarır . Bir bağımsız değişken (eklenti) negatif ve bir pozitif sonuç durumunda, çünkü gereken sıfıra çok yakın olması ya da en uç durumda bir bağımsız değişken sıfır, diğer değişken ile aynıdır. Kendileri tarafından argümanlar yana olamaz taşma durumu oluşturmak, bunların toplamı ya bir taşma oluşturamazsınız.

Her iki argümanın da aynı işareti varsa ne olur? Her ikisinin de pozitif olduğuna bir bakalım: MAX_VALUE türünden daha büyük bir toplam oluşturan iki argüman eklemek her zaman negatif bir değer verir, bu nedenle arg1 + arg2> MAX_VALUE ise taşma oluşur . Şimdi sonuçlanabilecek maksimum değer MAX_VALUE + MAX_VALUE olacaktır (aşırı durumda her iki bağımsız değişken de MAX_VALUE). 127 + 127 = 254 anlamına gelen bir bayt için (örnek). İki pozitif değer eklemekten kaynaklanabilecek tüm değerlerin bit temsillerine bakıldığında, taşan (128-254) değerlerin hepsinin bit 7 ayarlı olduğu görülür. taşmayan tüm öğelerin (0 ila 127) bit 7'si (en üstte, işareti) temizlenir. İfadenin ilk (sağ) kısmı tam olarak neyi kontrol eder:

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

(~ s & ~ d & r), yalnızca , her iki işlenen de (s, d) pozitif ve sonuç (r) negatifse (ifade 32 bitin tamamında çalışırsa, ancak ilgilendiğimiz tek bit ise doğru olur) <0) ile kontrol edilen en üstteki (işaret) bittir.

Şimdi her iki argüman da negatifse, toplamları hiçbir zaman sıfırdan bağımsız değişkenlerden daha yakın olamaz , toplam eksi sonsuzluğa daha yakın olmalıdır . Üretebileceğimiz en uç değer MIN_VALUE + MIN_VALUE'dur (yine bayt örneği için) herhangi bir aralık değeri (-1 ila -128) için işaret bitinin ayarlanmış olduğunu gösterirken olası herhangi bir taşma değeri (-129 ila -256) ) işaret biti temizlendi. Böylece sonucun işareti tekrar taşma durumunu gösterir. Bu, sol yarının (s & d & r) her iki argümanın da (s, d) negatif ve pozitif bir sonuç olduğu durumu kontrol eder. Mantık büyük ölçüde pozitif duruma eşittir; iki negatif değer eklenmesinden kaynaklanabilecek tüm bit desenleri, yalnızca ve bir yetersizlik meydana geldiğinde işaret bitinin silinmesine neden olur .


1
Bitsel operatörlerle de kontrol edebilirsiniz. Betterlogic.com/roger/2011/05/…
rogerdpack

1
Bu işe yarayacak, ancak kötü bir performans isabeti olacağını varsayıyorum.
chessofnerd

33

Varsayılan olarak, Java'nın int ve uzun matematiği taşma ve taşma üzerine sessizce sarılır. (Diğer tamsayı tiplerindeki tamsayı işlemleri, ilk önce işlenenlerin int veya uzun olarak JLS 4.2.2'ye yükseltilmesiyle gerçekleştirilir .)

Java 8 itibarıyla java.lang.Mathsağlar addExact, subtractExact, multiplyExact, incrementExact, decrementExactve negateExactint ve taşma üzerinde ArithmeticException atma, adlandırılmış işlemi gerçekleştirmek uzun argümanlar her ikisi için statik yöntemleri. (DivideExact yöntemi yoktur - özel bir vakayı ( MIN_VALUE / -1) kendiniz kontrol etmeniz gerekir .)

Java 8'den itibaren java.lang.Math toIntExact, bir int'e uzun bir süre atmayı sağlar ve long'un değeri bir int'e uymuyorsa ArithmeticException özel durumunu atar. Bu, örneğin denetlenmeyen uzun matematik kullanarak ints toplamını hesaplamak, daha sonra toIntExactsonunda int'e dökmek için kullanmak yararlı olabilir (ancak toplamınızın taşmasına izin vermemeye dikkat edin).

Hala Java'nın eski bir sürümünü kullanıyorsanız, Google Guava, kontrol edilen toplama, çıkarma, çarpma ve üs alma (taşmaya atma) için IntMath ve LongMath statik yöntemleri sağlar. Bu sınıflar ayrıca MAX_VALUEtaşma ile geri dönüşen faktöriyelleri ve binom katsayılarını hesaplamak için yöntemler sağlar (ki bu daha az kontrol edilir). Guava ilkel yardımcı sınıfları SignedBytes, UnsignedBytes, Shortsve Intstemin checkedCastbüyük türleri altında (/ taşma hakkında IllegalArgumentException atma daralma için yöntemler olup ArithmeticException), hem de saturatingCastyöntemler bu dönüş MIN_VALUEveya MAX_VALUEtaşma.


32

Java, int veya uzun ilkel türler için tamsayı taşması ile hiçbir şey yapmaz ve pozitif ve negatif tamsayılarla taşmayı yok sayar.

Bu cevap ilk önce tamsayı taşmasını açıklar, ifade değerlendirmesindeki ara değerlerle bile bunun nasıl olabileceğine bir örnek verir ve daha sonra tamsayı taşmasını önlemek ve tespit etmek için ayrıntılı teknikler veren kaynaklara bağlantılar verir.

Tamsayı aritmetiği ve beklenmedik veya algılanmayan taşma ile sonuçlanan ifadeler yaygın bir programlama hatasıdır. Beklenmeyen veya algılanmayan tamsayı taşması, özellikle dizi, yığın ve liste nesnelerini etkilediğinden, iyi bilinen bir kullanılabilir güvenlik sorunudur.

Taşma, pozitif veya negatif değerin söz konusu ilkel tip için maksimum veya minimum değerlerin üzerinde olacağı bir pozitif veya negatif yönde meydana gelebilir. Taşma, ifade veya işlem değerlendirmesi sırasında bir ara değerde meydana gelebilir ve nihai değerin aralık içinde olması beklenen bir ifade veya işlemin sonucunu etkileyebilir.

Bazen negatif taşmaya yanlışlıkla taşma denir. Düşük değer, bir değerin, gösterimin izin verdiğinden sıfıra yakın olması durumunda gerçekleşir. Yetersiz akış tamsayı aritmetiğinde gerçekleşir ve beklenir. Tamsayı yetersizliği, bir tamsayı değerlendirmesi -1 ile 0 veya 0 ile 1 arasında olduğunda gerçekleşir. Kesirli sonuç 0'a düşer. Bu normaldir ve tamsayı aritmetiği ile beklenir ve hata olarak kabul edilmez. Ancak, kodun bir istisna atmasına neden olabilir. Tamsayı taşması sonucu bir ifadede bölen olarak kullanılıyorsa, bir örnek "ArithmeticException: / sıfıra" istisnasıdır.

Aşağıdaki kodu göz önünde bulundurun:

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

bu da x'in 0'a atanmasıyla sonuçlanır ve daha sonra bigValue / x değerinin değerlendirilmesi, y değerine 2 atanması yerine "ArithmeticException: / sıfıra" (yani sıfıra böl) bir istisna atar.

X için beklenen sonuç 858.993.458 olur ve bu da maksimum int değeri 2.147.483.647'den düşüktür. Ancak, Integer.MAX_Value * 2 değerlendirilmesinden elde edilen ara sonuç, maksimum int değerini aşan ve 2s tamamlayıcı tamsayı gösterimine uygun olarak -2 olan 4.294.967.294 olacaktır. Sonraki -2 / 5 değerlendirmesi, x'e atanan 0 olarak değerlendirilir.

X hesaplaması için ifadeyi, değerlendirildiğinde, çarpmadan önce bölen bir ifadeye yeniden düzenleme:

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

sonuç olarak x'in 858.993.458 ve y değerinin 2 atanması beklenir.

BigValue / 5'ten elde edilen ara sonuç 429.496.729'dur ve bu bir int için maksimum değeri aşmaz. 429.496.729 * 2'lik müteakip değerlendirme, bir int için maksimum değeri aşmaz ve beklenen sonuç x'e atanır. Bu durumda y için değerlendirme sıfıra bölünmez. X ve y için değerlendirmeler beklendiği gibi çalışır.

Java tamsayı değerleri 2s tamamlayıcı imzalı tamsayı gösterimine göre saklanır ve davranır. Ortaya çıkan bir değer, maksimum veya minimum tamsayı değerlerinden daha büyük veya daha küçük olduğunda, bunun yerine 2'nin tamamlayıcı tamsayı değeri ortaya çıkar. En sıradan tamsayı aritmetik durumları olan 2s tamamlayıcı davranışını kullanmak için açıkça tasarlanmayan durumlarda, ortaya çıkan 2s tamamlayıcı değeri, yukarıdaki örnekte gösterildiği gibi bir programlama mantığına veya hesaplama hatasına neden olacaktır. Mükemmel bir Wikipedia makalesi, burada 2'nin tamamlayıcı ikili tamsayılarını açıklıyor: Two'nun tamamlayıcısı - Wikipedia

İstenmeyen tamsayı taşmasını önlemek için teknikler vardır. Teknikler, ön koşul testi, sürüm yükseltme ve BigInteger kullanılarak kategorize edilebilir.

Ön koşul testi, aritmetik bir işleme veya ifadeye giren değerlerin, bu değerlerle taşma olmamasını sağlamak için incelenmesini içerir. Programlama ve tasarım, giriş değerlerinin taşmaya neden olmayacağını garanti eden testler yaratmalı ve ardından taşmaya neden olacak giriş değerleri meydana gelirse ne yapılacağını belirlemelidir.

Upcasting, aritmetik işlemi veya ifadeyi gerçekleştirmek için daha büyük bir ilkel tipin kullanılmasını ve daha sonra elde edilen değerin bir tamsayı için maksimum veya minimum değerlerin ötesinde olup olmadığının belirlenmesini içerir. Upcasting ile bile, bir işlem veya ifadedeki değerin veya bazı ara değerin, upcast tipi için maksimum veya minimum değerlerin ötesinde olması ve taşmaya neden olması, bu da algılanmayacak ve beklenmeyen ve istenmeyen sonuçlara neden olacaktır. Analiz veya ön koşullar aracılığıyla, üst sürüm olmadan önleme mümkün veya pratik olmadığında, üst sürüm ile taşmayı önlemek mümkün olabilir. Söz konusu tamsayılar zaten uzun ilkel tipler ise, Java'daki ilkel tiplerle yayın yapmak mümkün değildir.

BigInteger tekniği, BigInteger kullanan kütüphane yöntemlerini kullanarak aritmetik işlem veya ifade için BigInteger'in kullanılmasını içerir. BigInteger taşmıyor. Gerekirse kullanılabilir tüm belleği kullanacaktır. Aritmetik yöntemleri normalde tamsayı işlemlerinden biraz daha az verimlidir. BigInteger kullanan bir sonucun bir tamsayı için maksimum veya minimum değerlerin ötesinde olması mümkündür, ancak sonuca götüren aritmetikte taşma meydana gelmez. Bir BigInteger sonucu istenen ilkel sonuç türü için örneğin int veya long için maksimum veya minimum değerlerin üzerindeyse, programlama ve tasarımın ne yapılacağını belirlemesi gerekecektir.

Carnegie Mellon Yazılım Mühendisliği Enstitüsü'nün CERT programı ve Oracle, güvenli Java programlama için bir dizi standart oluşturdu. Standartlara, tamsayı taşmasını önleme ve tespit etme teknikleri dahildir. Standart, burada kolayca erişilebilen bir çevrimiçi kaynak olarak yayınlanmıştır: Java için CERT Oracle Güvenli Kodlama Standardı

Tamsayı taşmasını önlemek veya tespit etmek için kodlama tekniklerinin pratik örneklerini tanımlayan ve içeren standardın bölümü burada: NUM00-J. Tamsayı taşmasını algılama veya önleme

Java için CERT Oracle Güvenli Kodlama Standardı'nın kitap formu ve PDF formu da mevcuttur.


Açıkça Yetersizlik ne devletler olarak bu en iyi cevabı burada (kabul cevabı yok) ve ayrıca / Yetersizlik taşma baş etme teknikleri listeler
naif

12

Biraz önce bu problemle karşılaştım, işte benim çözümüm (hem çarpma hem de toplama için):

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;
}

yanlışsa veya basitleştirilebilirse düzeltmekten çekinmeyin. Çoğaltma yöntemi ile bazı testler yaptım, çoğunlukla kenar durumlarda, ancak yine de yanlış olabilir.


Bölme, çarpmaya göre yavaş olmaya eğilimlidir. Çünkü int*int, sadece longsonuca uyup uymadığını görmek ve sonucun uygun olup olmadığını görmek inten hızlı yaklaşım olacaktır. Kişi long*long, işlenenleri pozitif olarak normalleştirirse, her birini üst ve alt 32 bit yarıya bölebilir, her bir yarıyı uzunluğa yükseltebilir (işaret uzantılarına dikkat edin!) Ve sonra iki kısmi ürünü hesaplayabilirsiniz [üst yarılardan biri sıfır olun].
supercat

"Uzun * uzun süre, eğer işlenenlerin pozitif olmasını normalleştirir ..." derseniz, Long.MIN_VALUE'yu normalleştirmeye nasıl devam edersiniz?
fragorl

Hesaplamayı gerçekleştirmeden önce bir şeyin taşma olup olmadığını test etmek gerekirse bu yöntemler ilginç olabilir . Örneğin, bu tür hesaplamalar için kullanılan kullanıcı girdisini test etmek iyi olabilir, gerçekleştiğinde istisnayı yakalamak.
Maarten Bodewes

8

Tamsayı taşması / taşmasını kontrol eden güvenli aritmetik işlemler sağlayan kütüphaneler vardır. Örneğin, Guava en IntMath.checkedAdd (a, int b int) toplamını döndürür ave b, değil taşma yapar ve atar sağlanan ArithmeticExceptioneğer a + biçinde taşmaları imzalı intaritmetik.


Evet, Java 8 veya üstü değilseniz, bu durumda Mathsınıf benzer kod içeriyorsa , bu iyi bir fikirdir .
Maarten Bodewes

6

Etrafı sarar.

Örneğin:

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);
    }
}

baskılar

-2147483648
2147483647

İyi! Ve şimdi, karmaşık hesaplamaya nasıl tespit edeceğinizi cevaplayabilir misiniz?
Aubin

5

Bence böyle bir şey kullanmalısın ve buna Upcasting deniyor:

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;
}

Daha fazla bilgiyi buradan okuyabilirsiniz: Tamsayı taşmasını tespit etme veya önleme

Oldukça güvenilir bir kaynaktır.


3

Hiçbir şey yapmaz - düşük / taşma gerçekleşir.

Taşan bir hesaplamanın sonucu olan "-1", diğer bilgilerden kaynaklanan "-1" den farklı değildir. Dolayısıyla, bir durum üzerinden ya da taşmış olup olmadığını sadece bir değeri inceleyerek söyleyemezsiniz.

Ancak, taşması önlemek, eğer önemliyse, ya da en azından ne zaman olacağını bilmek için hesaplamalarınız hakkında akıllı olabilirsiniz. Durumun nedir?


Bu gerçekten bir durum değil, sadece merak ettiğim ve beni düşündüren bir şey. Örnek bir use-case'e ihtiyacınız varsa, burada bir tane var: Kendi iç değişkenine sahip bir sınıf var 'saniye'. Bir tamsayı parametre olarak almak ve (sırasıyla) 'saniye' kadar artacak veya azalan iki yöntem var. Bir taşma / taşmanın meydana geldiğini nasıl test edersiniz ve bunun meydana gelmesini nasıl önlersiniz?
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
Bu testle ilgilenir. Her ne kadar Java'nın tamsayı taşmalarını ve taşmalarını nasıl işlediğini açıklamasa da (açıklamak için bir metin ekleyin).
Spencer Wieczorek

1

Bence bu iyi olmalı.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.