Pembulatan angka desimal yang benar dalam kode biner

Salah satu masalah serius dengan angka desimal yang diwakili dalam kode biner adalah masalah pembulatan angka biner ke nilai angka desimal yang paling dekat dengan angka desimal yang dibulatkan dengan benar. Di bawah ini kami membahas masalah ini dan memberikan algoritma sederhana untuk pembulatan yang tepat. Pengoperasian algoritma diilustrasikan oleh program uji di C ++.

Ingat bahwa angka desimal yang dapat diwakili adalah angka yang nilainya dapat diwakili secara akurat oleh kode biner. Jadi, angka 0,125 persis sama dengan angka biner 0,001. Dapat juga dikatakan bahwa nilai dari setiap bilangan biner y sama dengan beberapa bilangan desimal representatif x . Sebagai contoh, nilai angka biner y = 1.001101 * 2 ^ -3 sama dengan nilai angka representatif desimal x = 0,150390625.
Kami mengatakan bahwa angka biner y setara dengan angka desimal x . Sebaliknya, angka desimal x sama dengan angka biner y .

Mari kita lihat apa yang terjadi dengan angka desimal ketika dimasukkan dari konsol, atau ketika muncul dalam program sebagai konstanta.
Setiap angka desimal dikonversi (dikonversi) oleh kompiler ke dalam format yang ditentukan oleh programmer. Karena angka biner diproses paling cepat di komputer, angka desimal input dikonversi, paling sering, ke format titik tetap (termasuk int), atau ke salah satu format titik apung - format biner tunggal, ganda, atau ke format biner lainnya .

Menurut standar IEEE754, bilangan real dalam format internal mesin direpresentasikan dalam bentuk biner yang dinormalisasi. Jadi, bilangan real positif biner y dapat direpresentasikan sebagai y = b0.b1 ... bp * 2 ^ e (b0 ≠ 0).
Angka yang sama dapat direpresentasikan sebagai 0.b0b1 ... bp * 2 ^ (e + 1) (b0 ≠ 0) jika e + 1> 0 dan 0.b0b1 ... bp * 2 ^ e (b0 ≠ 0) jika e <0 .
Selanjutnya kami akan mematuhi pandangan kedua, karena dalam program uji C ++ kami di bawah ini, ada fungsi q = frexp (x, & e), yang memungkinkan kita untuk menentukan nilai eksponen e dalam bilangan biner yang direpresentasikan sebagai b0.b1 ... bp * 2 ^ e .

Jadi, ekivalen desimal dari setiap angka dinormalisasi biner y = 0.b0b1 ... bp * 2 ^ e (b0 ≠ 0) sama dengan beberapa angka desimal dinormalisasi x = 0.d0d1 ... dN ... dn * 10 ^ E (d0 ≠ 0).
Misalnya, angka y = 0.1001101 * 2 ^ -2 setara dengan angka desimal yang dapat diwakili x = 0,150390625 .
Untuk mendapatkan angka Xr dari x sama dengan angka dibulatkan ke N digit signifikan, X harus dikalikan dengan faktor 10 ^ k , di mana k = NE . Ini diperlukan agar angka yang dihasilkan berisi bagian integer dengan N digit signifikan, yang kemudian dapat dibulatkan ke integer terdekat. Bilangan bulat bulat harus dikurangi ke skala sebelumnya dengan mengalikannya dengan 10 ^ -k . Secara matematis, ini dapat ditulis dengan rumus berikut:
X = [x * 10 ^ k + 0,5] * 10 ^ -k = [y * 10 ^ k + 0,5] * 10 ^ -k, di mana [] adalah bagian bilangan bulat dari angka tersebut.

Dapat ditunjukkan bahwa bilangan biner bilangan bulat B yang mengandung angka biner m sama dengan nilai angka desimal D , yang berisi n = ⌊m * log2⌋ tempat desimal, asalkan B <10 ^ n. Dan sama dengan n = n +1 , asalkan B ≥ 10 ^ n . Dalam perhitungan, kita bisa mengambil log2≈0.301 .

Kami menentukan nilai k berdasarkan informasi yang tersedia dalam representasi biner dari y . Dalam rumus untuk k, akurasi pembulatan N diketahui, jadi kita perlu menentukan eksponen E.
Eksponen E ditentukan dari relasi: E = ⌊e * 0.301⌋ .
Tetap memperhitungkan keadaan berikut. Jika x * 10 ^ k = X> 10 ^ N , maka Anda perlu mengalikannya dengan 10 ^ (- 1) dan menyesuaikan koefisien k . Kami mendapatkan X = X * 10 ^ (- 1), k = k-1 .
Angka bulat akan sama dengan Xr = X * 10 ^ (- k) .

