(Selesai) Tutorial untuk memahami IEEE Floating-Point kesalahan

Sanggahan Konten KB yang Dihentikan

Artikel ini ditulis untuk produk yang tidak lagi didukung oleh Microsoft. Oleh karena itu, artikel ini disediakan "sebagaimana adanya" dan tidak akan diperbarui lagi.

Ringkasan

Floating-Point matematika adalah topik yang kompleks yang membingungkan banyak programmer. Tutorial berikut ini akan membantu Anda mengenali pemrograman situasi di mana floating-point kesalahan mungkin terjadi dan cara menghindari mereka. Juga harus memungkinkan Anda untuk mengenali kasus yang disebabkan oleh inheren floating-point matematika batasan bukan bug kompiler aktual.

Informasi lebih lanjut

Sistem angka desimal dan biner

Biasanya, kita menghitung hal-hal dasar 10. Basis benar-benar sembarang. Satu-satunya alasan bahwa orang telah digunakan secara tradisional 10 dasar adalah bahwa mereka memiliki 10 jari, yang telah dibuat mudah menghitung alat.


Nomor 532.25 di desimal (dasar 10) berarti berikut ini:

   (5 * 10^2) + (3 * 10^1) + (2 * 10^0) + (2 * 10^-1) + (5 * 10^-2)
500 + 30 + 2 + 2/10 + 5/100
_________
= 532.25


Nomor biner sistem (dasar 2), setiap kolom mewakili daya 2 dan bukan 10. Sebagai contoh, nomor 101.01 berarti berikut ini:

   (1 * 2^2) + (0 * 2^1) + (1 * 2^0) + (0 * 2^-1) + (1 * 2^-2)
4 + 0 + 1 + 0 + 1/4
_________
= 5.25 Decimal


Bagaimana bilangan bulat ditunjukkan di PC

Karena tidak ada bagian pecahan untuk bilangan bulat, representasi mesin jauh lebih mudah daripada nilai floating-point. Bilangan bulat normal pada komputer pribadi (PC) adalah 2 byte (16 bit) lama dengan bit paling penting yang menunjukkan tanda. Bilangan bulat panjang adalah 4 bita lama. Nilai yang positif adalah nomor biner yang sederhana. Misalnya:

    1 Decimal = 1 Binary
2 Decimal = 10 Binary
22 Decimal = 10110 Binary, etc.


Namun, negatif bilangan bulat yang diwakili menggunakan dua pelengkap skema. Untuk mendapatkan dua pelengkap perwakilan angka negatif, mengambil biner untuk nilai absolut nomor kemudian balik semua bit dan tambahkan 1. Misalnya:

   4 Decimal = 0000 0000 0000 0100
1111 1111 1111 1011 Flip the Bits
-4 = 1111 1111 1111 1100 Add 1


Perhatikan bahwa -1 desimal = 1111 1111 1111 1111 biner yang menjelaskan mengapa dasar memperlakukan -1 sebagai Logis true (semua bit = 1). Ini merupakan akibat dari tidak memiliki terpisah operator untuk perbandingan bitwise dan logis. Sering di dasar, lebih mudah untuk menggunakan fragmen kode di bawah ini ketika program Anda akan membuat banyak perbandingan logis. Ini sangat membantu dibaca.

   CONST TRUE = -1
CONST FALSE = NOT TRUE


Perhatikan bahwa menambahkan kombinasi dari dua melengkapi nomor bersama dengan menggunakan aritmatika biner biasa menghasilkan hasil yang benar.

Floating-Point komplikasi

Bilangan bulat setiap desimal dapat persis diwakili oleh integer biner; Namun, hal ini tidak berlaku untuk pecahan angka. Pada kenyataannya, setiap angka yang tidak masuk akal dalam 10 dasar juga akan tidak masuk akal dalam sistem dengan dasar yang lebih kecil dari 10.


Untuk biner, khususnya, hanya pecahan angka yang dapat ditunjukkan dalam bentuk p/q, mana q adalah bilangan bulat daya 2, dapat dinyatakan seluruhnya, dengan jumlah bit yang terbatas.


Pecahan desimal bahkan umum, seperti 0,0001 desimal, tidak dapat diwakili tepatnya dalam biner. (0,0001 adalah pecahan biner berulang dengan periode 104 bit!)


Hal ini menjelaskan mengapa contoh sederhana, seperti berikut

   SUM = 0
FOR I% = 1 TO 10000
SUM = SUM + 0.0001
NEXT I%
PRINT SUM ' Theoretically = 1.0.


akan 1.000054 cetak sebagai output. Galat kecil dalam mewakili 0,0001 biner menjalar ke jumlah.


Untuk alasan yang sama, Anda harus selalu sangat berhati-hati ketika membuat perbandingan nomor nyata. Contoh berikut menunjukkan kesalahan pemrograman umum:

   item1# = 69.82#
item2# = 69.20# + 0.62#
IF item1# = item2# then print "Equality!"


