SORU
20 ŞUBAT 2014, PERŞEMBE


Neden Kayan Nokta Numaraları Yanlış.

Neden bazı sayılar kayan noktalı sayı olarak depolanan doğruluğunu kaybediyor?

Örneğin, ondalık sayı 9.2 ifade edebilir tam olarak bir oran iki ondalık tamsayı (92/10), hem de olabilir hangi ifade tam olarak ikili (0b1011100/0b1010). Ancak, aynı oran kayan noktalı sayı olarak depolanan asla tam olarak 9.2 eşittir:

32-bit "single precision" float: 9.19999980926513671875
64-bit "double precision" float: 9.199999999999999289457264239899814128875732421875

Ne kadar basit görünen böyle bir sayı "Çok" olarak ifade etmek için . büyük olabilir ^strong>64 bitbellek?

CEVAP
20 ŞUBAT 2014, PERŞEMBE


Çoğu programlama dilinde, kayan nokta sayıları çok scientific notation gibi gösterilir: bir üs ve mantis (significand denir). Çok basit bir numara, 9.2 aslında bu kısmı olduğunu söylüyor:

5179139571476070 * 2-49

Üs -49 ve mantis nerede 5179139571476070. İmkansız temsil edemezbazıondalık sayılar bu şekilde üs ve mantis her ikisi de tamsayı olmalıdır. Diğer bir deyişle, bir bütün olmalı yüzertamsayıbir çarpı2 tamsayı güç.

9.2 sadece 92/10, ama olabilir10olarak ifade edilemez2neğerntamsayı değerleri için sınırlı.


Veri görmüyorum

İlk birkaç fonksiyonları içinbakın32 - ve 64-bit yapmak bileşenleri 14**. Eğer sadece bakım eğer bu çıkış (Python örnek): hakkında geçiştirmeye

def float_to_bin_parts(number, bits=64):
    if bits == 32:          # single precision
        int_pack      = 'I'
        float_pack    = 'f'
        exponent_bits = 8
        mantissa_bits = 23
        exponent_bias = 127
    elif bits == 64:        # double precision. all python floats are this
        int_pack      = 'Q'
        float_pack    = 'd'
        exponent_bits = 11
        mantissa_bits = 52
        exponent_bias = 1023
    else:
        raise ValueError, 'bits argument must be 32 or 64'
    bin_iter = iter(bin(struct.unpack(int_pack, struct.pack(float_pack, number))[0])[2:].rjust(bits, '0'))
    return [''.join(islice(bin_iter, x)) for x in (1, exponent_bits, mantissa_bits)]

Bu işlev arkasında karmaşıklığı bir çok şey var, ve açıklamak için oldukça teğet olur, ama eğer ilgileniyorsanız, bizim için önemli bir kaynak struct modülüdür.

float Python 64-bit çift duyarlıklı sayı. C gibi diğer diller, C , C#, Java-hassas çift ayrı bir tür genellikle 64 bit olarak uygulanan double sahiptir.

Bizim örnek ile bu fonksiyonu çağırdığımızda, 9.2, burada ne olsun var:

>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']

Verilerin yorumlanması

Dönüş değeri yarıyordum üç bileşenlerine göreceksiniz. Bu bileşenler şunlardır:

  • İşaret
  • Üs
  • Mantis (Significand, ya da bir Kısmını)

İşaret

İşareti tek bir parça olarak ilk bileşen saklanır. Bunu açıklamak kolay: 0 kaydır pozitif bir sayı olduğu anlamına gelir; 1 negatif olduğu anlamına gelir. 9.2 pozitif olduğu için işareti değerimiz 0.

Üs

