C 花太多时间处理大量数据

C 花太多时间处理大量数据,c,time-complexity,C,Time Complexity,非负整数N的阶乘,表示为N!,是所有小于等于N的正整数的乘积。任何数的阶乘都可以用其素因子的最简单形式表示。e、 g.4=4*3*2*1=2^3*3^1阶乘也可以通过每个素因子在其中出现的次数来指定,因此24可以指定为3 1,表示3 2,1 3。 我写的代码给出了小数字的答案,但当数字变大时,程序不会返回答案 #include<stdio.h> long fact(long n) { if(n==0) return 1; else r

非负整数N的阶乘,表示为N!,是所有小于等于N的正整数的乘积。任何数的阶乘都可以用其素因子的最简单形式表示。e、 g.4=4*3*2*1=2^3*3^1阶乘也可以通过每个素因子在其中出现的次数来指定,因此24可以指定为3 1,表示3 2,1 3。 我写的代码给出了小数字的答案,但当数字变大时,程序不会返回答案

#include<stdio.h>

long fact(long n)
{
    if(n==0)
        return 1;
    else
        return(n*fact(n-1));
}

int main()
{
    long a[10]={0};
    long n,l=0,count=0,i,j,flag;
    if(!scanf("%ld",&n))
    {
        printf("Invalid input");
        goto l1;
    }

    if(n<0)
    {
        printf("Invalid input");
        goto l1;
    }

    n=fact(n);

    while(n%2==0)
    {
        count++;
        n=n/2;
    }

    a[l]=count;
    l++;

    for(i=2;i<=n;i++)
    {
        count=0;
        j=2;
        flag=0;
        while(j<i)
        {
            if(i%j==0)
            {
                flag=0;
                break;
            }
            else
                flag=1;
            j++;

        }

        if(flag==1)
        {
            count=0;
            while(n%i==0)
            {
                count++;
                n=n/i;
            }
            a[l]=count;
            l++;
        }
    }

    for(i=0;i<l;i++)
        printf("%ld ",a[i]);

l1:return 0;

}

对于大数的因式分解没有有效的算法。 虽然可能不是您所期望的答案,但请查看维基百科:

对于大数的因式分解,没有有效的算法。 虽然可能不是您所期望的答案,但请查看维基百科:

您不能存储n!价值,即使在很长的一段时间内,结果增长非常快。您应该修改您的算法:计算从2到n的每个数字的素因子分解,并递归地添加n-1、n-2的分解

例如,假设您使用10!进行此操作!。省略1

现在,主要因素是这些

这意味着10!相当于:

2 * 3 * 2 * 2 * 5 * 2 * 3 * 7 * 2 * 2 * 2 * 3 * 3 * 2 * 5
从上面的项中累加每个素数的计数,我们得到以下结果,^表示幂运算,而不是XOR的C运算符

2^8 * 3^4 * 5^2 * 7^1
所以答案是8421。检查我们的工作,我们得到:

2^8 = 256
3^4 = 81
5^2 = 25
7^1 = 7

7 * 25 * 81 * 256 = 3628800
我的计算器告诉我

10! = 3628800
因此,该算法是正确的。最后请注意,在任何时候我们都不需要对大于n的任何数字进行素数因子运算,在本例中为10


注意:避免gotos

您不能存储n!价值,即使在很长的一段时间内,结果增长非常快。您应该修改您的算法:计算从2到n的每个数字的素因子分解,并递归地添加n-1、n-2的分解

例如,假设您使用10!进行此操作!。省略1

现在,主要因素是这些

这意味着10!相当于:

2 * 3 * 2 * 2 * 5 * 2 * 3 * 7 * 2 * 2 * 2 * 3 * 3 * 2 * 5
从上面的项中累加每个素数的计数,我们得到以下结果,^表示幂运算,而不是XOR的C运算符

2^8 * 3^4 * 5^2 * 7^1
所以答案是8421。检查我们的工作,我们得到:

2^8 = 256
3^4 = 81
5^2 = 25
7^1 = 7

7 * 25 * 81 * 256 = 3628800
我的计算器告诉我

10! = 3628800
因此,该算法是正确的。最后请注意,在任何时候我们都不需要对大于n的任何数字进行素数因子运算,在本例中为10


注意:避免走投无路有两个主要障碍:

一个长的,甚至是一个无符号的长不足以容纳大多数数字的阶乘。long通常存储32位,尽管这在不同的体系结构中可能有所不同,这允许我们存储小于2**32-1的数字,即大约40亿。13! 已经比这个大了

太多的递归调用可能会严重影响性能,因为当编译器不进行尾部递归优化时,在调用堆栈中为函数分配空间会产生开销

更好的解决方案是,要么使用可以增长到任意大小的大整数,要么使用双精度浮点数,并使用迭代解找到近似解


另一方面:在C中使用goto是不受欢迎的。改用if、else、for、while、switch。将这种想法留给汇编编程。

您的方法有两个主要障碍:

一个长的,甚至是一个无符号的长不足以容纳大多数数字的阶乘。long通常存储32位,尽管这在不同的体系结构中可能有所不同,这允许我们存储小于2**32-1的数字,即大约40亿。13! 已经比这个大了

太多的递归调用可能会严重影响性能,因为当编译器不进行尾部递归优化时,在调用堆栈中为函数分配空间会产生开销

