[英]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
或任何最适合的。
这可能需要很长时间才能运行。
添加此项以查看您的进度(尽管需要更长时间):
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.