老师布置的作业要求:
阅读下面程序,请回答如下问题:
问题1:这个程序要找的是符合什么条件的数?
问题2:这样的数存在么?符合这一条件的最小的数是什么?
问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间精确到分钟(电脑:单核CPU 4.0G Hz,内存和硬盘等资源充足)。
问题4:在多核电脑上如何提高这一程序的运行效率?
using System;
using System.Collections.Generic;
using System.Text;
namespace FindTheNumber
{
class Program
{
static void Main(string[] args)
{
int [] rg =
{2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
20,21,22,23,24,25,26,27,28,29,30,31};
for (Int64 i = 1; i < Int64.MaxValue; i++)
{
int hit = 0;
int hit1 = -1;
int hit2 = -1;
for (int j = 0; (j < rg.Length) && (hit <=2) ; j++)
{
if ((i % rg[j]) != 0)
{
hit++;
if (hit == 1)
{
hit1 = j;
}
else if (hit == 2)
{
hit2 = j;
}
else
break;
}
}
if ((hit == 2)&& (hit1+1==hit2))
{
Console.WriteLine("found {0}", i);
}
}
}
}
}
答:
(1)在本子上进行了多次的演算后,大致感觉这个代码的目的是要在int64的范围中找到不能被rg[k]与rg[k+1]整除,但是同时可以被数组中其他的数整除的数。
(2)我首先将代码直接复制到了VS中运行,第一次运行了大概20分钟没有出结果,可以见得这个数肯定非常大,用笔算应该是不太现实的,我也尝试了几次就放弃了,这样的数存在么?说实话我不太清楚。在和同学的讨论中,有了一些思路,最后发现计算方法为:首先必须要符合不能被rg[k]与rg[k+1]整除,但是同时可以被数组中其他的数整除,可以确定rg[k]肯定大于15。
其次,在16到31之间的数中,17没有因子,23没有因子,其他数都可以在2-15之间找到因子,所以,这两个数一定包含23与17的其中一个,22是11的倍数,24是12的倍数,所以23不是其中的一个,18是2和9的倍数,因为i必须被2和9整除,所以18也不是,只有16可以,所以这两个是分别是16和17。那么最小的i就是剩下28个数的最小公倍数:2123581660200。(3)我在图书馆用了差不多2个小时来运行这段代码,并没有得到结果输出,因为for循环中的范围达到了int64.MaxValue,所以这个数一定不会小,就算得到了第一个结果,也有可能结果不唯一,所以我大胆的估计了至少一天才能出结果。可是我还是太年轻,在网上找到了一个大神的推断:
要估算时间,我们先确定一个原子操作(或者说原子过程更合适),这里我们取内层for循环里的整个if语句块,该段程序主要包括一个取模操作和一个判断,如果进入if语句的话,还包括1次加法操作,1~2次判断和一次赋值操作。
我们知道加法、判断等操作基本都在几个时钟周期内就可以完成,而除法操作却需要数十个时钟周期,而取模操作也是通过除法操作得到的(还记得汇编语言里,执行除法操作之后,一个寄存器里存结果,另一个寄存器里存余数),另外,对64位整数的除法明显要慢于32位整数,综合这些因素,我们可以假设该原子 操作需要100个时钟周期。因此2GHz的CPU在1秒内能跑2*10^9 / 100 = 2*10^7 即2000万次原子操作,做过ACM的同学就会有一个直观概念,这和我们通常做时限为1S的题时估算的计算次数差不多。
接下来估算原子操作执行的次数:外层循环跑了2123581660200次,内层循环取决于 i 的情况,当i为奇数的时候,内层最多跑5次即可结束,因为2,4,6都不能整除奇数;当i为偶数的时候,情况要复杂一些,但是也可以一个一个的详细分析。 这里我们粗略估计,就算内层循环平均可以跑10次,外层循环少跑一些,去掉零头,总的原子操作执行了2*10^13次。
所以需要 2*10^13 / (2*10^7) = 10^6秒约为277个小时。
277个小时,也就是10天多,真是太神奇了,如此简短的代码,竟然会有如此巨大的运算量,我现在都认为电脑CPU已经性能过剩了,没想到面对这样的程序还是无能为力。
我 的笔记本CPU是i5-3337u,双核1.8GHz,睿频能达到2.7GHz,按照上边大神的计算,2GHz的CPU可以在277小时内得到结果,那么 我的电脑在睿频达到最高速的状态下应该需要277*(2/(2.7*2))=102.6小时,这是在最理想的情况下要运行127小时,因为电脑肯定不可能 在102小时内全速运行,如果保持充电状态,大概能保持2GHz的运行速度,而且在我运行代码时,在任务管理器中查看到CPU的使用率只有39%,所以大 概需要的时间为:277*(2*(2*2))/0.39=355小时。
(4)如何在多核处理器的电脑上提高运行速度,这个我还不知道该怎样优化,希望老师能给予指点。