`
aladdin_leon
  • 浏览: 118828 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

关于数值自乘

阅读更多

      如果n与m是正整数,那么m^n就是把m连乘n次,用到了n次乘法运算,这是一个很没有效率的算法,那么我们来进行一下改进。主要思想就是减少乘法的运算次数。
      关键所在就是下面的定义式:
             当n=0时           m^n=1
             当n为偶数时   m^n=(m^k)^2
             当n为奇数时   m^n=m*(m^2k)
      所以在一个递归程序中分成3部分计算就可以了:第一部分看n是否为0;第二部分看n是否是偶数,如果是,就递归求m的n/2次方,算出的结果在平方就是答案了;第三部分看n是否为奇数,例如n=2k+1,m^(2k+1)=m*(m^2k),那么就递归去算m^2k,得出的结果在与m相乘就得到结果了。
      每一次分成两个部分(m^k或m^2k)之后,都要用一个乘法把(m^k)(m^k)或m(m^2k)算出来,在最坏的情况下,就是n是奇数,m^n=m*(m^2k),不过,m^2k却是偶数了,下一层递归就会算m^k了,然后用(m^k)(m^k)再算m^2k。因此递归的层数最多就是1+logn层,也就是乘法运算的数目,在n慢慢变大的时候,很容易知道1+logn小于n,所以这个算法的效率比连乘n次要高很多。C语言的代码如下: 

  1. unsigned long  recursive_power(unsigned long m, unsigned long n)   
  2. {   
  3.            unsigned long temp;   
  4.            if (n == 0)     
  5.                  return 1;   
  6.            else if (n & 0x01UL == 0)    
  7.            {   
  8.                  temp = recursive_power(m, n >> 1);    
  9.                  return temp * temp;   
  10.             }   
  11.             else                        
  12.                  return m * recursive_power(m, n-1);   
  13. }   

        测试程序如下面的代码所示:

  1. #include  <stdio.h></stdio.h>
  2. #include  <stdlib.h></stdlib.h>
  3. int main(void)   
  4. {   
  5.          char  line[100], *dummy_ptr;   
  6.          unsigned long m, n;   
  7.          printf("\nM^N Computation (M > 0 and N > 0)\n");   
  8.          printf("\nM   = ");   
  9.          gets(line);   
  10.           m = strtoul(line, &dummy_ptr, 10);   
  11.           printf("\nN   = ");   
  12.           gets(line);   
  13.           n = strtoul(line, &dummy_ptr, 10);   
  14.           printf("\n\nM^N = %lu", recursive_power(m, n));   
  15.           getchar();   
  16. }   

      现在问题已经解决了,但是我们如果再多想一想的话,可不可以不用递归就把问题解决呢?
      先以求m^45为例,45的二进制为101101,所以m^45=m^(1*2^5+0*2^4+1*2^3+1*2^2+0*2^1+1*2^0)=[m^(2^5)][m^(2^3)][m^(2^2)][m^(2^0)] 在101101中,值为1的那一位(比如第i位,从右往左为0,1,2,3 ...) ,在m的指数中就有m^(2^i)哪一项。正因为这个缘故,可以依次把m^(2^0)m^(2^1),... ,m^(2^i),m^(2^(i+1)),... 求出来,这正好对应着n的二进制表示中从右到左的顺序,如果在n的二进制表示中第i位是1,就把m^(2^i)乘到一个用来保存最终结果的变量中(初值为1),因此当n的每一位都查完之后,就有了答案。
      如何计算m^(2^0),m^(2^1),... ,m^(2^i),m^(2^(i+1)),... 这些数据呢?看看下面的式子:
                  m^(2^(i+1))=m^((2^i)*2)=(m^(2^i))^2
      在知道了m^(2^i)的前提下,把其平方就可以得到m^(2^(i+1))。但是m^(2^0)=m^1=m,所以求这些m^(2^i)只不过是求m的自乘而已,换句话说一开始值为m,下一次是m^2,再下次(m^2)(m^2)=m^4,接下去就是(m^4)(m^4)=m^8,... 然后就是看看如何求出n的二进制表示了。这倒是大家知道的常识了,把n用2去除的余数,就是最右面的一位,再用2去除上次得到的结果,商就是下一位了, ...
      我们通过一个表格来看一下如何算m^45:
                          n            m           temp                  说  明
           ----------------------------------------------------------------------------
                        45           m               1                     初  值
                        22         m^2            m           n为奇数,乘入temp
                        11         m^4            m           n为偶数,temp不变
                        05         m^8           m^5       n为奇数,乘入temp
                        02         m^16        m^13      n为奇数,乘入temp
                        01         m^32        m^13      n为偶数,temp不变
                        00         m^64        m^45      n为奇数,乘入temp
          ------------------------------------------------------------------------------

         C语言的代码如下:

  1. unsigned long iterative_power(unsigned long m, unsigned long n)   
  2. {   
  3.           unsigned long  temp = 1;   
  4.           while (n > 0)    
  5.           {      
  6.                 if (n & 0x01UL == 1)   
  7.                       temp *= m;        
  8.                       m *= m;                
  9.                       n >>= 1;          
  10.           }   
  11.           return temp;   
  12. }   

       这个程序的while循环最多只会绕1+logn次,每绕一次,最多作两次乘法,一次m自乘,一次m乘入temp,所以最多只做2(1+logn)次乘法,所以速度是很快的,就以m^45为例,传统连乘方式要乘44次,但是利用此算法只乘了14次。

分享到:
评论

相关推荐

    C语言数值算法初步

    其次,C语言中的算术运算符包括加(+), 减(-), 乘(*), 除(/)以及取模(%)。在数值算法中,正确理解和使用这些运算符是基础。需要注意的是,除法运算在处理整数时可能会导致结果被截断,而浮点数除法则会涉及到浮点数...

    MATLAB数值计算.zip

    1. **基本操作**:包括变量定义、数据类型(如标量、向量、矩阵和数组)、输入输出以及基本算术运算(加、减、乘、除、指数、对数等)。 2. **矩阵与数组操作**:MATLAB以矩阵为基础,支持矩阵的创建、索引、转置、...

    当数值超过long位时的加减乘算法,表达式自动运算

    在标题和描述中提到的问题,即"当数值超过long位时的加减乘算法,表达式自动运算",主要涉及了大整数运算的处理方法。 首先,我们需要理解`long`类型的局限性。在Java中,`long`类型占用64位,可以表示的整数范围是...

    C#数值计算算法源代码

    C#中的`System.Numerics.Complex`类提供了对复数的支持,包括加、减、乘、除等基本操作,以及模长、共轭等特性。源代码可能包含复数的额外操作,如极坐标转换、复数函数(如欧拉公式)等。 2. **矩阵运算**:矩阵是...

    各种类型的数值在计算机中的表示及存贮方法

    进制转换的简单运算方法包括十进制转二进制整数部分除2取余,小数部分乘2取整等。 7 二进制转十进制 从二进制数求其十进制的值,逐位码权累加求和。例如,二进制数1011.101可以转换为十进制数11.625。 8 二到八或...

    C、C++数值计算程序大全

    从提供的文件信息来看,这是一份关于C、C++数值计算程序的集合资料,该集合资料中包含了丰富的数值计算常用程序。然而,由于没有提供具体的数值计算程序实例或代码,我们无法直接对程序代码进行分析。不过,我们可以...

    论文研究 - 乘用车轮胎不均匀磨损的数值估算

    本文提出了一种预测乘用车轮胎不均匀磨损的数值技术。 通过3D图案轮胎模型的摩擦动态滚动分析,可以预测在车轮定位条件下随车速,外倾角和前束角产生的不均匀轮胎磨损。 通过油漆测试轮胎胎面表面磨损的方法来说明...

    Java数值计算算法编程

    以上是关于"Java数值计算算法编程"的一些核心知识点,实际编程中还需要根据具体需求选择合适的库和算法,确保程序的高效性和准确性。在压缩包中的"Source"文件很可能包含了各种数值计算的示例代码,可供学习和参考。

    这是用java开发的关于数值的程序

    在“这是用java开发的关于数值的程序”中,我们可以推测这个项目是专门为初学者设计的,旨在帮助他们理解如何在Java中处理和操作数值。 在Java中,数值类型主要分为两大类:基本类型(primitive types)和包装类型...

    数值分析实验讲义(MATLAB版)

    - **基本算术运算**:加(+)、减(-)、乘(*)、除(/)、指数(^)等。 - **数组与矩阵操作**:创建数组使用方括号 `[1, 2, 3]`;创建矩阵可以使用分号分隔行,如 `[1, 2; 3, 4]`。 - **函数调用**:如 `sin(x)` ...

    常用十大数值算法(数学建模有用)

    通过对矩阵多次自乘,逐渐逼近最大或最小特征值。 7. **牛顿迭代法**:牛顿法是求解非线性方程根的一种迭代方法,利用函数的切线来逼近根。其速度快且收敛性好,但要求函数的导数信息。 8. **高斯-赛德尔迭代法**...

    数值分析实验,报告数值分析实验,报告

    实验中,代码首先通过`size(A)`确定矩阵的维度,然后通过循环进行行交换和行倍乘操作,确保主对角线元素非零,并消除下方元素。最后,通过回代求得解。 2. 列主元消去法:这是一种优化的消元法,旨在减少计算过程中...

    VC/BC数值分析类库

    在这个类库中,开发者可以找到用于执行基本算术运算(如加、减、乘、除)以及更复杂的函数(如指数、对数、平方根)的函数。 2. 矩阵运算:矩阵是线性代数的基础,广泛应用于工程、物理、经济等领域。类库提供了...

    色环电阻包括颜色、对应数值、应乘位数

    根据给定内容,我们可以清晰地看到每个颜色环所对应的数值含义: - **黑色**:代表0,乘数为X10^0。 - **棕色**:代表1,乘数为X10^1,误差率为±1%,温度系数为100ppm/°C。 - **红色**:代表2,乘数为X10^2,误差...

    VB常用数值算法集源代码.rar

    首先,**基本数学运算**是所有数值计算的基础,VB提供了内建的数学函数以执行简单的加、减、乘、除等操作。此外,利用VB提供的自定义子程序,开发者可以实现更加复杂的数学运算,如模运算和幂运算等。这些基本操作在...

    C++经典数值算法源码

    C++提供了`&lt;complex&gt;`库支持复数操作,包括加、减、乘、除、共轭等基本运算,以及复数的模、幅角和极坐标表示。 3. **矩阵特征值与特征向量的计算**:在量子力学、控制理论等学科中,理解一个矩阵的特征值和特征...

    vb常用数值算法集原代码

    VB提供了复数类型,可以进行复数的加、减、乘、除及开方等操作。 8. **随机数生成**:在模拟和统计计算中,需要生成随机数。VB提供了Randomize和Rnd函数,可以生成0到1之间的伪随机数。 9. **数值优化**:如梯度...

    MATLAB的数值计算

    矩阵自乘`p`次。 - 如果`p`不是整数,则可能涉及到特征值和特征向量。 除了上述基础运算,MATLAB还支持更复杂的运算,如矩阵的转置、逆、行列式、秩、特征值、特征向量等,以及各种数值解法,如解线性方程组的`\`...

    数值分析第五版习题答案

    例如,如果的相对误差为,那么的误差可以通过乘以来求得。同时,我们还学习了如何计算近似值的误差限,这对于评估计算精度至关重要。 2. 条件数:函数的条件数反映了输入变化对输出影响的敏感程度。例如,如果函数...

Global site tag (gtag.js) - Google Analytics