Hal ini tidak akan mencetak "Persamaan!" karena 69.82 tidak dapat ditunjukkan persis dalam biner, yang menyebabkan nilai yang hasil dari tugas sedikit berbeda (dalam biner) dari nilai yang dihasilkan dari ekspresi. Dalam praktek, Anda harus selalu kode perbandingan sedemikian rupa untuk memungkinkan beberapa toleransi. Misalnya:

   IF (item1# < 69.83#) AND (item1# > 69.81#) then print "Equal"


Ini akan mencetak "Sama".

IEEE Format angka

QuickBasic MS-DOS, versi 3.0 yang disertakan bersama versi MBF (Microsoft Binary Floating Point) dan IEEE (Institute listrik dan elektronik insinyur) untuk mesin dengan coprocessor matematika. QuickBasic untuk MS-DOS, versi 4.0 dan yang lebih baru hanya menggunakan IEEE. Microsoft memilih standar IEEE mewakili nilai-nilai floating-point dalam versi dasar untuk alasan utama tiga berikut ini:

  1. Untuk mengizinkan dasar menggunakan Intel matematika coprocessors, yang menggunakan IEEE format. Intel seri 80 x 87 coprocessors tidak dapat bekerja dengan Microsoft biner Format angka.
  2. Untuk membuat bahasa menelepon antara Basic, C, Pascal, FORTRAN dan MASM lebih mudah. Jika tidak, konversi rutinitas akan digunakan untuk mengirim nilai numerik dari satu bahasa lain.
  3. Untuk mencapai konsistensi. IEEE adalah standar untuk compiler C dan FORTRAN industri diterima.
Berikut adalah perbandingan cepat IEEE dan MBF representasi nomor presisi ganda:

               Sign Bits   Exponent Bits   Mantissa Bits
--------- ------------- -------------
IEEE 1 11 52 + 1 (Implied)
MBF 1 8 56


Untuk informasi lebih lanjut tentang perbedaan antara IEEE dan MBF floating-point representasi, permintaan di Pangkalan Pengetahuan Microsoft di kata-kata yang berikut ini:

   IEEE and floating and point and appnote


Perhatikan bahwa IEEE memiliki bit lebih khusus untuk eksponen, yang memungkinkan untuk mewakili nilai yang lebih luas. MBF memiliki lebih banyak mantissa bit yang memungkinkan untuk menjadi lebih baik dalam kisaran sempit.

Konsep Floating-Point Umum

Sangat penting untuk memahami bahwa setiap biner sistem floating-point dapat mewakili sejumlah floating-point nilai dalam bentuk yang tepat. Nilai-nilai lainnya harus diperkirakan dengan nilai representable terdekat. Standar IEEE menentukan metode untuk mengumpulkan nilai untuk nilai representable "terdekat". QuickBasic MS-DOS mendukung standar dan babak berdasarkan aturan IEEE.


Selain itu, perlu diingat bahwa angka yang dapat ditunjukkan di IEEE menyebar melalui sangat berbagai. Anda bisa bayangkan mereka di nomor baris. Ada kepadatan tinggi representable nomor dekat 1.0 dan -1.0 tetapi sedikit sebagai Anda pergi ke 0 atau tanpa batas.


Tujuan dari standar IEEE, yang dirancang untuk perhitungan rekayasa, adalah untuk memaksimalkan akurasi (untuk mendapatkan nomor tutup mungkin sebenarnya). Presisi merujuk ke nomor digit yang dapat mewakili. IEEE standar mencoba keseimbangan jumlah bit khusus untuk eksponen dengan jumlah bit yang digunakan untuk bagian pecahan nomor, untuk menjaga akurasi dan presisi dalam batas yang dapat diterima.

Rincian IEEE

Angka Floating-Point ditunjukkan dalam bentuk berikut ini, di mana [eksponen] adalah eksponen biner:

   X =  Fraction * 2^(exponent - bias)


[Pecahan] adalah bagian pecahan menormalkan nomor normal karena eksponen yang disesuaikan sehingga bit terkemuka selalu 1. Dengan cara ini, itu tidak perlu disimpan, dan Anda mendapatkan lebih sedikit presisi. Itulah mengapa ada bit tersirat. Anda dapat berpikir ini seperti notasi ilmiah, di mana Anda manipulasi eksponen memiliki satu angka di sebelah kiri desimal, kecuali biner, Anda selalu dapat manipulasi eksponen sehingga bit pertama adalah 1, karena ada hanya 1s dan 0s.


[bias] adalah nilai bias digunakan untuk menghindari untuk menyimpan eksponen negatif.


Bias untuk nomor presisi tunggal adalah 127 dan 1023 (desimal) untuk nomor presisi ganda.


Nilai yang sama dengan 0 semua dan semua 1 (biner) yang disediakan untuk mewakili kasus khusus. Ada hal lain khusus, yang menunjukkan berbagai kondisi galat.

Contoh presisi tunggal

2 = 1 * 2 ^ 1 = 0100 0000 0000 0000... 0000 0000 = 4000 0000 hex
Perhatikan tanda bit nol, dan eksponen disimpan 128, atau 100 0000 0 biner yang 127 ditambah 1. Mantissa disimpan adalah (1.) 000 0000... 0000 0000, yang memiliki tersirat terkemuka 1 dan biner titik, jadi mantissa sebenarnya adalah 1.

-2 = -1 * 2 ^ 1 = 1100 0000 0000 0000... 0000 0000 = C000 0000 hex
Sama + 2 kecuali bahwa tanda bit ditetapkan. Hal ini berlaku untuk semua IEEE format angka floating-point.

4 = 1 * 2 ^ 2 = 0100 0000 1000 0000... 0000 0000 = 4080 0000 hex
Meningkatkan eksponen sama mantissa, dengan satu (bias nilai adalah 129, atau 100 0000 1 biner.

6 = 1.5 * 2 ^ 2 = 0100 0000 1100 0000... 0000 0000 = 40C 0 0000 hex
Sama eksponen mantissa lebih besar dengan setengah--ini (1.) 100 0000... 0000 0000, yang karena itulah pecahan biner, 1-1/2 (nilai angka pecahan adalah 1/2, 1/4, 1/8, dll.).

1 = 1 * 2 ^ 0 = 0011 1111 1000 0000... 0000 0000 = 3F80 0000 hex
Eksponen sama sebagai kekuatan lainnya 2, mantissa adalah salah satu kurang dari 2 127, atau 1 1111 011 biner.

.75 = 1.5 * 2 ^ -1 = 0011 1111 0100 0000... 0000 0000 = 3F40 0000 hex
Eksponen bias adalah 126, 011 1111 biner di 0, dan mantissa (1.) adalah 100 0000... 0000 0000, yang merupakan 1-1/2.

2.5 = 1,25 * 2 ^ 1 = 0100 0000 0010 0000... 0000 0000 = 4020 0000 hex
Sama persis seperti 2 kecuali bahwa bit yang mewakili 1/4 terletak di mantissa.

0,1 = 1.6 * 2 ^-4 = 0011 1101 1100 1100... 1100 1101 = 3DCC CCCD hex
1/10 adalah pecahan berulang biner. Mantissa malu hanya 1.6, dan eksponen bias mengatakan bahwa 1.6 adalah untuk dibagi oleh 16 (ini adalah 011 1101 1 biner yang 123 di desimal). Eksponen yang benar adalah 123-127 = - 4, yang berarti bahwa faktor yang menggandakan 2 **-4 = 1/16. Perhatikan bahwa mantissa disimpan bulat di bit terakhir. Ini adalah upaya untuk mewakili nomor unrepresentable akurat mungkin. (Alasan yang 1/10 dan 1/100 tidak tepat representable biner mirip dengan cara 1 3 tidak benar-benar representable dalam desimal.)

0 = 1.0 * 2 ^-128 = semua nol--kasus khusus.

Galat Floating-Point umum lainnya

Berikut adalah galat floating-point umum:

  1. Galat Round-off


    Galat ini terjadi bila semua bit di nomor biner yang tidak digunakan dalam penghitungan.


    Contoh: Menambahkan 0,0001 untuk 0,9900 (tunggal presisi)


    Desimal 0,0001 akan ditunjukkan sebagai:
    (1.) 10100011011011100010111 * 2^(-14+Bias) (13 terkemuka 0s biner!)
    0,9900 akan ditunjukkan sebagai:
    (1.)11111010111000010100011 * 2^(-1+Bias)
    Sekarang untuk benar-benar menambahkan angka-angka, titik (biner) desimal harus rata. Ini harus Unnormalized. Berikut adalah dihasilkan tambahan:
           .000000000000011010001101 * 2^0  <- Only 11 of 23 Bits retained
    +.111111010111000010100011 * 2^0
    ________________________________
    .111111010111011100110000 * 2^0


    Ini disebut round-off galat karena beberapa komputer bulat ketika pergeseran untuk tambahan. Orang lain hanya memotong. Round-off kesalahan penting untuk mempertimbangkan setiap kali Anda menambahkan atau mengalikan dua nilai yang sangat berbeda.
  2. Dua mengurangi hampir sama dengan nilai-nilai
           .1235
    -.1234
    _____
    .0001


    Ini akan normal. Perhatikan bahwa meskipun setiap angka asli memiliki empat digit signifikan, hasil memiliki hanya satu digit yang signifikan.
  3. Overflow dan underflow


    Hal ini terjadi ketika hasil terlalu besar atau terlalu kecil untuk diwakili oleh jenis data.
  4. Galat quantizing


    Hal ini terjadi dengan angka-angka yang tidak dapat ditunjukkan dalam bentuk sama persis dengan standar floating-point.
  5. Pembagian oleh sejumlah kecil


    Hal ini dapat memicu galat "dibagi dengan nol" atau dapat menghasilkan hasil yang buruk, seperti dalam contoh berikut:
          A = 112000000
    B = 100000
    C = 0.0009
    X = A - B / C


    Di QuickBasic MS-DOS, X sekarang memiliki nilai 888887, jawaban yang benar, 900000.
  6. Galat output


    Jenis galat terjadi saat fungsi output mengubah nilai mereka bekerja dengan.
Properti

ID Artikel: 42980 - Tinjauan Terakhir: 29 Jan 2017 - Revisi: 1

Tanggapan