《编程之美》2.20 程序理解和时间分析(读别人的程序)

本文解析了一段寻找特定整数的C++程序,该整数能被2到31之间的多数数字整除,但不能被其中连续的两个数字整除。文章详细分析了程序逻辑,并估算了其在现代计算机上的运行时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

        给出一段C#代码,要求不用电脑,理解程序并回答问题。

 

解答:

 

 

解答: 

 

         理解这个程序就是从输出的地方往前追溯就可以。这个程序输出的条件是hit==2&&(hit1+1==hit2),再往前追溯看hit,hit1,hit2三个变量分别代表什么,hit表示满足i%r[j]!=0的条件的次数,hit==2表示这个条件只能被满足两次,也就是说对于一个i,在rg数组的30个数中,这个i能被其它28个数整除,而不能被其中两个数整除。而hit1表示第一个不能整除i的数的下标,hit2表示第二个不能整除i的下标,这两个下标被要求相差只有1。

         于是,程序所要寻找的是这样的数:这个数i不能被2-31这30个数中的两个相邻的数整除,但能被其它28个数整除。所以,这个i肯定是其它28个数的最小公倍数的整数倍。然而i不能被两个相邻的数整除,所以必然是分解质因子后要么i的质因子中不包括这两个数的质因子,要么是i的质因子的次数小于这两个数中相同质因子的次数

       那么,只需要给2-31这30个数分解质因数,找一下是否有这样的相邻的两个数,要么它们的质因子中有其它数没有的质因子,要么对于相同的一个质因子,这两个数包含这个质因子的次数高于其它所有次数(注意只需要该质因子高于其他所有rg中数的该因子的次数,而非其他所有该因子的次数之和,原因是最后只需最小公倍数)。为此建立一张表如下:

 

 由上表中可以看出,只有16、17、19、23、25、27、29、31这几个数包含次数最高的质因子。而相邻的则只有16,17。所以,这段程序所要求的数i就是,它不能被16、17整除,但能被30个数中的其它28个数整除,最小的i就是其它28个数的最小公倍数,从上表中知道,这个最小的i是:23*33*52*7*11*13*19*23*29*31,用计算器计算出这个数是:2123581660200。可以把上述程序中的for循环中的i初始化成这个数来检验。

 

 

 

 

估算时间:

 

      我们先确定一个原子操作(或者说原子过程更合适),这里我们取内层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个小时。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值