所以我正在尝试实现一种更有效的计算2^n
的方法。
我知道您可以将其拆分为O(logn)
并且使用递归很容易。你继续除以2,然后乘以奇数(或类似的东西)时的较低功率。问题是我用手写出了我的乘法方法,因为它的数字很大。所以它需要返回多个参数。
我能想到的一个解决方案是制作一个包含所有必需信息的对。除此之外我虽然试图弄清楚如何使用迭代来编写它。我能看到的唯一方法是使用某种数据结构,然后循环将n除以2,并在n为奇数时存储该值。然后编写for循环并在每次迭代时检查该值是否包含在数据结构中。在我看来,这似乎是一项相对昂贵的操作。
它最终可能会比递归版本效率低吗?
我这样做是因为:
答案 0 :(得分:6)
如果你打算使用大数字,而不是重新发明轮子,你可能应该看一下GNU MP Bignum Library。
关于递归与迭代问题,答案是你总是可以把它们写成等价的;一个仅将自身称为tail call的递归函数与while循环一样高效(只要您的编译器支持尾调用优化,但最常见的编译器)。例如,您正在描述的快速取幂函数的尾递归版本是(伪代码):
function fastExp(base, exponent, accumulator) {
if(exponent == 0) {
return accumulator;
} else if(exponent % 2 == 0) {
return fastExp(base * base, exponent/2, accumulator);
} else {
return fastExp(base, exponent-1, base * accumulator);
}
}
将此递归函数视为循环,其中循环条件为exponent != 0
,并且递归调用类似于循环开始时的goto
。 (顺便说一下,当你开始时,你需要用accumulator = 1
来调用它。)它等同于以下内容:
function fastExp(base, exponent) {
var accumulator = 1;
while(exponent != 0) {
if(exponent % 2 == 0) {
base *= base;
exponent /= 2;
} else {
exponent -= 1;
accumulator *= base;
}
}
return accumulator;
}
因此,您可以看到它们是等效的,因此将执行相同数量的操作。
答案 1 :(得分:0)
如果您将所有内容存储为 1 s和 0 s..ie。二进制格式的序列,则2 ^ n是只需 0 的序列,前面有单个1 ,也许您可以使用fact来简单地编写代码
2^1 = 10
2^2 = 100
2^3 = 1000
2^4 = 10000
等等,除非这是一个学习练习,否则我会选择标准的任意精度库,就像Philippe建议的那样