如何以有效的方式计算能量

时间:2014-11-16 06:24:17

标签: c function

给出f(N)= 1 ^ 1 * 2 ^ 2 * 3 ^ 3 ..... N ^ N的函数。我必须计算f(N)/ f(r)* f(N-r)。 我的c代码如下所示,但它适用于小N,如5或6.

#include<stdio.h>

unsigned long long power(long x, long y)
{
    unsigned long long temp;
    if( y == 0)
        return 1;
    temp = power(x, y/2);
    if (y%2 == 0)
        return temp*temp;
    else
        return x*temp*temp;
}

int main(){
    unsigned long long N,M,Q,r[100001],j;
    int t,i;
    scanf("%d",&t);
    while(t--){
        scanf("%llu%llu%llu",&N,&M,&Q);
        for(i=0;i<Q;i++)
            scanf("%llu",&r[i]);
        for(i=0;i<Q;i++){
         unsigned long long mult=1;
           for(j=2;j<=N;j++){
              mult=mult*(power(j,j));
        }
           unsigned long long mult1=mult;
            mult=1;
          //unsigned long long ans=mult/((power(r[i],r[i]))*(power((N-r[i]),(N-r[i]))));
            for(j=2;j<=r[i];j++)
                mult=mult*(power(j,j));
            unsigned long long mult2=mult;
            mult=1;
            for(j=2;j<=N-r[i];j++)
                mult=mult*(power(j,j));
            unsigned long long mult3=mult;
           mult=1;
            unsigned long long ans=mult1/(mult2*mult3);
            printf("%llu\n",ans%M);
        }
    }
    return 0;
}

假设,f(5)= 1 ^ 1 * 2 ^ 2 * 3 ^ 3 * 4 ^ 4 * 5 ^ 5 = 86400000.if N非常大N <= 10 ^ 5.然后如何存储这样的一个很大的价值。任何人都可以给我一个有效的算法来找到这个值并将其存储在任何array.thanks中。

3 个答案:

答案 0 :(得分:1)

对于无符号整数指数,它主要只是重复乘法的简写(例如x^9x*x*x*x*x*x*x*x*x)。

要有效地计算它(减少乘法次数),您可以使用临时计算。例如,对于x*x*x*x*x*x*x*x*x,您可以计算y = x*x并执行y*y*y*y*x;这是5次乘法而不是8次。您还可以y = x*x然后z = y*y然后z*z*x将其降低到4次乘法。

事实证明,二进制文件很棒,并且很容易找到所需的最少乘法次数 - 指数的二进制数字告诉你。

更具体地说,(对于无符号整数指数,忽略溢出),这有效:

    result = 1;
    temp = x;
    while( exponent != 0) {
        if( (exponent & 1) != 0) {
            result *= temp;
        }
        exponent >>= 1;
        temp *= temp;
    }
    return result;

当然溢出将是一个问题。对于大数字,您将需要某种可用于乘法的“大整数”代码(其中tempresult变量都是“大整数”)。

“大整数”通常只是一个(可变长度)整数数组,其中数组的每个元素表示大基数中的一个数字(例如,对于32位数字,“base 4294967296”)。如果你想自己实现它,我相信你可以找到乘法和除法的算法;如果不这样做,或者是合适的C库。

另一种选择是使用浮点。我建议不要将其用于近似值,因为在处理大数字时会导致精度损失(并且“非常大的数字”仍会出现溢出)。

答案 1 :(得分:0)

你可以尝试:

unsigned long long power(long x, long y)
{
    if( 0 == y ) return 1;
    if( 1 == y ) return x;

    unsigned long long result = x;
    for(long i = 2; i < y; i++ )
    {
        result *= x;
    }
    return( result );
}

答案 2 :(得分:0)

你有快速指数函数:

unsigned long long fastpow(unsigned long long a, int b)
{
    unsigned long long res = 1;
    while (b) {
        if (b & 1) res *= a;
        b >>= 1;
        a *= a;
    }
    return res;
}

它通常用于加密环境,但可以在这里使用。

正如我在评论中所说,你试图写的功能比事实(N)更快,所以你将无法计算出你在问题中放置的范围(10 ^ 5)会得到足够大的数字,以免它们在任何地方都很容易适应。

使用unsigned long long结果,您只能进入:

f(0) -> 1
f(1) -> 1
f(2) -> 4
f(3) -> 108
f(4) -> 27648
f(5) -> 86400000
f(6) -> 4031078400000
f(7) -> 3319766398771200000
f(8) -> overflows in 64 bit.