Sebagai hasilnya, kami memperoleh algoritma sederhana berikut untuk pembulatan desimal yang benar dari bilangan real biner. Algoritma ini cocok untuk semua format angka biner dengan presisi pembulatan desimal N.
Di pintu masuk:
Akurasi pembulatan desimal N ;
Adalah angka biner dalam format y = 0.b0b1 ... bp * 2 ^ e (b0 ≠ 0) .
Output: Angka desimal bulat X = 0.d0d1 ... dN * 10 ^ E.
- 1. Tentukan eksponen e dari angka biner y;
2. E = ⌊e * 0.3⌋;
3. k = NE;
4. X = x * 10 ^ k;
5. Jika X <10 ^ N, maka item 8;
6. X = X * 10 ^ -1;
7. k = k-1;
8. Xr = [X + 0.5] * 10 ^ (- k);
Akhir
- Dalam algoritma di atas, bilangan Xr adalah bilangan desimal yang dapat direpresentasikan yang paling dekat dengan bilangan, yang merupakan pembulatan yang benar dari bilangan x , yang pada gilirannya adalah ekivalen desimal dari bilangan y .
Karena kita terbiasa bekerja dengan angka desimal, maka, sebagai aturan, aliran input adalah angka desimal. Pada output, kami ingin mendapatkan angka desimal juga. Misalnya, seperti di Excel. Tapi, setelah mengubah angka desimal menjadi kode biner, mereka biasanya diubah secara permanen. Sebagai akibatnya, pembulatan yang dikonversi ke angka biner mungkin tidak bersamaan dengan pembulatan angka yang dicetak pada konsol. Ini berlaku terutama untuk kasus ketika kami mencoba untuk membulatkan angka desimal ke jumlah maksimum yang mungkin dari digit signifikan. Untuk lajang, ini adalah 7, dan untuk gandakan itu adalah 15.
Ini dapat diselidiki dengan baik pada program pengujian di bawah ini, yang ditulis penulis dalam C ++.

Dalam program pengujian, berdasarkan permintaan, yang berikut dimasukkan ke konsol:
- akurasi pembulatan desimal N dari angka X , yang merupakan angka representatif terdekat dari biner setara dengan angka x ;
Apakah angka x dalam bentuk sewenang-wenang.

Di bawah angka desimal yang dimasukkan x, angka X dicetak, yang merupakan angka yang paling dekat dengan x (lihat tangkapan layar di bawah).
Pembulatan dilakukan pada angka X , karena nilai tepat x hilang dalam konversi biner.
Pengembalian:
- angka desimal dalam format Xr = M * 10 ^ (N + e), di mana M adalah angka desimal bilangan bulat dengan N digit signifikan;
Adalah bilangan xr , yang sama dengan bilangan representatif yang paling dekat dengan biner yang dinormalisasi dari bilangan X.
gambar
Di tangkapan layar:

N = 15 - jumlah digit signifikan desimal di mana angka desimal input dibulatkan.
x = 7.123456789098765321 e-89 adalah angka desimal yang ingin kita bulatkan menjadi 15 digit signifikan.
X = 7.12345678909876559 e-089 - angka desimal yang dapat diwakilkan, nilainya sama dengan angka biner yang diperoleh dengan mengubah angka x ke format p = 53.
Xr = x = 712345678909877e-103 - bilangan mantissa integer diperoleh dengan membulatkan angka X.
xr = x = 7.12345678909877e-089 - angka yang diperoleh dengan menormalkan ekuivalen biner dari angka desimal Xr. Ini adalah yang terdekat dengan Xr.

Di bawah ini adalah kode program pengujian untuk pembulatan angka desimal yang benar yang diwakili dalam kode biner dalam C ++.

#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <iomanip>
using namespace std;

int main()
{
   double q,x,xr,X;
   unsigned long long int Xr;
   int N,p,E,e,k;

  cout <<"Input a binary precision p=";
  cin>>p;
  cout <<"Input a decimal precision N=";
  cin>>N;
  cout <<endl<<"Input a number and press ENTER:"<<"\n"<<"x= ";
  cin>>x;
   cout<<"X= "<< setprecision(18)<<x << '\n';

    q=frexp (x, &e);
    E =static_cast <int> (e*0.301);
    k=N-E;
   if (E<0)       //for format xr=d0.d1...dN*10^E (d0≠0).
        k=k+1;
    X=x*pow(10,k);
       if (X > pow (10,N)){
            X=X/10;
            k=k-1;
      }

       X=X+0.5;
       Xr=static_cast <unsigned long long int> (X);
       xr=Xr*pow(10,-k);

    cout<<endl <<"Xr= "<<Xr<<"e"<<-k<<'\n';
    cout<<"xr="<<xr<<'\n';

   system("pause");
      return 0;
}


pow(10,k). , k , , 10^k, 5^k.

Source: https://habr.com/ru/post/id471506/


All Articles