Üs 11 bit olarak orta bileşen saklanır. , 0b10000000010 bizim durumumuzda. Ondalık, 25 ** değerini temsil eder. Bu bileşen bir cilvesi eşit bir sayı çıkarmak gerekir2(# bit) - 1- 1gerçek üs alma; bizim durumumuzda, bu 0b1111111111 (ondalık sayı 1023) gerçek üstü, 0b00000000011 (ondalık sayı 3) çıkarma anlamına gelir.

Mantis

Mantis 52 bit olarak üçüncü bileşeni saklanır. Ancak, bu bileşen için bir cilvesi var. Bu durumu anlamak için, bilimsel gösterim, bu gibi: bir dizi düşünün

6.0221413x1023

Mantis 6.0221413 olurdu. Bilimsel gösterimde mantis her zaman sıfır olmayan tek bir rakam ile başlayan bir hatırlayın. Aynı tutar için doğru ikili, ikili, sadece iki basamak dışında: 0 1. İkili mantisher zaman1 ile başlar! Bir şamandıra saklandığında, ikili mantis önünde 1 alanı kazanmak için atlanmış; geri üçüncü elementimiz önünde yere götürmeliyizdoğrumantis:

1.0010011001100110011001100110011001100110011001100110

Bu bitlerin üçüncü bileşeni içinde saklı aslında temsil ettiği için daha basit bir ek içerirkesirlimantis parçası radix point sağında.

Ondalık sayılar ile uğraşırken, biz "" ya 10 yetkileri ile çarparak bölerek. ondalık noktasını taşımak İkili ya da 2'nin katları ile çarparak bölerek aynı şeyi yapabiliriz. Üçüncü elementimiz 52 bit olduğundan, onun tarafından bölüyoruz252sağa 52 yerlere taşımak için:

0.0010011001100110011001100110011001100110011001100110

Ondalık gösterimde, bu 4503599627370496 675539944105574 0.1499999999999999 elde etmek için bölme gibi. (Bu ikili düzende tam olarak ifade edilebilecek bir oran bir örnektir, ama sadece ondalık yaklaşık; daha fazla ayrıntı için, bkz: 675539944105574 / 4503599627370496.)

Kesirli bir sayı halinde üçüncü bileşeni dönüştürdü olduğumuza göre, 1 ekleme doğru mantis verir.

Bileşenleri özetlemek

  • İşareti (birinci bileşen): Negatif Pozitif 0, 1
  • Üs (orta bileşen): Çıkarma2(# bit) - 1- 1gerçek üs alma
  • Mantis (son bileşen): Böl2(# bit)ve Ekle 40* *gerçek mantis almak için

Sayısının hesaplanması

Birlikte üç parça koyarak, bu ikili sayıyı.

1.0010011001100110011001100110011001100110011001100110 x 1011

Sonra ondalık ikili dönüştürebilirsiniz:

1.1499999999999999 x 23(hatalı!)

Ve bir kayan nokta değeri olarak depolanan (9.2) ile başladık sayısı son temsilini ortaya çarpın:

9.1999999999999993


Bir Kesir olarak temsil eden

9.2

Numarasını inşa ettiğimize göre, Olası basit bir kesire bunu yeniden oluşturmak için:

1.0010011001100110011001100110011001100110011001100110 x 1011

Tam sayı için Shift mantis:

10010011001100110011001100110011001100110011001100110 x 1011-110100

Ondalık dönüştürmek:

5179139571476070 x 23-52

Üs çıkarma:

5179139571476070 x 2-49

Bölüm içine negatif üs açmak:

5179139571476070 / 249

Üs çarpın:

5179139571476070 / 562949953421312

Eşittir:

9.1999999999999993

9.5

>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']

Zaten mantis sadece 4 basamak sıfır bir sürü izler görebilirsiniz. Ama diyelim ki adım geçiyor.

İkili bilimsel gösterimde birleştirin:

1.0011 x 1011

Ondalık noktasını Shift:

10011 x 1011-100

Üs çıkarma:

10011 x 10-1

Maskelerin:

X 2 19-1

Bölüm için negatif üs:

/ 2 191

Üs çarpın:

/ 2 19

Eşittir:

9.5



Daha fazla okuma

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • How It Should Have Ended

    How It Shoul

    5 Mart 2007
  • Jonathan Flavell

    Jonathan Fla

    1 HAZİRAN 2006
  • Mr. H

    Mr. H

    1 Temmuz 2012