İşte ikili olarak neler oluyor. Bildiğimiz gibi, bazı kayan nokta değerleri tam olarak ondalık olarak gösterilse bile tam olarak ikili olarak temsil edilemez. Bu 3 sayı sadece bu gerçeğin örnekleridir.
Bu program ile her bir sayının onaltılık gösterimlerini ve her bir eklemenin sonuçlarını çıktılarım.
public class Main{
public static void main(String args[]) {
double x = 23.53; // Inexact representation
double y = 5.88; // Inexact representation
double z = 17.64; // Inexact representation
double s = 47.05; // What math tells us the sum should be; still inexact
printValueAndInHex(x);
printValueAndInHex(y);
printValueAndInHex(z);
printValueAndInHex(s);
System.out.println("--------");
double t1 = x + y;
printValueAndInHex(t1);
t1 = t1 + z;
printValueAndInHex(t1);
System.out.println("--------");
double t2 = x + z;
printValueAndInHex(t2);
t2 = t2 + y;
printValueAndInHex(t2);
}
private static void printValueAndInHex(double d)
{
System.out.println(Long.toHexString(Double.doubleToLongBits(d)) + ": " + d);
}
}
printValueAndInHex
Yöntem sadece bir onaltılık-yazıcı yardımcısıdır.
Çıktı aşağıdaki gibidir:
403787ae147ae148: 23.53
4017851eb851eb85: 5.88
4031a3d70a3d70a4: 17.64
4047866666666666: 47.05
--------
403d68f5c28f5c29: 29.41
4047866666666666: 47.05
--------
404495c28f5c28f6: 41.17
4047866666666667: 47.050000000000004
İlk 4 sayılardır x
, y
, z
ve s
'nin onaltılık gösterimleri. IEEE kayan nokta gösteriminde, 2-12 bitleri ikili üssü , yani sayının ölçeğini temsil eder. (İlk bit, işaret biti ve mantis için kalan bitlerdir .) Temsil edilen üs aslında ikili sayı eksi 1023'tür.
İlk 4 sayının üsleri çıkarılır:
sign|exponent
403 => 0|100 0000 0011| => 1027 - 1023 = 4
401 => 0|100 0000 0001| => 1025 - 1023 = 2
403 => 0|100 0000 0011| => 1027 - 1023 = 4
404 => 0|100 0000 0100| => 1028 - 1023 = 5
İlk toplama grubu
İkinci sayı ( y
) daha küçük boyuttadır. Almak için bu iki sayıyı eklerken x + y
, ikinci sayının ( 01
) son 2 biti aralık dışına kaydırılır ve hesaplamaya dahil edilmez.
İkinci bir ek ekler x + y
ve z
aynı ölçek iki sayı ekler.
İkinci toplama grubu
Burada, x + z
önce gerçekleşir. Aynı ölçeğe sahiptirler, ancak ölçeğinde daha yüksek bir sayı verir:
404 => 0|100 0000 0100| => 1028 - 1023 = 5
İkinci toplama eklenir x + z
ve y
şimdi sayılar eklemek için 3 bit çıkarılır y
( 101
). Burada, yukarı doğru bir yuvarlak olmalıdır, çünkü sonuç bir sonraki kayan nokta sayısıdır: 4047866666666666
ilk toplama grubu 4047866666666667
için, ikinci toplama seti için. Bu hata toplamın çıktısında gösterilecek kadar önemlidir.
Sonuç olarak, IEEE sayıları üzerinde matematiksel işlemler yaparken dikkatli olun. Bazı temsiller kesin değildir ve ölçekler farklı olduğunda daha da kesinleşmezler. Mümkünse benzer ölçekte numaralar ekleyin ve çıkarın.
(2.0^53 + 1) - 1 == 2.0^53 - 1 != 2^53 == 2^53 + (1 - 1)
). Bu nedenle, evet: toplamların sırasını ve diğer işlemleri seçerken dikkatli olun. Bazı diller "yüksek hassasiyetli" toplamları (ör. Python'larmath.fsum
) gerçekleştirmek için yerleşik bir yöntem sunar , bu nedenle saf toplam algoritması yerine bu işlevleri kullanmayı düşünebilirsiniz.