İçindekiler:
Video: Coding Minecraft in One Week - C++/OpenGL Programming Challenge 2024
İster inanın ister inanmayın, bilgisayarlar - hatta en güçlü olanlar - matematik hesaplamaları yaparken belirli sınırlamalara sahiptir. Bu kısıtlamalar genellikle önemsizdir, ancak bazen gizlice sizi ısırırlar. İşte Java'da matematik yaparken dikkat etmeniz gereken şeyler.
Tamsayı taşması
Tamsayı türleriyle ilgili temel sorun, sabit bir boyuta sahip olmalarıdır. Sonuç olarak,
kısa
,
int
veya
uzun
türündeki değişkenlerde saklanabilecek boyutların sınırı vardır.
uzun
değişkenleri büyük sayılara sahip olsalar da, er ya da geç, bir
uzun
değişkene bile sığmayacak kadar büyük bir sayı bulursunuz.
Tamam, şunu düşünün: (
int a = 1000000000;
Sistem. dışarı. println (a);
a + = 1000000000;
Sistem. dışarı. println (a);
a + = 1000000000;
Sistem. dışarı. println (a);
a + = 1000000000;
Sistem. dışarı. println (a);
Burada, her bir eklemeden sonra
a
değerinin daha büyük olmasını bekliyorsunuz. Ancak şu görüntülenen çıktı var:
1000000000
2000000000
-1294967296
-294967296
İlk ekleme işe yarıyor gibi gözüküyor, ancak bundan sonra sayı negatif oluyor! Bunun nedeni, değerin
int
veri türünün boyut sınırına ulaşmış olmasıdır. Maalesef, Java bu hatanın olduğunu söylemiyor.
int
değişkenini mümkün olduğunca bit dolu olarak sıkıştırır, sığmayan bitleri atar ve fark etmemenizi umar.
int
yolunun negatif değerlerini saklama biçiminden dolayı, büyük pozitif değerler aniden büyük negatif değerler haline gelir.
Hikayenin ahlakı, büyük tam sayılarla çalışıyorsanız,
uzun
yerine
int
kullanmanız gerekir; çünkü
uzun
,
int
'tan daha büyük sayıları saklayabilir. Programlarınız
uzun
için bir problem olacak kadar büyük sayılarla ilgiliyse, bunun yerine kayan noktalı türler kullanmayı düşünün. Kayan nokta türleri,
uzun
değerinden daha büyük değerleri işleyebilir ve kapasitesini aştığınızda size bildirirler.
Kayan noktalı gariplik
Kayan noktalı sayıların kendi problemleri var. Yeni başlayanlar için, kayan nokta sayıları ikili sayı sistemi (taban 2) kullanılarak saklanır, ancak insanlar ondalık sayı sisteminde (taban 10) sayılarla çalışır. Ne yazık ki, bu iki sistem arasındaki sayıyı doğru bir şekilde dönüştürmek bazen imkansız. Bunun nedeni, herhangi bir sayı tabanında belirli kesirlerin tam olarak temsil edilememesi.
Bir örnek: Taban 10'un 1/3 oranını tam olarak göstermesinin bir yolu yoktur. Yaklaşık olarak 0 3333333 olarak değerlendirebilirsiniz, ancak nihayetinde saklayabileceğiniz kaç basamağın sınırına erişeceğinizden durdurmanız gerekir. 2. tabanda, tam olarak temsil edemediğiniz kesirlerden birinin ondalık değeri 1/10'dur. Başka bir deyişle, bir
float
veya
double
değişkeni doğru olarak
0'ı temsil edemez. 1
.
Bu kodu çalıştırmayı deneyin:
float x = 0.f;
NumberFormat nf = NumberFormat. getNumberInstance ();
nf. setMinimumFractionDigits (10);
Sistem. dışarı. println (nf. format (x));
Ortaya çıkan çıktı şudur:
0. 1000000015
0 rağmen. 1000000015
yakın 'den
0'dır. 1
, bu tam değil.
Çoğu durumda, Java'nın kayan nokta matematiğinin önemi yoktur. Hata marjı son derece düşüktür. Evinizin boyutunu ölçmek için Java kullanıyorsanız, hatayı fark etmek için elektron mikroskobuna ihtiyaç duyarsınız. Bununla birlikte, finansal işlemlerle uğraşan uygulamaları yazıyorsanız, normal yuvarlama, hataları anlamlı hale getirmek için bazen büyütebilir. Bir kuruşa fazla veya çok az bir satış vergisi tahsil edebilirsiniz. Aşırı durumlarda, faturalarınızın açık ek hataları olabilir.
Tamsayı türleri tabii ki ikili olarak saklanır. Ancak, tamsayılar kayan nokta türleriyle aynı hatalara tabi değildir - tamsayılar kesirleri hiç göstermemektedir - bu nedenle
tamsayı
türleri için bu tür hata konusunda endişelenmenize gerek yoktur.
Sıfıra göre bölme
Matematiğin temel kurallarına göre, bir sayıyı sıfırlayamazsınız. Bunun nedeni basittir: Division, çarpmanın tersidir - yani
a * b = c
ise,
a = c / b
olduğu da doğrudur. Eğer
b
'un sıfır olmasına izin verirseniz, bölme anlamsız olur, çünkü herhangi bir sayı sıfır olduğunda sıfır olur. Bu nedenle
a
ve
c
da sıfır olmalı. Kısaca, matematikçiler yüzyıllar önce bu ikilemi, sıfıra bölünmeye izin verilmemekle çözdüler.
Öyleyse bir Java programında bir sayıyı sıfıra bölmeyi denerseniz ne olur? Cevap, tamsayıları mı yoksa kayan nokta sayılarını mı böldüğünüze bağlıdır. Sayıları bölme girişiminde bulunduğunuz deyim, bölme işlemini sıfıra deneyen deyim, programı çökertmenin kaba bir yolu olan bir istisna, çağrılmasını önler.
Burada bulamadığınız programınızın devam etmesine izin vermek için bu istisnayı önlemenin bir yolu var. Bu arada, yazdığınız herhangi bir program sıfırdan bir tamsayı bölmesi çöker.
Bir kayan nokta türü sıfıra bölmeye çalışırsanız, sonuçlar o kadar ani değildir. Bunun yerine, Java, kayan nokta sonucuna aşağıdaki tabloda listelenen özel değerlerden birini atar. Aşağıdaki paragraflar, bu özel değerlerin nasıl belirlendiğini açıklamaktadır:
- Bir sayıyı sıfıra bölüyorsanız ve her iki sayının işareti aynı ise sonuç pozitif sonsuzluktur.
0. 0
bölü 0. 0pozitif sonsuzluktur,
-34 olduğu gibi. 0bölü by
-0. 0.
Bir sayıyı sıfıra bölüyorsanız ve sayıların işaretleri farklıysa sonuç negatif sonsuzluktur. - -40. 0
bölü 0.
34 olduğu gibi 0negatif sonsuzdur. 0
bölü 0. 0.
Sıfırları sıfıra bölerseniz, sonuç işaretlerden bağımsız olarak bir sayı (NaN) değildir.Şamandıranın ve çift sınıfın özel sabitleri
Sabit - Anlamı
Pozitif sonsuzluk | NEGATİF_INFINITY |
Negatif sonsuzluk
|
NaN |
Değil sayı
|
Değişken nokta sıfırları pozitif veya negatif olabilir. Java, pozitif ve negatif sıfırların sayısal olarak eşit olduğunu düşünür. |
Bu özel değerlerden birine sahip bir kayan nokta değeri yazdırmaya çalışırsanız, Java değeri uygun bir dizeye dönüştürür. Aşağıdaki ifadeleri uyguladığınızı varsayalım:
|
double x = Math. sqrt (-50); // Bir sayı değil |
çift y = x;
if (x == y)
Sistemi. dışarı. println ("x eşittir y");
Ortaya çıkan konsol çıktısı
Sonsuzluk
i
-50 ise. 0
, konsol
-Infinity
görüntüler ve
i
sıfırsa, konsol
NaN
görüntüler.
Aşağıdaki paragraflar biraz garip olguyu tanımlamaktadır:
NaN
kendine eşit değildir, bu da bazı garip sonuçlar doğurabilir. Örneğin:
çift x = Matematik. sqrt (-50); // Bir sayı değil
-
çift y = x;
if (x == y)
Sistemi. dışarı. println ("x eşittir y");
if
ifadesinin
x
değişkeninin
y
değişkenine eşit olup olmadığını test etmek için, tartışmayı yapmak için varsayıyorum. Bu test,
x
değerini
y
değerine atayan bir atama ifadesinin hemen sonrasında olduğundan güvenle,
x
değerinin
y
sağ?
Yanlış. Çünkü
x
NaN
,
y
da
NaN
'dır.
NaN
başka bir
NaN
da dahil olmak üzere herhangi bir değere eşit kabul edilmez. Böylece,
if
ifadesinde yapılan karşılaştırma başarısız olur.
Başka garip bir sonuç: Kendinden eksilen bir sayının daima sıfır olduğunu varsayamazsınız. Bu ifadeyi düşünün:
double z = x - x; // mutlaka sıfır olmalı
Bu deyim her zaman
- z
değerini sıfırlamamalı mıyım? Değil
x
NaN
ise. Bu durumda, sayıyı eksi olmayan bir sayı henüz bir sayı değildir.
Bir daha gariplik: Sonsuza kadar olan herhangi bir matematiksel işlem, başka bir sonsuzluk veya
NaN
ile sonuçlanır. Örneğin, Infinity + 5, sonsuza eşittir, bu nedenle Buzz Lightyear'ın "Sonsuzluğa ve ötesine! "Sadece gerçekleşmeyecek. Fakat sonsuzluk eksi sonsuzluk size …
- NaN
verir.