更好的解决方案是,要么使用可以增长到任意大小的大整数,要么使用双精度浮点数,并使用迭代解找到近似解


另一方面:在C中使用goto是不受欢迎的。改用if、else、for、while、switch。将这种想法留给汇编编程。

问题在于这一行与溢出相结合:

for(i=2;i<=n;i++)
只要n可以分解成大量的小素数,这就可以很好地工作,这是阶乘满足的条件。没问题。当您的阶乘不能再表示为long时,问题就开始了。然后,结果将是long值范围内的其他一些数字,可能有一个非常大的素数因子,或者是素数本身

现在我假设,您正在一个平台上工作,其中long是64位,您可以通过打印sizeoflong的值来检查,因此这些大素数可以在10^18的范围内。即使是最现代、最快的硬件也无法在您的一生中循环所有这些数字。因此,该循环将不再有效 当你还在等待的时候,你就可以忘记它


唯一的出路是确保您的计算不会溢出。您可以在每次乘法后检查结果是否除以其中一个因子得到另一个因子。如果没有,则表示存在溢出,并应以错误退出。

问题在于此行与溢出相结合:

for(i=2;i<=n;i++)
只要n可以分解成大量的小素数,这就可以很好地工作,这是阶乘满足的条件。没问题。当您的阶乘不能再表示为long时,问题就开始了。然后,结果将是long值范围内的其他一些数字,可能有一个非常大的素数因子,或者是素数本身

现在我假设,您正在一个平台上工作,其中long是64位,您可以通过打印sizeoflong的值来检查,因此这些大素数可以在10^18的范围内。即使是最现代、最快的硬件也无法在您的一生中循环所有这些数字。因此,当您仍在等待时,该循环不会终止



唯一的出路是确保您的计算不会溢出。您可以在每次乘法后检查结果是否除以其中一个因子得到另一个因子。如果没有,则会出现溢出,并应带着错误退出。

这是因为您正在使用递归解决方案来计算阶乘,这会使调用堆栈不断增长,直到调用堆栈耗尽真正大的数为止。尝试使用迭代版本来计算,而不是递归形式。示例:无符号整数iter\u factorialint n{int f=1;int i;fori=1;感谢您的回答。但我也尝试过不使用递归,但同样的问题仍然存在。您可能导致长类型溢出:100!=9.332622e+157无符号长的最大值:2^64-1您可以使用浮点数获得近似值……递归调用不是问题所在。整数溢出是一个问题。这是因为您使用递归解决方案来计算阶乘,这会使调用堆栈不断增长,直到调用堆栈中的真正大数用完为止。请尝试使用迭代版本来计算,而不是递归形式。例如:unsigned int iter\u factorialint n{int f=1;int i;fori=1;感谢您的回答。但我也尝试过不使用递归,但同样的问题仍然存在。您可能导致长类型溢出:100!=9.332622e+157无符号长的最大值:2^64-1您可以使用浮点数获得近似值……递归调用不是问题所在。整数溢出是一个问题。编辑是为了清晰,包括了样本。编辑是为了清晰,包括了样本。他的算法对阶乘有效,因为n!没有大于n的素数。他的算法对阶乘有效,因为n!没有大于n的素数。第二点是静音的,因为你可以很快达到溢出函数调用需要10到20个CPU周期,他能计算的阶乘计算时间不会超过一微秒。第二点是静音,因为你可以很快达到溢出。函数调用需要10到20个CPU周期,他能计算的阶乘计算时间不会超过一微秒。没有这个问题需要计算大的阶乘,当然不需要计算大量的素因子。问题是为所述阶乘的素因子分解生成一个指数列表。给出的示例4!==24==3 1,表示2^3*3^1,您不需要计算或因子大的阶乘来完成这个任务事实上,这是问题本身的部分目的。根据定义,阶乘由素数和非素数组成,它们可以分解为素数。我明确指出,大素数只能由于阶乘计算中的溢出而出现,即他试图分解的数字不是阶乘是的。因此可能会有较长的运行时间。如果你使用无符号字符作为类型,6!将是208,它的素因子分解为2^4*13。13显然比6大。我同意,并投了我的赞成票。一般来说,我们都同意他的基本问题是他选择的算法,至少听起来是这样。你可以很容易地用它来做对于一个n!的问题,我们从来没有对一个大于n的数字进行过因式分解,听起来我们在这一点上也达成了一致。在任何一个像样的系统上,在几秒钟内就可以找到100000!的素因子指数表。这个问题不需要计算大的因式,也绝对不需要计算大量的素因子问题是为所述因子的素因子分解生成一个指数列表。给出的示例,4!==24==31,意味着2^3*3^1,您不需要计算,也不需要因子,大因子来完成这一点,也就是说,在
事实上,这是问题本身的部分预期目的。根据定义,阶乘由素数和非素数组成,它们可以分解为素数。我明确指出,大素数只能由于阶乘计算中的溢出而出现;我E他试图分解的数字根本不是阶乘。因此可能需要较长的运行时间。如果使用无符号字符作为类型,则为6!将是208,其素因子分解为2^4*13。13明显比6大得多。我同意,投了赞成票。总的来说,我们都同意他的基本问题是他选择的算法——至少听起来是这样。人们可以很容易地做到这一点,而不必将大于n的数字分解为n!问题,听起来我们在这个问题上也是一致的。正在查找100000的素因子指数列表!在任何像样的系统上都能在几秒钟内完成。