实现基于整数的幂函数的最有效方法pow(int,int)
给C中的另一个整数赋予整数的最有效方法是什么?
// 2^3 pow(2,3) == 8 // 5^5 pow(5,5) == 3125
指数乘以平方。
int ipow(int base, int exp) { int result = 1; while (exp) { if (exp & 1) result *= base; exp >>= 1; base *= base; } return result; }
这是在非对称密码学中对大数进行模幂运算的标准方法。
请注意, 通过平方的指数并不是最优的方法。 对于所有指数值,这可能是您可以做的最好的一种常规方法,但对于特定的指数值,可能会有更好的序列,需要更less的乘法。
例如,如果你想计算x ^ 15,平方的幂乘方法会给你:
x^15 = (x^7)*(x^7)*xx^7 = (x^3)*(x^3)*xx^3 = x*x*x
这是总共6次乘法。
事实certificate,这可以通过使用“正好”5乘法通过加法链求幂来完成 。
n*n = n^2 n^2*n = n^3 n^3*n^3 = n^6 n^6*n^6 = n^12 n^12*n^3 = n^15
没有有效的algorithm来find这个最佳的乘法序列。 维基百科 :
寻找最短加法链的问题不能通过dynamic规划来解决,因为它不能满足最优子结构的假设。 也就是说,将功率分解成更小的功率是不够的,每个功率的计算最小,因为较小功率的加法链可能是相关的(以共享计算)。 例如,在上述第十五条的最短加法链中,由于a³被重新使用(相对于a⁶=a²(a²)2),a⁶的子问题必须计算为(a³)²,这也需要三次相乘)。
这是Java中的方法
private int ipow(int base, int exp) { int result = 1; while (exp != 0) { if ((exp & 1) == 1) result *= base; exp >>= 1; base *= base; } return result; }
如果你需要提高2的权力。 最快的方法是通过权力位移。
2 ** 3 == 1 << 3 == 8 2 ** 30 == 1 << 30 == 1073741824 (A Gigabyte)
int pow( int base, int exponent) { // Does not work for negative exponents. (But that would be leaving the range of int) if (exponent == 0) return 1; // base case; int temp = pow(base, exponent/2); if (exponent % 2 == 0) return temp * temp; else return (base * temp * temp); }
如果你想得到一个2的整数的值提高到某个东西的强度,最好使用shift选项:
pow(2,5)
可以被1<<5
代替
这是更有效率。
一个非常特殊的情况是,当你需要对y表示2 ^( – x)时,其中x当然是负数,y太大而不能在int上移位。 你还可以用一个浮子来连续做2 ^ x。
struct IeeeFloat { unsigned int base : 23; unsigned int exponent : 8; unsigned int signBit : 1; }; union IeeeFloatUnion { IeeeFloat brokenOut; float f; }; inline float twoToThe(char exponent) { // notice how the range checking is already done on the exponent var static IeeeFloatUnion u; uf = 2.0; // Change the exponent part of the float u.brokenOut.exponent += (exponent - 1); return (uf); }
通过使用double作为基types,可以获得更多的2的幂。 (非常感谢评论者帮助把这篇文章打散)。
也有可能学习更多的关于IEEE浮点数 ,其他特殊情况下的指数可能会出现。
正如跟随平方的效率幂的评论。
这种方法的优点是它在log(n)时间运行。 例如,如果你打算计算一些很大的东西,比如x ^ 1048575(2 ^ 20 – 1),那么你只需要循环20次,而不是100万次。
而且,就代码复杂性而言,比试图find最佳的乘法序列还要简单,就是Pramod的build议。
编辑:
我想我应该澄清之前有人标记我的溢出的可能性。 这种方法假定你有某种巨大的库。
power()
函数仅适用于整数
int power(int base, unsigned int exp){ if (exp == 0) return 1; int temp = power(base, exp/2); if (exp%2 == 0) return temp*temp; else return base*temp*temp; }
复杂性= O(log(exp))
power()
函数为负exp和float基础工作 。
float power(float base, int exp) { if( exp == 0) return 1; float temp = power(base, exp/2); if (exp%2 == 0) return temp*temp; else { if(exp > 0) return base*temp*temp; else return (temp*temp)/base; //negative exponent computation } }
复杂性= O(log(exp))
晚会之后:
下面是一个解决scheme,也尽可能处理y < 0
。
- 它使用
intmax_t
的结果来获得最大范围。 没有规定不适合intmax_t
答案。 -
powjii(0, 0) --> 1
这是这种情况下常见的结果 。 -
pow(0,negative)
是另一个未定义的结果,返回INTMAX_MAX
intmax_t powjii(int x, int y) { if (y < 0) { switch (x) { case 0: return INTMAX_MAX; case 1: return 1; case -1: return y % 2 ? -1 : 1; } return 0; } intmax_t z = 1; intmax_t base = x; for (;;) { if (y % 2) { z *= base; } y /= 2; if (y == 0) { break; } base *= base; } return z; }
此代码使用for(;;)
的永久循环来避免其他循环解决scheme中的最终base *= base
。 这个乘法是1)不需要和2)可以是int*int
溢出这是UB。
一个更多的实现(Java)。 可能不是最有效的解决scheme,但迭代次数与指数解决scheme相同。
public static long pow(long base, long exp){ if(exp ==0){ return 1; } if(exp ==1){ return base; } if(exp % 2 == 0){ long half = pow(base, exp/2); return half * half; }else{ long half = pow(base, (exp -1)/2); return base * half * half; } }
考虑负指数的更通用的解决scheme
private static int pow(int base, int exponent) { int result = 1; if (exponent == 0) return result; // base case; if (exponent < 0) return 1 / pow(base, -exponent); int temp = pow(base, exponent / 2); if (exponent % 2 == 0) return temp * temp; else return (base * temp * temp); }
我已经实现了记忆所有计算能力的algorithm,然后在需要时使用它们。 因此,例如x ^ 13等于(x ^ 2)^ 2 ^ 2 * x ^ 2 ^ 2 * x其中x ^ 2 ^ 2从表中取而不是再次计算它。 所需的乘法次数是Ceil(Log n)
public static int Power(int base, int exp) { int tab[] = new int[exp + 1]; tab[0] = 1; tab[1] = base; return Power(base, exp, tab); } public static int Power(int base, int exp, int tab[]) { if(exp == 0) return 1; if(exp == 1) return base; int i = 1; while(i < exp/2) { if(tab[2 * i] <= 0) tab[2 * i] = tab[i] * tab[i]; i = i << 1; } if(exp <= i) return tab[i]; else return tab[i] * Power(base, exp - i, tab); }
我使用recursion,如果exp是偶数,5 ^ 10 = 25 ^ 5。
int pow(float base,float exp){ if (exp==0)return 1; else if(exp>0&&exp%2==0){ return pow(base*base,exp/2); }else if (exp>0&&exp%2!=0){ return base*pow(base,exp-1); } }
我的情况有点不同,我试图用权力来创build一个面具,但我想我会分享我find的解决scheme。
显然,它只适用于2的权力。
Mask1 = 1 << (Exponent - 1); Mask2 = Mask1 - 1; return Mask1 + Mask2;
我已经find了一个比起for循环这个巨大的开关语句有点快的方法。 好吧,也许这不是最简单的方法,但有一个范围从-50(或另一个数字,取决于您的需要)到+50的交换机,并在每个有像return number * number * ...; break;
return number * number * ...; break;
等等。 对于具有双精度数字的1M运行,这需要0.001秒。 对于整数它更快。 你可以在这里find一个示例标题
我能想到的唯一缺陷就是caching内存,有这样一个大声明你可能会遇到一些问题,但这只是假设。
但是,您仍然可以限制交换机的大小,通常功率不会高于20-25。
忽略2的特殊情况下,最有效的方法将是简单的迭代。
int pow(int base, int pow) { int res = 1; for(int i=pow; i<pow; i++) res *= base; return res; }
编辑:正如已经指出,这不是最有效的方式…只要你定义效率作为CPU周期,我认为是公平的。