埃及乘法算法-代码优化及推导过程

书接上回:埃及乘法算法详解_who_am_i__的博客-CSDN博客

我们今天来看看如何优化改进埃及乘法算法的代码,从上回的代码中我们可以看到我们已经把原来需要计算n次的加法运算缩减到了log n次加法运算(埃及乘法算法)。但是上文中用到的是函数的递归调用,我们知道在多次递归调用函数时会有很大一部分开销。为了减去这部分开销我们要把递归调用改成迭代的形式。

首先我们用c++实现一个这样的函数:

f(r,n,a) = r + na

这里同样使用埃及乘法算法计算na,首先我们做下分析:

当n=1时:f(r,1,a) = r+a;

当n为奇数时:f(r,n,a) = f(r+a,n/2,a+a) = r+a + (n-1)/2 *2a = r + na; // 在编程中n为奇数时(n-1)/2=n/2

当n为偶数时:f(r,n,a) = f(r,n/2,a+a) = r+n/2*2a=r+na;

那么代码就显而易见了:

// 利用埃及乘法算法计算r+na;这里的odd(n)和half(n),请看上一篇博文
int mult_acc0(int r,int n, int a){
    if(n == 1) return r+a;
    if(odd(n)){
        return mult_acc0(r+a,half(n),a+a);
    }else{
        return mult_acc0(r,half(n),a+a);
    }
}

从上面的代码可以看出来当n为奇数和偶数时只有一处不同:即第一个参数:r+a和r,这样我们就可以去掉一个递归调用:

int mult_acc1(int r,int n, int a){
    if(n == 1) return r+a;
    if(odd(n)) r += a;
    return mult_acc1(r,half(n),a+a);
}

 于是这个函数就变成尾递归了,也就是说他只会在返回值里进行递归。现在我们来看该函数的另外两项特征:

n的值很少会取到1

如果n为偶数,那就没必要在判断他是不是等于1了
基于这两个特征我们可以先判断n是否为奇数,然后再判断他是不是1,这样就可以把和1的比较次数缩减为原来的一半:

int mult_acc2(int r,int n, int a){
    if(odd(n)){
        r += a;
        if(n==1) return r;
    }
    return mult_acc2(r,half(n),a+a);
}

看到这里你可能会觉得,上面讲了那么多不还是递归调用吗,而且我们要的时n*a的优化方法,你讲r+n*a有什么用呢。这个会在后续一一解答。

下面进行最终要的一步:将上述函数修改声严格的尾递归函数。严格尾递归函数:指的是那种使用与形式参数完全对应的实际参数,来进行所有递归调用的尾递归过程。

将mult_acc2转化为严格尾递归函数:

int mult_acc3(int r,int n, int a){
    if(odd(n)){
        r += a;
        if(n==1) return r;
    }
    n = half(n);
    a = a + a;
    return mult_acc3(r,n,a); // 这里的形参与实参完全对应
}

 至此,我们就可以用while(true)结构来代替尾递归了:

int mult_acc4(int r,int n, int a){
    while(true){
        if(odd(n)){    
            r += a;
            if(n==1) return r;
        }
        n = half(n);
        a = a + a;
    }
}

以上函数我们可以称之为乘法累加函数,因为r对a+a进行了累加。那么我们就可以使用上述函数计算na:

int multiply(int n,int a){
    if(n == 1) return a;
    return mult_acc4(a,n-1,a);
}

 至此已完成递归到迭代的优化。但是这种方式还存在些许问题,比如说当n时2的整数次幂时,对于mult_acc4,执行while(odd(n)){n=(n-1)/2;} n永远是个奇数,这就导致mult_acc4此时执行效率最低。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

who_am_i__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值