4.1 相关程序
即使最终答案在所选择的数据类型范围之内 ,计算的中间结果仍然可能溢出
eg:
点击查看代码
long long fac(int n)
{
long long m = 1;
for(int i = 1; i <= n; i++)
m *= i;
return m;
}
这段代码在n = 21的时候就会出现数据溢出,这是一个隐藏的bug需要注意
这个题目还说明:即使认为题目在按时你使用某种语言特性,也应该深入分析,不能贸然行事,即使最终答案在所选择的数据类型范围之内,计算的中间结果仍然可能溢出
修改后通过约分来减小中间数据的大小
FlnButFly's Version
点击查看代码
#include<stdio.h>
long long C(int n, int m)
{
long long ans = 1;
if(m > n - m)
{
for(int i = n; i > m; i--)
ans *= i;
for(int i = 1; i <= m-n; i++)
ans /= i;
}
else
{
for(int i = n; i > n-m; i--)
ans *= i;
for(int i = 1; i <= m; i++)
ans /= i;
}
return ans;
}
int main()
{
printf("%lld\n", C(21,1));
return 0;
}
点击查看源代码
long long C(int n, int m)
{
if(m < n-m) m = n-m;
long long ans = 1;
for(int i = m+1; i <= n; i++) ans *= i;
for(int i = 1; i <= n-m; i++) ans /= i;
return ans;
}
里面给出的代码更加简洁,它将判断m与n-m的大小简化了,其展开后相当于上面写的完整版,对于加减法中,一个数可以相互转化,也就是m = n - m;实质上是将m和n - m的数值互换了,这样可以简便代码,也就是说这是类似一种封装的思想,因为我们约分的时候一定找的是最大的数去约分,这样才能尽量避免计算式的数据溢出所以我们只要确定最大的数,然后按照顺序填进去就可以了,也就是说这里的m和m-n是可以互换的,并不一定就一定是彼此
对复杂的表达式进行化简有时不仅能减少计算量,还能减少甚至避免中间结果溢出
如果怕太大有时候甚至可以取对数来消去他的增长速度,参考第三章最后一题
编写程序判断一个数是否为素数,因数只有1和自己本身的大于1的数称为素数,这边最先想到的就是模拟,程序如下:
点击查看代码
#include<stdio.h>
int isPrime(int num)
{
for(int i = 2; i < (num + 1) /2 + 1; i++)
if(num % i == 0)
return 1;
return 0;
}
int main()
{
int num;
scanf("%d", &num);
if(isPrime(num))
printf("No\n");
else
printf("Yes\n");
return 0;
}
当然自己编写的程序还不够好,只判断不超过sqrt(num)的函数是更好的,也就是i*i<=num;因为如果这之前的都不行那后面肯定也没有这个数的其他因数了
假设num = a * b;
如果a大则b小,其中最极限的情况就是a == b;
判断一个事物是否具有某一性质的函数有一个学术名称--谓词(predicate)
尽可能的让自己的函数名的选取有规律可循,空格可以用下划线来代替
建议把谓词(用来判断某事物是否具有某种特性的函数)命名成“is_xxx”的形式,返回int值,非0表示真,0表示假
这个函数的缺陷也很明显,正常情况下如果num=1的时候,其返回值是Yes不符合素数的定义,如果要解决需要增加一个特殊判断,同时如果n太大的时候可能会造成数据的溢出,此时数据为负值,仍能够符合i * i < n,但是很明显在逻辑上是错误的
编写函数的时候,应尽量保证该函数能对任何合法参数得到正确的结果。如若不然,应在显著位置标明函数的额缺陷,以避免误用
修改后的程序代码:
点击查看代码
#include<stdio.h>
#include<math.h>
int isPrime(int num)
{
if(num <= 1)
return 0;
int m = floor(sqrt(m) + 0.5);
for(int i = 2; i < m + 1; i++)
if(num % i == 0)
return 0;
return 1;
}
int main()
{
int num;
scanf("%d", &num);
if(isPrime(num))
printf("Yes\n");
else
printf("No\n");
return 0;
}
以上的代码特判了n<=1的情况,还是用了变量m,一方面避免了重复计算sqrt(num),重复计算带来的问题前面的strlen已经体现了,会拖慢程序的运行效率,注意floor(x + 0.5)是四舍五入的方法,尽量避免浮点误差,也就是就算sqrt将某个整数的值编程xxx.9999也将被修正,否则可能会导致程序的错误,丢失精度
当然上述的程序只是简单的模拟,其效率是低下的,在数据很大的时候需要运行很长的时间才能得出结论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)