孪生素数

如果n和n+2都是素数,则称它们是孪生素数。输入m,输出两个数均不超过m的最大孪生素数。5≤m≤10000。例如m=20时答案是17、19,m=1000时答案是881、883。

【分析】

被1和它自身整除的、大于1的整数称为素数。由于要判断n和n+2是否是素数,所以把“判断素数”可以写成一个函数,只需调用这个函数两次就可以了。这样的“判断一个事物是否具有某一性质”的函数还有一个学术名称——谓词(predicate)。

程序4-2  孪生素数(1)

 

#include<stdio.h>
/* do NOT use this if x is very large or small */
int is_prime(int x)
{
  int i;
  for(i = 2; i*i <= x; i++)
    if(x % i == 0)   return 0;
  return 1;
}

int main()
{
  int i, m;
  scanf("%d", &m);
  for(i = m-2; i >= 3; i--)
    if(is_prime(i) && is_prime(i+2)) {
      printf("%d %d\n", i, i+2);
      break;
    }
  return 0;
}


 

说明:(1)在is_prime函数的编写中,用到了两上小技巧。一是只判断不超过sqrt(x)的整数i;二是及时退出:一旦发现x有一个大于1的因子,立刻返回0(假),只有最后才返回1(真)。

(2)函数的命名应注意做到“见名知意”,即选有含义的英文单词(或其缩写)作为函数名。例如,“is_prime”取自英文“is is a prime?”(它是素数吗?)。

提示4-8:建议把谓词(用来判断某事物是否具有某种特性的函数)命名成“is_xxx”的形式。它返回int值,非0表示值,0表示假。

提示4-9:编写函数时,应尽量保证它能对任何合法参数都能得到正确的结果。如若不然,应在显著位置标明函数的缺陷,以避免误用。

下面改进之后的版本:

程序4-3  孪生素数(2)

#include <stdio.h>
#include <math.h>
#include <assert.h>
int is_prime(int x){
  int i, m;
  assert(x >= 0);     //使用断言,防止x<0
  if(x == 1) return 0;
  m = floor(sqrt(x) + 0.5);
  for(i = 2; i <= m; i++)
    if(x % i == 0) return 0;
  return 1;
}

int main(){
  int i, m;
  scanf("%d", &m);
  for(i = m-2; i >= 3; i--)
    if(is_prime(i) && is_prime(i+2)) {
      printf("%d %d\n", i, i+2);
      break;
    }
  return 0;
}


 

除了特判n==1的情况外,程序中还使用了变量m,一方面避免了每次重复计算sqrt(x),另一方面也通过四舍五入避免了浮点误差。

最后,程序使用了assert.h的assert宏来限制非法的函数调用:当x>=0不成立时,程序将异常终止,并给出了提示信息。

说明:(1)断言(assert)的语义如下:如果表达式的值为0(假),则输出错误消息并终止程序的执行(一般还会出对话框,说明在什么地方引发了assert);如果表达式为真,则不进行任何操作。因此,断言失败就表明程序存在一个bug。

(2)C/C++的宏(assert)就是这样的断言,当表达式为假时,调用库函数abort()终止程序。

(3)程序中可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段,所以不要把程序中的assert语句删除掉。

(4)如果程序在assert处终止了,并不是说含有该assert的函数有错误,而是调用函数出了差错,assert可以帮助我们追踪到错误发生的原因。

(5)在函数的入口处,建议使用断言来检查参数的有效性(合法性)。请给assert语句加注释,告诉人们assert语句究竟要干什么。

提示4-10:编程时合理利用assert宏,将给调试带来很大的方便。

总而言之,在实际的系统中,“一个地方的参数错误就引起整个程序异常退出”是不可取的,在编写和调试算法程序中,assert会“迫使”编写出更高质量的程序。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值