在二进制代码中正确舍入十进制数字

使用二进制代码表示的十进制数字的主要问题之一是将二进制数字舍入为最接近正确舍入的十进制数字的可表示十进制数字的值的问题。 下面我们讨论这个问题,并给出用于适当取整的简单算法。 该算法的操作由C ++中的测试程序进行说明。

回想一下,可表示的十进制数是一个其值可以用二进制代码准确表示的数字。 因此,数字0.125完全等于二进制数字0.001。 也可以说任何二进制数y的值等于某个可表示的十进制数x 。 例如,二进制数y = 1.001101 * 2 ^ -3的值等于十进制可表示数x = 0.150390625的值。
我们说二进制数y等于十进制数x 。 相反,十进制数x等于二进制数y

让我们看看从控制台输入十进制数或在程序中将其显示为常量时,十进制数会发生什么。
编译器会将任何十进制数字转换(转换)为程序员指定的格式。 由于二进制数字在计算机中处理速度最快,因此输入的十进制数字通常会转换为定点格式(包括int)或浮点格式之一(单,双或另一种二进制格式) 。

根据IEEE754标准,机器内部格式的实数以规范化的二进制形式表示。 因此,二进制正实数y可以表示为y = b0.b1 ... bp * 2 ^ e(b0≠0)。
如果e + 1> 00 ,则相同的数字可以表示为0.b0b1 ... bp * 2 ^(e + 1)(b0≠0)0.b0b1 ... bp * 2 ^ e(b0≠0)如果e <0
此外,我们将坚持第二种观点,因为 在下面的C ++测试程序中,有一个函数q = frexp(x,&e),它使我们能够确定二进制数b0.b1 ... bp * 2 ^ e中指数e的值。

因此,任何二进制归一化数y = 0.b0b1 ... bp * 2 ^ e(b0≠0)的十进制等效值等于某个归一化十进制数x = 0.d0d1 ... dN ... dn * 10 ^ E(d0 ≠0)。
例如,数字y = 0.1001101 * 2 ^ -2等效于可表示的十进制数字x = 0.150390625
要使x的数字Xr等于四舍五入为N个有效数字的数字, X必须乘以10 ^ k ,其中k = NE 。 这是必需的,以便生成的数字包含具有N个有效数字的整数部分,然后可以将其舍入为最接近的整数。 然后必须通过将舍入的整数乘以10 ^ -k来将其舍入为小数位。 从数学上讲,可以用以下公式编写:
X = [x * 10 ^ k + 0.5] * 10 ^ -k = [y * 10 ^ k + 0.5] * 10 ^ -k,其中[]是数字的整数部分。

可以证明,如果B <10 ^ n ,则包含m个二进制数字的整数二进制数B等于十进制数字D的值,该十进制数字D包含n = 1 m * log 2 3小数位 如果 B≥10 ^ n ,则等于n = n +1 。 在计算中,我们可以取log2≈0.301

我们根据y的二进制表示形式中的可用信息确定k的值。 在k的公式中 N 舍入精度已知的,因此我们需要确定指数E。
根据以下关系式确定指数EE =⌊e *0.301⌋
仍然需要考虑以下情况。 如果x * 10 ^ k = X> 10 ^ N ,则需要将其乘以10 ^(-1)并调整系数k 。 我们得到X = X * 10 ^(-1),k = k-1
舍入后的数字将等于Xr = X * 10 ^(-k)

结果,我们获得了以下简单算法,用于对二进制实数进行正确的十进制舍入。 该算法适用于具有任意指定的十进制舍入精度N的任何二进制数格式
在入口处:
小数舍入精度N ;
是格式为y = 0.b0b1 ... bp * 2 ^ e(b0≠0)的二进制数。
输出:四舍五入的十进制数字X = 0.d0d1 ... dN * 10 ^ E.
-1.确定二进制数y的指数e;
2. E =⌊e*0.3⌋;
3. k = NE;
4. X = x * 10 ^ k;
5.如果X <10 ^ N,则第8项;
6. X = X * 10 ^ -1;
7. k = k-1;
8. Xr = [X + 0.5] * 10 ^(-k);
结束
-在上述算法中,数字Xr是最接近该数字的可表示的十进制数字,这是数字x的正确舍入,而四舍五入又是数字y的十进制等效项。
由于我们习惯于使用十进制数字,因此,通常,输入流恰好是十进制数字。 在输出中,我们也想获取十进制数字。 例如,在Excel中。 但是,将十进制数转换为二进制代码后,通常会不可逆地对其进行转换。 结果,转换为二进制数字的舍入可能与控制台上打印的数字的正确舍入不一致。 这主要适用于以下情况:当我们尝试将十进制数字四舍五入到最大可能的有效数字位数时。 单身是7,双身是15。
这可以在下面的测试程序中很好地研究,该程序由作者用C ++编写。

在测试程序中,根据要求,将以下内容输入到控制台中:
-数字XN个小数舍入的精度,它是数字x的二进制等价关系中最接近的可表示数字;
x是任意形式的数字。

在输入的十进制数字x下,将打印数字X ,这是最接近x的可表示数字(请参见下面的屏幕截图)。
对数字X进行四舍五入,因为 x的确切值在二进制转换中丢失。
返回值:
-格式为Xr = M * 10 ^(N + e)的十进制数字其中M是具有N个有效数字的整数十进制数字;
是数字xr ,它等于最接近数字X的标准化二进制等价关系的可表示数字
图片
在屏幕截图中:

N = 15-输入的十进制数字舍入到的十进制有效位数。
x = 7.123456789098765321 e-89是我们要舍入到15位有效数字的十进制数字。
X = 7.12345678909876559 e-089-可表示的十进制数字,其值等于二进制数,该数字是通过将数字x转换为格式p = 53获得的。
Xr = x = 712345678909877e-103-通过对数字X进行四舍五入获得的整数尾数。
xr = x = 7.12345678909877e-089-通过归一化十进制数Xr的二进制等效值而获得的数字。 最接近Xr。

以下是用于正确舍入用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/zh-CN471506/


All Articles