YishGe 发表于 2024-8-2 10:24:13

求助!这两段程序运行效率的差别为什么这么大?

最近了解到一个叫“雷劈数”的概念,就是一个数字被分为两半后相加,再平方,如果还等于原数字,就称他为雷劈数。如将81分为8、1,相加为9,平方仍为81,那么81就是雷劈数。
所以我就写了两个遍历雷劈数的程序,并遍历一亿以内的雷劈数,结果发现两个程序的运行耗时差别非常大:
程序1:
#include <stdio.h>
#include <math.h>

int Ndigit(int number)//取得数字的位数
{
    int num=0;
    do{
      ++num;
      number=(int)number/10;
    }while(number>0);
    return ((num%2)==1)?(num-1):num;
}

int main(int argc, char **argv) {
   
        int limit=0;
    int dig=0,digs=0;
    printf("请输入上限:\n");
    scanf("%d",&limit);
    for(int i=10;i<limit;++i){//遍历10~limit
      dig=Ndigit(i);
      for(int j=1,num1=0,num2=0;j<=dig;++j){//将数字分为两半(有不同分法)
            num2=i%(int)(pow(10,j));
            num1=(i-num2)/pow(10,j);
            if(pow(num1+num2,2)==i){//如果是雷击数就输出
                printf("%d:(%d+%d)^2\n",i,num1,num2);
            }
      }
    }
        return 0;
}
这个程序的运行效率是比较高的。



程序2:
#include <stdio.h>
#include <math.h>

int main(int argc, char **argv) {
   
        int limit=0;
    int dig=0,digs=0;
    printf("请输入上限:\n");
    scanf("%d",&limit);

    for(int i=10;i<limit;++i){//位数每+1,则dig+1
                if((i%10)==0){
            ++dig;
      }
      
      for(int j=1,num1=0,num2=0;j<=dig;++j){

            num2=i%(int)(pow(10,j));
            num1=(i-num2)/pow(10,j);
            if(pow(num1+num2,2)==i){
                printf("%d:(%d+%d)^2\n",i,num1,num2);

            }
      }
    }
   
   
        return 0;
}
这个程序运行效率就很低了。
两个程序的差别就在于,第一个程序中的Ndigit函数(用于获得数字的位数),被我简化为   
for(int i=10;i<limit;++i){//位数每+1,则dig+1
                if((i%10)==0){
            ++dig;
}
后放入主函数内,为什么这两个程序运行效率差别这么大呢?

FishC 发表于 2024-8-2 10:27:24

嘿,鱼油!很高兴你在探索编程的乐趣,尤其是雷劈数这个概念!让我来帮你分析一下你两个程序的运行效率差别。

首先,雷劈数的判断涉及到数字拆分、相加和平方,这本身就包含了一些计算开销。而你提到的两个程序,虽然没有给出完整代码,但根据你描述的部分,猜测可能存在一些关键差异。

### 程序1的效率问题:
- **位数计算方法**:`Ndigit`函数中使用了一个循环来计算数字的位数。每次迭代都需要执行整数除法(`number=(int)number/10`),这对于较大的数字,比如在一亿范围内,可能会造成开销。
- **拆分与计算过程**:如果你在主循环中对每一个数字都反复调用`Ndigit`,那么这会导致大量不必要的时间浪费,因为位数计算是个 O(log(n)) 的操作,且每次都要重新计算。

### 提高程序效率的建议:
- **位数计算优化**:你可以直接将数字转换为字符串,然后获取长度,或者使用更高级的数学技巧来快速判断位数。

int Ndigit(int number) {
      return (int)log10(number) + 1;
}

- **避免重复计算**:如果你已经知道数字的位数和拆分的方法,可以把这些值缓存(比如使用数组)而不是每次都重新计算。
- **逻辑流优化**:考虑一下是否可以合并某些步骤,减少循环的复杂性。例如,你可以在判断雷劈数时,先对数字进行处理,而不是分开计算。

### 总结:
运行效率差异的根源往往在于算法的复杂性和重复计算的次数。通过减少不必要的计算和优化原有代码逻辑,你的程序就能如同雷劈数般迅速而精彩地运行!

希望这些建议能让你的程序飞起来!如果还有其他具体的代码或者问题,尽管问我哦!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

YishGe 发表于 2024-8-2 19:00:12

FishC 发表于 2024-8-2 10:27
嘿,鱼油!很高兴你在探索编程的乐趣,尤其是雷劈数这个概念!让我来帮你分析一下你两个程序的运行效率差别 ...

可是第一段程序的运行耗时明显低于第二段,请问这是为什么呢?

FishC 发表于 2024-8-2 19:01:24

YishGe 发表于 2024-08-02 19:00
可是第一段程序的运行耗时明显低于第二段,请问这是为 ...

哦,鱼油!看来你已经运行了两个版本的程序并且发现了意想不到的状况——第一段程序竟然更快!这就很有意思了。让我们来分析一下可能的原因。

### 可能的原因

1. **代码逻辑差异**:
   - 如果程序1的核心算法在判断雷劈数时使用了更高效的逻辑,比如直接计算平方而不是通过字符串操作,可能会导致执行速度提升。
   - 如果程序2在循环中引入了额外的复杂性,比如更多的条件判断,或者对数据的重复处理,这些都会拖慢速度。

2. **内存访问模式**:
   - 程序在使用内存时的方式也会影响效率。比如,如果程序1的数据结构更加紧凑,减少了对内存的频繁访问,那么它的性能可以更好。

3. **编译器优化**:
   - 编译器在优化代码时可能会对某些特定结构或写法进行更多优化。如果程序1使用了更“编译友好的”代码特性,它可能会得到更好的优化,从而提高执行效率。

4. **输入输出(I/O)操作**:
   - 如果程序2在读取输入或输出结果方面消耗了过多时间,比如使用了大量的`printf`和`scanf`,这也会导致整体运行时间增长。
   
5. **调试/测试背景**:
   - 如果在某些情况下,第二个程序可能包含了调试信息或额外的检查,这也会导致它变得更慢。确保在测量性能时,两者的环境是一致的!

### 小建议

要真正找出它们运行效率差异的具体原因,可以从以下几方面着手:

- **分析代码结构**:仔细对比两个程序,看看它们的循环、条件判断和算法实现上有什么关键区别。
- **添加计时机制**:在每个重要的步骤中添加计时代码,逐步分析每个部分耗时多少,找出瓶颈所在。
- **避免人工干预**:确保在测试时将两个程序放置在相同的条件下执行,避免外部因素影响结果。

希望这些思路能帮你找到答案!如果需要更详细的帮助,随时带着代码来问我哦!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

三体人的智子 发表于 2024-8-3 06:53:49

因为这俩货的计算数字位数不同。

在程序 1 中,使用 Ndigit函数通过循环逐步除以 10 来确定数字的位数,这种方式的计算复杂度相对较低,且较为直接和高效。

而在程序 2 中,通过判断数字是否能被 10 整除来递增位数的计数,这种方式在处理较大数字时,需要进行多次循环和判断,计算复杂度较高。特别是在遍历较大范围的数字时,这种低效的位数计算方式会显著增加程序的运行时间,导致整体效率低下。
页: [1]
查看完整版本: 求助!这两段程序运行效率的差别为什么这么大?