判断一个数是否为素数(二)

2013-07-23 09:09:03 · 作者: · 浏览: 2059


    4.快速计算乘方的算法
    如计算2^13,则传统做法需要进行12次乘法。
    [cpp]
    /*计算n^p*/
    unsigned power(unsigned n,unsigned p)
    {
    for(int i=0;i<p;i++) n*=n;
    return n;
    }
    /*计算n^p*/
    unsigned power(unsigned n,unsigned p)
    {
    for(int i=0;i<p;i++) n*=n;
    return n;
    }
    该死的乘法,是时候优化一下了!把2*2的结果保存起来看看,是不是成了:
    4*4*4*4*4*4*2
    再把4*4的结果保存起来:16*16*16*2
    一共5次运算,分别是2*2、4*4和16*16*16*2
    这样分析,我们算法因该是只需要计算一半都不到的乘法了。
    为了讲清这个算法,再举一个例子2^7:2*2*2*2*2*2*2
    两两分开:(2*2)*(2*2)*(2*2)*2
    如果用2*2来计算,那么指数就可以除以2了,不过剩了一个,稍后再单独乘上它。
    再次两两分开,指数除以2: ((2*2)*(2*2))*(2*2)*2
    实际上最后一个括号里的2 * 2是这回又剩下的,那么,稍后再单独乘上它 现在指数已经为1了,可以计算最终结果了:16*4*2=128
    优化后的算法如下:
    [cpp]
    unsigned Power(unsigned n,unsigned p)
    {
    unsigned main=n; //用main保存结果
    unsigned odd=1; //odd用来计算"剩下的"乘积
    while (p>1)
    {//一直计算,直到指数小于或等于1
    if((p%2)!=0)
    {// 如果指数p是奇数,则说明计算后会剩一个多余的数,那么在这里把它
    乘到结果中
    odd*=main; //把"剩下的"乘起来
    }
    main*=main; //主体乘方
    p/=2; //指数除以2
    }
    return main*odd; //最后把主体和"剩下的"乘起来作为结果
    }
    unsigned Power(unsigned n,unsigned p)
    {
    unsigned main=n; //用main保存结果
    unsigned odd=1; //odd用来计算"剩下的"乘积
    while (p>1)
    {//一直计算,直到指数小于或等于1
    if((p%2)!=0)
    {// 如果指数p是奇数,则说明计算后会剩一个多余的数,那么在这里把它
    乘到结果中
    odd*=main; //把"剩下的"乘起来
    }
    main*=main; //主体乘方
    p/=2; //指数除以2
    }
    return main*odd; //最后把主体和"剩下的"乘起来作为结果
    }
    够完美了吗?不,还不够!看出来了吗?main是没有必要的,并且我们可以有更快的代码来判断奇数。要知道除法或取模运算的效率很低,所以我们可以利用偶数的一个性质来优化代码,那就是偶数的二进制表示法中的最低位一定为0!
    完美版:
    [cpp]
    unsigned Power(unsigned n, unsigned p)
    { // 计算n的p次方
    unsigned odd = 1; //oddk用来计算"剩下的"乘积
    while (p > 1)
    { // 一直计算到指数小于或等于1
    if (( p & 1 )!=0)
    { // 判断p是否奇数,偶数的最低位必为0
    odd *= n; // 若odd为奇数,则把"剩下的"乘起来
    }
    n *= n; // 主体乘方
    p /= 2; // 指数除以2
    }
    return n * odd; // 最后把主体和"剩下的"乘起来作为结果
    }
    unsigned Power(unsigned n, unsigned p)
    { // 计算n的p次方
    unsigned odd = 1; //oddk用来计算"剩下的"乘积
    while (p > 1)
    { // 一直计算到指数小于或等于1
    if (( p & 1 )!=0)
    { // 判断p是否奇数,偶数的最低位必为0
    odd *= n; // 若odd为奇数,则把"剩下的"乘起来
    }
    n *= n; // 主体乘方
    p /= 2; // 指数除以2
    }
    return n * odd; // 最后把主体和"剩下的"乘起来作为结果
    }
    ========================================================