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)
将乘以x
和y
并将结果存储在乘法后的值。
我只是想知道两个"如果条件"在while循环中工作,while循环何时终止,以及片段的时间复杂度。
答案 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 为
但由于15 =(4 + 1)* 3,31 = 15 * 2 + 1 =((4 + 1)* 3)* 2 + 1和31 = 7 * 4 + 3 =(3 * 2 + 1)* 4 + 3我们也可以写:
所有都需要比二进制求幂少一个乘法。 (最终的表达式需要缓存中间结果x 3 ,以避免计算两次。)我不知道我的x 31 的表达式是否是最优的。即使对于数量很少的人来说,找到最佳表达也是非常困难的。您必须查看可以表达x n 的所有不同方式,请记住,只需要计算一次公共中间结果。如上所述,这是NP难的。在实践中,二进制求幂虽然不是最优的,但已经足够好了。
答案 1 :(得分:0)
b & 1
测试b是否为奇数。如果是,则result
设置为tmp * power
。
b >>= 1
将b除以2.如果结果非零,则tmp
设置为power
,power
设置为tmp * tmp
。
最终,b
被除以2以至于达到零,结束while
循环。
该算法是所谓的" Russian Peasant multiplication"的推广。叫" Exponentiation by squaring"。通过对中间结果(我们在第二个if
测试中看到)进行平方而不是加倍,可以使用相同的基本过程进行取幂而不是乘法。
时间复杂度与b
中的最高设置位成比例;如果b
中的最高设置位为位 K ,则循环将迭代 K 次。也就是说,时间复杂度与b的基数2对数成比例。