提示
- 函数的参数和返回值最好是“一等公民”,如int、char或者double等。其他“非 一等公民”作为参数和返回值要复杂一些。如果函数不需要返回值,则返回类型应写成 void。
注意这里的return是一个动作,而不是描述。
计算组合数
程序4-1 组合数(有问题)
long long factorial(int n){
long long m = 1;
for(int i = 1; i <= n; i++)
m *= i;
return m;
}
long long C(int n, int m)
{
return factorial(n)/(factorial(m)*factorial(n-m)));
}
提示
- 即使最终答案在所选择的数据类型范围之内,计算的中间结果仍然可能溢出。
- 对复杂的表达式进行化简有时不仅能减少计算量,还能减少甚至避免中间结 果溢出。
- 一个简单的方法是利用n!/m!=(m+1) (m+2)…(n-1)n。虽然不能完全避免中间结果溢出,但是对于题目给出的范围已经可以保证得 到正确的结果了。代码如下:
程序4-2 组合数
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;
}
素数判定
编写函数,参数是一个正整数n,如果它是素数,返回1,否则返回0。
提示
- 这种“判断一个事物是否具有 某一性质”的函数还有一个学术名称——谓词(predicate),下面程序中将写一个谓词。
- :建议把谓词(用来判断某事物是否具有某种特性的函数)命名成“is_xxx”的 形式,返回int值,非0表示真,0表示假。
- 编写函数时,应尽量保证该函数能对任何合法参数得到正确的结果。如若 不然,应在显著位置标明函数的缺陷,以避免误用。
程序4-3 素数判定(有问题)
//n=1或者n太大时请勿调用,n太大时的 理由则不明显:i*i可能会溢出!
int is_prime(int n) {
for(int i = 2; i*i <= n; i++)
if(n % i == 0) return 0;
return 1;
}
程序4-4 素数判定(2)
int is_prime(int n)
{
if(n <= 1) return 0;
int m = floor(sqrt(n) + 0.5);
for(int i = 2; i <= m; i++)
if(n % i == 0) return 0;
return 1;
}