c语言float幂函数pow,c - 实现基于整数的幂函数pow(int,int)的最有效方法

c - 实现基于整数的幂函数pow(int,int)的最有效方法

将整数提升到C中另一个整数的幂的最有效方法是什么?

// 2^3

pow(2,3) == 8

// 5^5

pow(5,5) == 3125

17个解决方案

356 votes

通过平方来表示。

int ipow(int base, int exp)

{

int result = 1;

for (;;)

{

if (exp & 1)

result *= base;

exp >>= 1;

if (!exp)

break;

base *= base;

}

return result;

}

这是在非对称加密中对大量数进行模幂运算的标准方法。

Elias Yarrkov answered 2019-02-25T00:02:03Z

57 votes

请注意,通过平方取幂不是最佳方法。 作为适用于所有指数值的通用方法,它可能是最好的,但对于特定的指数值,可能有更好的序列需要更少的乘法。

例如,如果你想计算x ^ 15,通过平方取幂的方法将给你:

x^15 = (x^7)*(x^7)*x

x^7 = (x^3)*(x^3)*x

x^3 = x*x*x

这是总共6次乘法。

事实证明,这可以通过加法链取幂使用“仅”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

没有有效的算法来找到这种最佳乘法序列。 来自维基百科:

寻找最短加法链的问题不能通过动态规划来解决,因为它不满足最优子结构的假设。 也就是说,将功率分解成较小的功率是不够的,每个功率都是最小的,因为较小功率的加法链可能是相关的(共享计算)。 例如,在上面a¹的最短加法链中,a⁶的子问题必须计算为(a³)²,因为a³被重新使用(相反,例如a⁶=a²(a²)²,这也需要三次乘法)。

Pramod answered 2019-02-25T00:03:02Z

15 votes

如果你需要提高2到一个功率。 这样做的最快方法是按功率移位。

2 ** 3 == 1 << 3 == 8

2 ** 30 == 1 << 30 == 1073741824 (A Gigabyte)

Jake answered 2019-02-25T00:03:25Z

15 votes

这是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;

}

user1067920 answered 2019-02-25T00:03:49Z

7 votes

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);

}

Chris Cudmore answered 2019-02-25T00:04:06Z

6 votes

如果你想得到一个2的整数值,那么使用shift选项总是更好:

pow(2,5)可以替换为1<<5

这样效率更高。

aditya answered 2019-02-25T00:04:44Z

6 votes

一个非常专业的情况是,当你需要说2 ^( - x到y)时,其中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;

u.f = 2.0;

// Change the exponent part of the float

u.brokenOut.exponent += (exponent - 1);

return (u.f);

}

通过使用double作为基本类型,您可以获得更多2的幂。(非常感谢评论者帮助解决这个问题)。

还有可能更多地了解IEEE浮点数,其他特殊的取幂情况可能会出现。

Doug T. answered 2019-02-25T00:05:22Z

4 votes

正如通过平方对关于取幂效率的评论的后续跟进。

该方法的优点是它在log(n)时间内运行。 例如,如果你要计算一些巨大的东西,比如x ^ 1048575(2 ^ 20 - 1),你只需要通过循环20次,而不是100万+使用天真的方法。

此外,就代码复杂性而言,它比尝试找到最佳乘法序列更简单,这是la Pramod的建议。

编辑:

我想在有人给我标记溢出的可能性之前我应该澄清一下。 这种方法假设您有某种hugeint库。

Jason Z answered 2019-02-25T00:06:08Z

4 votes

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 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))

roottraveller answered 2019-02-25T00:06:48Z

2 votes

晚会:

以下解决方案也尽可能地处理intmax_t。

它使用intmax_t的结果作为最大范围。 没有规定不适合intmax_t的答案。

for(;;)这是本案的常见结果。

for(;;),另一个未定义的结果,返回base *= base

for(;;)

此代码使用永久循环for(;;)以避免在其他循环解决方案中常见的最终base *= base。 乘法是1)不需要和2)可能是int*int溢出,这是UB。

chux answered 2019-02-25T00:07:53Z

1 votes

另一个实现(在Java中)。 可能不是最有效的解决方案,但迭代次数与指数解决方案相同。

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;

}

}

Vaibhav Fouzdar answered 2019-02-25T00:08:20Z

1 votes

考虑负指数的更通用的解决方案

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);

}

Abhijit Gaikwad answered 2019-02-25T00:08:45Z

1 votes

我已经实现了算法来记忆所有计算的功率,然后在需要时使用它们。 因此,例如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);

}

rank1 answered 2019-02-25T00:09:12Z

0 votes

我使用递归,如果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);

}

}

kyorilys answered 2019-02-25T00:09:36Z

0 votes

我的情况有点不同,我正试图用力量创造一个面具,但我想我会分享我找到的解决方案。

显然,它仅适用于2的幂。

Mask1 = 1 << (Exponent - 1);

Mask2 = Mask1 - 1;

return Mask1 + Mask2;

MarcusJ answered 2019-02-25T00:10:08Z

0 votes

如果您在编译时知道指数(并且它是一个整数),您可以使用模板来展开循环。 这可以提高效率,但我想在这里展示基本原理:

#include

template

unsigned long inline exp_unroll(unsigned base) {

return base * exp_unroll(base);

}

我们使用模板特化来终止递归:

template<>

unsigned long inline exp_unroll<1>(unsigned base) {

return base;

}

指数需要在运行时知道,

int main(int argc, char * argv[]) {

std::cout << argv[1] <(atoi(argv[1])) << ;std::endl;

}

Johannes Blaschke answered 2019-02-25T00:10:48Z

-4 votes

忽略2提升到幂的特殊情况,最有效的方法是简单的迭代。

int pow(int base, int pow) {

int res = 1;

for(int i=pow; i

res *= base;

return res;

}

编辑:正如已经指出的那样,这不是最有效的方式......只要你将效率定义为cpu周期,我认为这是足够公平的。

bfabry answered 2019-02-25T00:11:20Z

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值