MERHABA! Bugünkü dersimizde büyük sayılardan bahsedeceğiz. Hayır, GERÇEKTEN BÜYÜK demek istiyorum. İlkel veri türleri için değer aralıkları tablosuyla daha önce defalarca karşılaştık . Şuna benziyor:
ilkel tip Bellekteki boyut Değer aralığı
bayt 8 bit -128 ila 127
kısa 16bit -32768 ila 32767
karakter 16bit 0 ila 65536
int 32 bit -2147483648 ila 2147483647
uzun 64bit -9223372036854775808 ila 9223372036854775807
batmadan yüzmek 32 bit (2 üzeri -149) ila ((2 üzeri -23) * 2 üzeri 127)
çift 64bit (-2 üzeri 63) ila ((2 üzeri 63) - 1)
mantıksal 8 (dizilerde kullanıldığında), 32 (dizilerde kullanılmadığında) doğru ya da yanlış
En geniş tamsayı veri tipi long . Kayan noktalı sayılar söz konusu olduğunda, bu double . Peki ya ihtiyacımız olan sayı uzun bir sayıya bile sığmayacak kadar büyükse ? Uzun veri türü, oldukça geniş bir olası değerler aralığına sahiptir, ancak yine de 64 bit ile sınırlıdır. Çok Büyük Sayımız 100 bit gerektiriyorsa ne bulmamız gerekiyor? Neyse ki, hiçbir şey icat etmemize gerek yok. Bunun gibi durumlar için Java'nın iki özel sınıfı vardır: BigInteger (tamsayılar için) ve BigDecimal(kayan noktalı sayılar için). Onları özel yapan nedir? Her şeyden önce, teoride maksimum boyutları yoktur. "Teoride" diyoruz çünkü sonsuz belleğe sahip bilgisayar yoktur. Ve eğer programınız kullanılabilir bellek miktarından daha büyük bir sayı oluşturursa, o zaman program elbette çalışmayacaktır. Ancak bu tür durumlar olası değildir. Sonuç olarak BigInteger ve BigDecimal'in neredeyse sınırsız büyüklükteki sayıları temsil edebildiğini söyleyebiliriz . Bu sınıflar ne için kullanılıyor? Her şeyden önce, son derece katı doğruluk gereksinimleri olan hesaplamalar için. Örneğin, insan yaşamı bazı programlardaki (örneğin uçakları, roketleri veya tıbbi ekipmanı kontrol eden yazılımlar) hesaplamaların doğruluğuna bağlı olabilir. Dolayısıyla, 150. ondalık basamak önemliyse BigDecimalen iyi seçimdir. Ek olarak, bu sınıftaki nesneler, en küçük değerlerin bile doğru hesaplanmasının da son derece önemli olduğu finans dünyasında sıklıkla kullanılır. BigInteger ve BigDecimal nesneleri ile nasıl çalışıyorsunuz ve onlar hakkında bilgi sahibi olmanız gerekiyor mu? Bu sınıfların nesneleri şu şekilde oluşturulur:

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
Yapıcıya bir dize iletmek olası seçeneklerden yalnızca biridir. Burada dizeleri kullanıyoruz, çünkü sayılarımız long ve double için maksimum değerleri aşıyor ve derleyiciye hangi sayıyı oluşturmak istediğimizi açıklamanın bir yolunu bulmamız gerekiyor :) Basitçe sayıyı geçmek 111111111111111111111111111111111111111111111111111111111111111111 yapıcıya çalışmaz: Java, iletilen sayıyı ilkel veri türlerinden birine sıkıştırmaya çalışır, ancak bunların hiçbirine sığmaz. Bu nedenle, istenen sayıyı geçmek için bir dize kullanmak iyi bir seçenektir. Her iki sınıf da, iletilen dizelerden sayısal değerleri otomatik olarak çıkarabilir. Büyük sayılı sınıflarla çalışırken hatırlanması gereken bir diğer önemli nokta, nesnelerinin değişmez ( Immutable ) olmasıdır . String sınıfı ve ilkel türler (Tamsayı, Uzun, vb.) için sarmalayıcı sınıfları ile ilgili deneyiminiz sayesinde değişmezliğe zaten aşinasınız .

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
Konsol çıktısı:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
Beklediğiniz gibi sayımız değişmedi. Toplama işlemini gerçekleştirmek için, işlemin sonucunu alacak yeni bir nesne oluşturmalısınız.

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
Konsol çıktısı:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Bakın, şimdi her şey olması gerektiği gibi çalışıyor :) Bu arada, toplama işleminin ne kadar sıra dışı göründüğünü fark ettiniz mi?

