繁体   English   中英

我如何进行“数百万次计算?”

[英]How do I perform “Millions of Calculations?”

我的代码粘贴在下面。当我运行这个程序时,它继续计算。我正在使用旧的Turbo C ++编译器。这样的程序需要多长时间才能执行?我等了大约5分钟,但没有任何输出。

/*The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.
*/
#include<stdio.h>
#include<conio.h>
#define TWO_MILLION 2*1000*1000
int IsPrime(long unsigned int num);
int main()
{
    long unsigned int i,sum=0;
    clrscr();
    for(i=2;i<TWO_MILLION;i++)
    {
        if(IsPrime(i))
        sum+=i;
    }
    gotoxy(25,25);
    printf("%ld",sum);
    getch();
    return 0;
}
int IsPrime(long unsigned int num)
{
    int flag=1;
    long unsigned int i;
    for(i=2;i<num;i++)
    {
        if(num%i==0)
        {
            flag=0;
            break;
        }
    }
    return flag;
}

你没有进行数百万计算,你正在做数万亿计算。

IsPrime将在O(n)时间运行,即它将执行200万条指令以确定该单个数字。 做两百万次这样的事情将花费太长时间。

要做到这一点,你真的想使用类似的东西: http//en.wikipedia.org/wiki/Sieve_of_Eratosthenes ,它可以更有效地确定特定范围内的所有素数。

这样的程序需要多长时间才能执行?

这完全取决于您的平台。 我怀疑,因为你正在执行〜(两百万)^ 2次操作(~4万亿次)计算,这是一段非常长的时间。

有更好的方法来执行你正在做的事情 - 例如检查素数你只需要检查数字的平方根,而不是一直到数字本身。 更不用说可能有一个动态编程解决方案可以比这快得多。

正如其他人所说,这需要很长时间。 另一种有趣的方法是Eratosthenes的Sieve。 你可以在以下网址阅读:

http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

基本上你用一个2到200万的数字初始化一个数组。 尚未处理的最低数字是素数。 然后,从阵列中删除此数字的所有倍数并继续。 它会比你拥有的速度快得多。

不合适的答案

gotoxy(25,25);

你是否以文本模式运行程序? 如果文本屏幕只有80 x 25 ,如果第25行被其他一些东西遮挡,那么你很可能在文本屏幕上看不到任何变化。

正如其他人所说: 检查实施的限制

如果TurboC++具有<limits.h>,则这些实现限制在该标头中定义了相应的宏

#include <limits.h>
#include <stdio.h>
int main(void) {
    printf("int goes from %d to %d.\n", INT_MIN, INT_MAX);
    printf("long goes from %ld to %ld.\n", LONG_MIN, LONG_MAX);
    return 0;
}

如果失败,您需要自己“计算”限制。 我正在切换到unsigned因为它们没有溢出问题,我只需要“计算”上限(下限为0)

#include <stdio.h>
int main(void) {
    unsigned u;
    unsigned long lu;

    u = -1; lu = -1;
    printf("unsigned ints go all the way to %u\n", u);
    printf("unsigned longs go all the way to %lu\n", lu);
    return 0;
}

在我的系统上,第一个程序输出

int goes from -2147483648 to 2147483647.
long goes from -9223372036854775808 to 9223372036854775807.

和第二个程序输出

unsigned ints go all the way to 4294967295
unsigned longs go all the way to 18446744073709551615

除了“史诗”之外,仍然没有关于常数的评论/答案......

#define TWO_MILLION 2*1000*1000

这是不好的。 稍后更改值时,您要么具有名称 - 内容不匹配:

#define TWO_MILLION 5*1000*1000

或者你重命名为

#define FIVE_MILLION 5*1000*1000

并且需要在你使用它的任何地方改变它。 不要在内容之后命名常量,这只是将你的魔法数字变成魔法名字。 在它们的含义之后命名它们,例如MAX_NUMBER UPPER_LIMIT RANGE_TO_TEST或任何最适合的。

您可以使用筛选方法来完成此操作,这些方法并不比您使用的方法复杂得多。 我们的想法是选择前n个连续素数并用它们构建一个筛子。 我在讨论这个问题(与样张) 我的回答另一个问题和谢尔顿L. Cooper在提供了一个实现自己的 我认为他没有得到足够的赞成(我已经得到了'很好的答案',所以也许你可以帮助他解决这个问题。

因此,在计算筛数后,您只需要通过与筛子对齐并且小于n平方根的数字来测试可分性。

这可能需要长时间才能运行。

添加此项以查看您的进度(尽管需要更长时间):

for(i=2;i<num;i++)
    {
        if(num%i==0)
        {
            flag=0;
            printf("%d,", num); /* <== show the prime */
            break;
        }
    }

编辑

正如其他人指出的那样,这是计算素数的最慢方法。 您的任务的目的可能是让您查找(并实施)更快的任务?

您的程序导致整数溢出,您可以使用long long来修复它。

此外,您检查数字是否为素数的算法不是很好。 另一种同样容易的方法是将数字2测试到数字的平方根。 您只需要检查数字的平方根,以确定它是否为素数。

一个简单的更改将向您显示程序运行的速度,以及它需要完成的工作量。 每100次迭代就可以轻松打印出您的状态。 (或者您可以将其设置为1000或10000次迭代。)


认识到你可能会增加一倍,你在循环的速度IsPrime
检查2之后,您只需要检查奇数,并且可以使用i+=2而不是i++

如果你担心速度,你为什么花这么多时间检查偶数? (请注意,一旦开始只做奇数,您还需要将输出测试更改为奇数)

您可以将main循环的速度加倍 ,同时避免在那里使用偶数。 (再次,你需要特殊情况2,然后使用i + = 2,从3开始得到3,5,7,9 ....)

通过使IsPrime的循环运行速度IsPrime两倍,并使main循环中的循环速度提高两倍,这将使您的程序速度提高4 (如果它花了一个小时,现在它将是15分钟。)


您可以进行的另一个大速度改进是仅将循环运行到sqrt(num) ,而不是num

由于我讨厌引入浮点函数,例如sqrt ,我建议使用近似的近似值,它将在传递sqrt边界的100次迭代中停止,并且还会定期显示状态更新。

if (num%2 == 0)
{
    flag=0;
    return flag;
}

/* Now that we checked 2, we only need to check odd numbers from now on. */
for(i=3;i<num;i+=2)
{
    if (i%101 == 0)
    {
        printf("i is %d out of %d\n", i, num);
        if (i*i > num)
        {
            break;  /* If you pass the sqrt boundary, quit. */
        }
    }

    if(num%i==0)
    {
        flag=0;
        break;
    }
}

PS我将此代码放入C#项目(小端口)。 当然,现在它运行在64位操作系统上,具有更好的编译器和2.8GHz CPU。
它跑了不到20秒。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM