• 高精度乘法计算


    高精度乘法计算基础

    1.高精度浮点运算方法

      高精度浮点(Floating Point,FP)运算可以转换成整数型运算。由于高精度浮点数可以看成是由整数部分(Integer Part,IP)与小数部分(Decimal Part,DP)的组合,因此其乘法可以看成以下3种运算的组合,即整数x整数(IxI)、整数x小数(IxD)和小数x小数(DxD)。用表达式表示,则FP1*FP2=IP1*IP2+(IP1*DP2+IP2*DP1)+DP1*DP2

      (1)对于IxI型运算,所得的结果仍是整数

      (2)对于DxD型运算,所得结果仍是小数

      (3)对于IxD型运算,所得到的计算结果是一个浮点数,即可能包括整数和小数。

    此时可以使用小数部分的每个单元分别乘以整数部分。这样对于n位小数,可以得到拥有n个数字的字符串。把第d位乘以整数部分所得到的所有数字向低位移动d位,则可以得到整数和小数部分的数字位,然后进行求和,即可以得到所需要的计算结果。

    2.高精度乘法与移位计算

      由于在高精度计算中采用了数组或链表作为数值储存单元,因此可以使用移位计算代替乘法或除法运算。在对二进制计算中,对于一个数值,每个单元向高位移动一位,得到的数值结果等于这个数乘以2,而向低位移动一位时,其结果等于这个数值除以2,如8>>1=4,8<<1=16.同理,在高精度计算时,若进制基数为S,而向低位移动一位时,其结果等于这个数值除以S。注意,在移位后应把空出的低位设置为0.使用移位操作代替乘法或除法计算,可以大大地提高计算效率。

    高精度整数乘法

    1.高精度与单精度整数乘法

      这种乘法运算与高精度加法类似,所不同的是,对于高精度数字由低位到高位逐位乘以单经读书。设高精度的数位数字为a[i],单精度数为b,则可以把a[i]*b除以进制的玉树作为更新a[i]的值,把其商数作为进位。

    void mults(int a[],int na,int b,int c[],int * nc)
    {
        int i,s,carry=0;
        for(i=0;i<na;i++)                               //高精度与单精度乘法
        {
             s=carry+a[i]*b;                             //本位数乘以单精度整数,在加上进位
             c[i]=s%10;                                    //计算本位数字
             carry=s/10;                                   //计算进位
        }
        while(carry!=0)                                  //对进位进行处理
        {
             c[na]=carry%10;                           //计算本位
             carry=carry/10;                             //计算进位
             na++;                                           //计算结果的数字长度
        }
         *nc=na;                                            //返回结果数字长度
    }
    

      2.高精度与高精度整数乘法

      因为当两个高精度整数相乘时,所得到的积的位数最多不会超过最长整数的两倍,所以保存计算结果的变量空间可以设置为最长整数位数的两倍。当i和j初始值从0开始,乘数的第i位a[i]与被乘数的第j位b[j]相乘时,则其结果可以加入到c[i+j]中,然后再进行进位处理

    void multm(int a[],int na,int b[],int nb,int c[],int *nc)
    {
        int i,j,s,carry=0;
        *nc=na+nb;                                  //乘积长度
        for(i=0;i<*nc;i++)   c[i]=0;           //乘积变量初始化
        for(i=0;i<na;i++)
        {
             for(j=0;j<nb;j++)
             {
                  c[i+j]=c[i+j]+a[i]*b[j];       //两个整数数位与数位之间相乘
                  c[i+j+1]=c[i+j+1]+c[i+j]/10;//进位
                  c[i+j]=c[i+j]%10;                 //计算本位数字
             }
        }
    }
    

      高精度浮点数乘

    1.整数与小数相乘

      在不考虑小数点的情况下,先计算整数与每个小数单元中的数字,每次可以 得到一个长整数,在根据当前小数单元的位置,确定对这个长整型的缩小位数。第1位小数,缩小10倍(这里以十进制为例),相当于将此长整数整体向右移动1位。同理,对于第n为小数,相当于将此长整数整体向右移动n位。由此,每次计算都可以得到一个确定的整数和小数部分。对这些数值求和,即可以得到整数与小数部分的乘积。

    void ixd(int xi[],int ni,int yd[],intnd,int zi[],int zd[])
    {
        int i,n,carry;
        int x1[MAXLEN],x2[MAXLEN],tmp[MAXLEN];
        for(i=0;i<ni;i++)  zi[i]=0;
        for(i=0;i<nd;i++)  zd[i]=0;
        for(i=0;i<nd;i++)                                      //循环小数数字单元
        {
             mults(xi,ni,yd[nd-i-1],tmp,&n);               //整数与每个小数位上的数字相乘
             rart(tmp,n,i+1,x1,ni,x2,nd);                  //从新整数中分离出整数和小数
             carry=add_int(zd,x2,zd,nd);                  //小数累加
             zi[0]+=carry;                                      //向整数进位
             add_int(zi,x1,zi,ni);                              //整数累加
        }
    }
    
    //通过移位把一个整数分解成两个整数,分别表述整数和小数部分。这种移位计算相当于乘法运算
    void rpart(int a[],int maxn,int num,int ai[],int ni,int ad[],int nd[])
    {
         int i;
         for(i=0;i<ni;i++) ai[i]=0;
         for(i=0;i<nd;i++) ad[i]=0;
         if(num<=maxn)                                                        //缩小位数小于给定的整数长度
        {
       for(i=0;i<maxn-num;i++)     ai[i]=a[num+i];            //计算得到整数数字单元中的数字
             for(i=0;i<num;i++)     ad[nd-num+i]=a[i];             //计算得到小数数字单元中的数字
      }
         else                                                                         //此情况下,整数部分全为0
         {
               for(i=0;i<maxn;i++)   ad[nd-num+i] =a[i];          //计算得到小数数字单元中的数字
         }
    }
    

     2.两整数相乘与两小数相乘

     这两种乘法都可以使用长整数乘法来运算。整数与整数相乘的运算较简单,只需使用前面介绍的整数乘法函数运算即可。对于小数与小数相乘的运算,可以先不考虑小数点问题,把他们作为两长整数进行运算。如1.85 x 2.123,在计算时,先不考虑小数点,直接计算85 x123=10455,它表示小数乘法0.85x0.123=0.10455  两个小数相乘后仍然是小数,其位数为这两个小数位数相加,因此其长度可能超过指定的小数位长度,此时需要将低位社区,可以使用一个截断字符串函数来进行。这种截断也便于两小数相加时小数位对齐。在进行两个小数相加或相减时,必须需要注意“小数位对齐”,否则计算将出错

    //用于对长度为maxn位的数字,以左为界,取出num位数字
    	void ltruncate(int a[],int maxn,int b[],int num)
    	{
    		int i;
    		for(i=manx-1;i>=maxn-num;i++)       //以左为界,取出num位数字
    			b[i-maxn+num] =a[i];
    	}
    

      3.浮点数与浮点数相乘

    void multiply(BIGFLOAT a,BIGFLOAT b,BIGFLOAT *c)
    {
    	int yi[MAXLEN],yd[MAXLEN];
    	int xi1[MAXLEN],xd1[MAXLEN];
    	int xi2[MAXLEN],xd2[MAXLEN];
    	int nyi,nyd,carry1,carry2;
    	
    	if(a.sign==b.sign)                   //确定乘积符号
    		c->sign=0;                       //乘积为正
    	else
    		c-.sign=1;                       //乘积为负
    	
    	c->ni=a.ni;                          //确定乘积整数长度
    	c->nd=a.nd;                          //确定乘积小数长度
    	
    	multm(a.a,a.ni,b.a,b.ni,yi,&nyi);    //整数x整数
    	multm(a.d,a.nd,b.d,b.nd,yd,&nyd);    //小数x小数
    	ltruncate(yd,nyd,c->d,c->nd);        //小数位对齐
    	ixd(a.a,a.ni,b.d,b.nd,xi1,xd1);      //整数x小数
    	ixd(b.a,b.ni,a.d,a.nd,xi2,xd2);      //小数x整数
    	
    	carry1=add_int(c->d,xd1,c->d,c->nd); //关于小数部分的整数加法计算
    	carry2=add_int(c->d,xd2,c->d,c->nd); //关于小数部分的整数加法计算
    	
    	yi[0]+=carry1+carry2;                //小数部分向整数部分进位
    	add_int(yi,xi1,c->a,c->ni);          //整数加法计算
    	add_int(c->a,xi2,c->a,c->ni);        //整数加法计算
    }
    

      因此当任意给定两个高精度的浮点数后,使用以上的multily都可以计算他们的乘积

  • 相关阅读:
    方法是Objective-C独有的一种结构,只能在Objective-C中声明、定义和使用,C语言不能声明、定义和使用
    NSDate
    runtime
    iOS开发常用的工具
    程序的国际化
    经常使用的iOS SDK库和第三方库
    RunLoop是什么?
    狼若回头,必有理由
    第1年1月21日 Guard Malloc
    第1年1月10日 flv格式
  • 原文地址:https://www.cnblogs.com/Daywei/p/2383123.html
Copyright © 2020-2023  润新知