BigInteger result = integer.add(BigInteger.valueOf(33333333));
Bu başka bir önemli nokta. Büyük sayı sınıfları + - * / işleçlerini kullanmaz. Bunun yerine, bir dizi yöntem sağlarlar. Ana olanları tanıyalım (her zaman olduğu gibi, yöntemlerin tam bir listesini Oracle belgelerinde bulabilirsiniz: burada ve burada ).
  1. aritmetik işlemler için yöntemler: topla() , çıkar() , çoğalt() , böl() . Bu yöntemler sırasıyla toplama, çıkarma, çarpma ve bölme işlemlerini yapmak için kullanılır.

  2. doubleValue() , intValue() , floatValue() , longValue() , vb. büyük bir sayıyı Java'nın ilkel türlerinden birine dönüştürmek için kullanılır. Bu yöntemleri kullanırken dikkatli olun. Bit boyutundaki farklılıkları unutmayın!

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }
    

    Konsol çıktısı:

    
    8198552921648689607
    
  3. min() ve max() iki büyük sayının minimum ve maksimum değerini bulmanızı sağlar.
    Bu yöntemlerin statik olmadığını unutmayın!

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }
    

    Konsol çıktısı:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
    

BigDecimal yuvarlama davranışı

Büyük sayıları yuvarlamak ve yuvarlama davranışını yapılandırmak o kadar basit olmadığından, bu konunun kendi ayrı bölümü vardır. Bir BigDecimal için ondalık basamak sayısını ayarlamak üzere setScale() yöntemini kullanabilirsiniz . Örneğin, 111.5555555555 sayısının ondalık noktadan sonra üç hane olmasını istediğimizi varsayalım. Ancak 3 sayısını setScale() metoduna argüman olarak ileterek istediğimizi elde edemeyiz . Yukarıda belirtildiği gibi, BigDecimalhesaplama kesinliği konusunda katı gereksinimleri olan sayıları temsil etmek içindir. Sayımız şu anki haliyle virgülden sonra 10 hanelidir. Bunlardan 7 tanesini düşürüp sadece 3 kalsın istiyoruz. Buna göre 3 rakamına ek olarak yuvarlama moduna geçmeliyiz. BigDecimal'in toplam 8 yuvarlama modu vardır. Bu çok fazla! Ancak, hesaplamalarınızın kesinliğini gerçekten hassas bir şekilde ayarlamanız gerekiyorsa, ihtiyacınız olan her şeye sahip olacaksınız. İşte BigDecimal tarafından sunulan 8 yuvarlama modu :
  1. ROUND_CEILING — yuvarlar

    
    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
    
  2. ROUND_DOWN — sıfıra doğru yuvarlar

    
    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
    
  3. ROUND_FLOOR — aşağı yuvarlar

    
     111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555
    
    

  4. ROUND_HALF_UP — ondalık noktadan sonraki sayı >= 0,5 ise yukarı yuvarlar

    
    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
    
  5. ROUND_HALF_DOWN — ondalık noktadan sonraki sayı > 0,5 ise yukarı yuvarlar

    
    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
    
  6. ROUND_HALF_EVEN — yuvarlama, ondalık noktanın solundaki sayıya bağlıdır. Soldaki sayı çift ise yuvarlama aşağı olacaktır. Virgülün solundaki sayı tek ise yukarıya yuvarlama yapılır.

    
    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2
    

    Ondalık basamağın solundaki sayı 2'dir (çift). Sayı aşağı yuvarlanır. 0 ondalık basamak istiyoruz, yani sonuç 2.

    
    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4
    

    Ondalık noktanın solundaki sayı 3'tür (tek). Sayı yukarı yuvarlanır. 0 ondalık basamak istiyoruz, yani sonuç 4.

  7. ROUND_UNNECCESSARY — Bu mod, bir yönteme bir yuvarlama modu geçirmeniz gerektiğinde kullanılır, ancak sayının yuvarlanması gerekmez. ROUND_UNNECCESSARY modu ayarlı bir sayıyı yuvarlamaya çalışırsanız, bir ArithmeticException atılır.

    
    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
    
  8. ROUND_UP — sıfırdan uzağa yuvarlar.

    
    111.5551 -> setScale(3, ROUND_UP) -> 111.556
    

Büyük sayıları karşılaştırma

Bu da önemlidir. Java'da nesneleri karşılaştırmak için equals() yöntemini kullandığımızı hatırlayacaksınız . Uygulama ya dilin kendisi tarafından sağlanır (standart Java sınıfları için) ya da programcı tarafından geçersiz kılınır. Ancak BigDecimal nesneleri söz konusu olduğunda , karşılaştırmalar için equals() yönteminin kullanılması önerilmez. Bunun nedeni, BigDecimal.equals() yönteminin yalnızca 2 sayı aynı değere ve ölçeğe sahipse doğru döndürmesidir: Double ve BigDecimal sınıfları için equals() yönteminin davranışını karşılaştıralım :

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));
      
   }
}
Konsol çıktısı:

true 
false
Gördüğünüz gibi, BigDecimal için 1.5 ve 1.50 sayıları eşitsiz çıktı! Bunun nedeni tam olarak , equals() yönteminin BigDecimal sınıfında uygulanmasının özellikleriydi . İki BigDecimal nesnesinin daha doğru bir karşılaştırması için , CompareTo() yöntemini kullanmak daha iyidir :

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
Konsol çıktısı:

0
CompareTo () yöntemi 0 döndürdü; bu, 1,5 ve 1,50'nin eşit olduğu anlamına gelir. Ve işte beklediğimiz sonuç! :) Bu, bugünkü dersimizi sonlandırıyor. Şimdi görevlere geri dönme zamanı! :)