任何人都可以解释下面的代码片段吗?

时间:2015-08-05 03:55:10

标签: c++ c

void dec_exp(Decimal *result, const Decimal *a, unsigned int b)
    {
        Decimal tmp, power = *a;
        dec_parse(result, "1");
        while (b)
        {
            if (b & 1)
            {
                tmp = *result;
                dec_mul(result, &tmp, &power);
            }
            if (b >>= 1)
            {
                tmp = power;
                dec_mul(&power, &tmp, &tmp);
            }
    }
}

其中Decimal是包含小数值的结构变量,它的长度和小数点所在的位置。

在函数中传递参数:a是基值,b是幂。并且result将在计算后存储值a ^ b。

dec_parse(Decimal &x,string y)y解析为十进制并提取信息,如小数点位置,修剪前导零和尾随零,并将字符串转换为Decimal结构变量。

dec_mul(Decimal result, Decimal &x, Decimal &y)将乘以xy并将结果存储在乘法后的值。

我只是想知道两个"如果条件"在while循环中工作,while循环何时终止,以及片段的时间复杂度。

2 个答案:

答案 0 :(得分:0)

(*a)是非负整数的特殊情况下计算b b

变量result初始化为一(注意a 0 是所有a的一个)并且power被初始化为a的内容。如果result为奇数(第一个power),则每次循环都会b乘以if。第二个if右移b一位(即除以二),如果仍然为正,则为power。换句话说,power包含越来越大的(*a) 2 n 值。

这是一种用于计算 b 的相当有效且易于实现(但不是最佳)的算法。最优算法是NP-hard并且(可能)需要大量内存。该算法易于编码,只需要很少的内存。

忽略多余的乘法,此算法最适合b = 0到b = 14。它在a 15 中不是最理想的。此算法计算为a 15 a * a 2 * a 4 * a 8 ,或六次乘法。最优计算(对decimal的调用次数最少的计算)为a 3 = a * a * {{1} }; a 15 = a 3 *((a 3 2 2 ,或五次乘法。

此算法的另一个名称是从右到左的二进制求幂。它之所以称之为是因为它从a的最右边的位(1位)开始,并逐渐处理b的更高有效位。换句话说,它从左到右工作。从左到右的二进制求幂从b的最高有效位开始,并且在b的逐渐不太重要的位上工作。在将多余的乘法消除为1之后,两种算法都使用完全相同的乘法次数。

这不是"最佳"算法,其中最优意味着最少的乘法次数"。例如,从右到左和从左到右的二进制求幂算法计算x 15 和x 31

  • x 15 = x * x 2 * x 4 * x 8 =((x 2 * x) 2 * x) 2 * x(分别是从右到左和从左到右)
  • x 31 = x * x 2 * x 4 * x 8 * x 16 =((x 2 * x) 2 * x) 2 * x) 2 * X

但由于15 =(4 + 1)* 3,31 = 15 * 2 + 1 =((4 + 1)* 3)* 2 + 1和31 = 7 * 4 + 3 =(3 * 2 + 1)* 4 + 3我们也可以写:

  • x 15 =(x 4 * x) 3
  • x 31 =((x 4 * x) 3 2 * x
  • x 31 =(((x 3 2 * x) 4 )* x 3

所有都需要比二进制求幂少一个乘法。 (最终的表达式需要缓存中间结果x 3 ,以避免计算两次。)我不知道我的x 31 的表达式是否是最优的。即使对于数量很少的人来说,找到最佳表达也是非常困难的。您必须查看可以表达x n 的所有不同方式,请记住,只需要计算一次公共中间结果。如上所述,这是NP难的。在实践中,二进制求幂虽然不是最优的,但已经足够好了。

答案 1 :(得分:0)

b & 1测试b是否为奇数。如果是,则result设置为tmp * power

b >>= 1将b除以2.如果结果非零,则tmp设置为powerpower设置为tmp * tmp

最终,b被除以2以至于达到零,结束while循环。

该算法是所谓的" Russian Peasant multiplication"的推广。叫" Exponentiation by squaring"。通过对中间结果(我们在第二个if测试中看到)进行平方而不是加倍,可以使用相同的基本过程进行取幂而不是乘法。

时间复杂度与b中的最高设置位成比例;如果b中的最高设置位为位 K ,则循环将迭代 K 次。也就是说,时间复杂度与b的基数2对数成比例。