Um dos problemas graves com números decimais representados no código binário é o problema de arredondar um número binário para o valor de um número decimal representável mais próximo de um número decimal corretamente arredondado. Abaixo discutimos esse problema e fornecemos um algoritmo simples para o arredondamento adequado. A operação do algoritmo é ilustrada por um programa de teste em C ++.
Lembre-se de que um número decimal representável é um número cujo valor pode ser representado com precisão por código binário. Portanto, o número 0,125 é exatamente igual ao número binário 0,001. Também se pode argumentar que o valor de qualquer número binário
y é igual a algum número decimal representável
x . Por exemplo, o valor do número binário
y = 1.001101 * 2 ^ -3 é igual ao valor do número representável decimal
x = 0,150390625.
Dizemos que o número binário y é equivalente ao número decimal
x . Por outro lado, o número decimal
x é equivalente ao número binário
y .
Vamos ver o que acontece com um número decimal quando é inserido no console ou quando aparece no programa como uma constante.
Qualquer número decimal é convertido (convertido) pelo compilador no formato especificado pelo programador. Como os números binários são processados mais rapidamente em um computador, o número decimal de entrada é convertido, na maioria das vezes, para um formato de ponto fixo (incluindo int) ou para um dos formatos de ponto flutuante - único, duplo ou para outro formato binário .
De acordo com o padrão IEEE754, os números reais no formato interno de uma máquina são representados na forma binária normalizada. Portanto, um número real positivo binário
y pode ser representado como
y = b0.b1 ... bp * 2 ^ e (b0 ≠ 0).O mesmo número pode ser representado como
0.b0b1 ... bp * 2 ^ (e + 1) (b0 ≠ 0) se
e + 1> 0 e
0.b0b1 ... bp * 2 ^ e (b0 ≠ 0) se
e <0 .
Além disso, aderiremos à segunda visão, já que no nosso programa de teste C ++ abaixo, existe uma função q = frexp (x, & e), que nos permite determinar o valor do expoente
e no número binário representado como
b0.b1 ... bp * 2 ^ e .
Portanto, o equivalente decimal de qualquer número normalizado binário
y = 0.b0b1 ... bp * 2 ^ e (b0 ≠ 0) é igual a algum número decimal normalizado
x = 0.d0d1 ... dN ... dn * 10 ^ E (d0 (0).Por exemplo, o número
y = 0.1001101 * 2 ^ -2 é equivalente ao número decimal representável
x = 0,150390625 .
Para obter o número
Xr de
x igual ao número arredondado para
N dígitos significativos,
X deve ser multiplicado por um fator de
10 ^ k , onde
k = NE . Isso é necessário para que o número resultante contenha uma parte inteira com
N dígitos significativos, que podem ser arredondados para o número inteiro mais próximo. O número inteiro arredondado deve então ser reduzido à escala anterior multiplicando-o por
10 ^ -k . Matematicamente, isso pode ser escrito com a seguinte fórmula:
X = [x * 10 ^ k + 0,5] * 10 ^ -k = [y * 10 ^ k + 0,5] * 10 ^ -k, em que [] é a parte inteira do número.
Pode-se mostrar que um número binário inteiro
B contendo
m dígitos binários é igual ao valor do número decimal
D , que contém
n = ⌊m * log2⌋ casas decimais, desde que
B <10 ^ n. E igual a n = n + 1 , desde que
B ≥ 10 ^ n . Nos cálculos, podemos tomar
log2≈0.301 .
Determinamos o valor de
k com base nas informações disponíveis na representação binária de
y . Na fórmula de
k, a precisão de arredondamento de
N é conhecida, portanto, precisamos determinar o expoente
E.O expoente
E é determinado a partir da relação:
E = *e * 0,301⌋ .
Resta considerar a seguinte circunstância. Se
x * 10 ^ k = X> 10 ^ N , é necessário multiplicá-lo por
10 ^ (- 1) e ajustar o coeficiente
k . Temos
X = X * 10 ^ (- 1), k = k-1 .
O número arredondado será igual a
Xr = X * 10 ^ (- k) .
Como resultado, obtemos o seguinte algoritmo simples para o arredondamento decimal correto dos números reais binários. O algoritmo é adequado para qualquer formato de número binário com uma precisão de arredondamento decimal especificada arbitrariamente
N.Na entrada:
Precisão de arredondamento decimal
N ;
É um número binário no formato
y = 0.b0b1 ... bp * 2 ^ e (b0 ≠ 0) .
Saída: Número decimal arredondado
X = 0.d0d1 ... dN * 10 ^ E.1. Determine o expoente e do número binário y;
2. E = *e * 0,3 ⌋;
3. k = NE;
4. X = x * 10 ^ k;
5. Se X <10 ^ N, então item 8;
6. X = X * 10 ^ -1;
7. k = k-1;
8. Xr = [X + 0,5] * 10 ^ (- k);
Fim.
- No algoritmo acima, o número
Xr é o número decimal representável mais próximo do número, que é o arredondamento correto do número
x , que por sua vez é o equivalente decimal do número
y .
Como estamos acostumados a trabalhar com números decimais, então, como regra, o fluxo de entrada é exatamente números decimais. Na saída, também queremos obter números decimais. Por exemplo, como no Excel. Mas, depois de converter números decimais em código binário, eles geralmente são transformados irreversivelmente. Como resultado, o arredondamento convertido em números binários pode não coincidir com o arredondamento correto dos números impressos no console. Isso se aplica principalmente aos casos em que tentamos arredondar um número decimal para o número máximo possível de dígitos significativos. Para solteiro, isso é 7 e, para o dobro, 15.
Isso pode ser bem investigado no programa de teste abaixo, que o autor escreveu em C ++.
No programa de teste, mediante solicitação, o seguinte é inserido no console:
- a precisão de
N arredondamento decimal do número
X , que é o número representável mais próximo do equivalente binário do número
x ;
É o número
x em forma arbitrária.
Sob o número decimal inserido
x, o número
X é impresso, que é o número representável mais próximo de
x (veja a captura de tela abaixo).
O arredondamento é realizado no número
X , porque o valor exato de
x é perdido na conversão binária.
Devoluções:
- número decimal no formato
Xr = M * 10 ^ (N + e), onde
M é um número decimal inteiro com
N dígitos significativos;
É o número
xr , que é igual ao número representável mais próximo do equivalente binário normalizado do número
X.
Na captura de tela:
N = 15 - o número de dígitos decimais significativos para os quais o número decimal de entrada é arredondado.
x = 7.123456789098765321 e-89 é o número decimal que gostaríamos de arredondar para 15 dígitos significativos.
X = 7.12345678909876559 e-089 - um número decimal representável, cujo valor é igual ao número binário obtido pela conversão do número x no formato p = 53.
Xr = x = 712345678909877e-103 - número inteiro da mantissa obtido pelo arredondamento do número X.
xr = x = 7.12345678909877e-089 - o número obtido normalizando o equivalente binário do número decimal Xr. É o mais próximo de Xr.
Abaixo está o código do programa de teste para o arredondamento correto dos números decimais representados no código binário em 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.