//*******************************

//

//    2014年9月18日星期四,于宿舍撰写

//    作者:夏华林

//

//********************************

好久没有没有更新博客了,最近确实烦心事儿挺多,已经大三了,真的静下心来好好看看书了。

今天要说的,就是一个由IsPrime算法引发的细节问题,我这里说的细节,是我所认为的,若有不妥,望指正!

一个简单的IsPrime算法的实现如下:

 bool IsPrime(int n)
{
int i; if(n % == )return false;
for(i = ; i <= sqrt(n); i += )
{
if(n%i == )return false;
}
return true;
}

这段代码中有一些严重的错误,很明显的就是,当参数为1和2的时候,函数就会返回一个错误的答案,要解决这个问题,最简单的方法就是单独检查1和2,可以在函数的开头简单的加入:

if(n <= )return false;
if(n == )return true;

还有一个性能上的问题,IsPrime算法的本意是为了提高效率,但实际情况下,有时候却会比老的算法花的时间更长。

这种问题存在于for循环的控制行中:

for(i = ; i <= sqrt(n); i += )

尽管现代计算机能在相当短的时间内计算平方根,但,计算平方根还是会比执行简单的算术运算要花的时间要长。程序中,每执行一次循环,都要计算一下sqrt(n),而n在整个循环中都是不变的量,那么我们每次循环都计算一下sqrt(n)就显得不那么划算,为了避免一次次的调用sqrt()函数,可以在循环前先计算出sqrt(n),把它存入一个变量,例如:

double limit = sqrt(n);
for(i = ; i <= limit; i += )

这个简单的改变,将明显的改善了IsPrime算法的实现效率。

这个IsPrime算法还有一个很难查出的问题,发现这个逻辑错误是很难的,因为它可能在你成千上万的测试例子中都不会出现,而对于一些特殊的测试例子,这个实现可能会在一些机器上能得出正确结果,而在另一个机器上得出不正确的答案。

为了理解这个问题,我觉得自己还是有必要再补写一篇关于计算机浮点数相关的文章,但限于篇幅,这里就不详细叙述其原理了

对浮点数判断严格的相等,是一个危险的行为。假设n是49,它是7的平方,当计算机对49调用sqrt()函数时,会返回什么?在严格的数学领域,这个平方根是7,但计算机并不是在这个领域内运作的,它返回的仅仅是一个接近7的浮点数,而这个数可能是6.9999999999999999999,尽管这个数很接近7,但这个差别足以影响i<=limit的结果。如果i是7,而limit是6.999999999,则循环的最后一个周期将不会得到执行,程序永远不会检查到是否可以整除7,而7又是49唯一的质因子,这样程序会错误的将49分类素数。另一方面,如果sqrt(49)返回的是7.0或者7.0000000001,那么IsPrime算法将会得到正确的答案。因而,这个实现的正确性居然要取决于硬件是如何执行浮点数运算的,而让一个算法的正确性依赖于运行它的计算机的特性是一个严重的错误。这个问题很容易解决,如果n的平方根小于某一个界限,为了保险起见,我们总倾向于多检查一个可能的约数,多测试一个约数并不会有什么害处,仅仅是付出一个非常小的代价,就能确保算法能在不同硬件上得到正确性的执行,这样的取舍对于我们来说是相当合算的

只要简单的修改:

double limit = sqrt(n) + ;

IsPrime算法本身是一个非常简单的,但其中的细节却值得我们引起足够的重视。

一个由IsPrime算法引发的细节问题的更多相关文章

  1. 【红外DDE算法】数字细节增强算法的缘由与效果(我对FLIR文档详解)

    [红外DDE算法]数字细节增强算法的缘由与效果(我对FLIR文档详解) 1. 为什么红外系统中图像大多是14bit(甚至更高)?一个红外系统的性能经常以其探测的范围来区别,以及其对最小等效温差指标.首 ...

  2. ZeroMQ接口函数之 :zmq_z85_decode – 从一个用Z85算法生成的文本中解析出二进制密码

    ZeroMQ 官方地址 :http://api.zeromq.org/4-0:zmq_z85_decode zmq_z85_decode(3)         ØMQ Manual - ØMQ/4.1 ...

  3. 一个UUID生成算法的C语言实现 --- WIN32版本 .

    一个UUID生成算法的C语言实现——WIN32版本   cheungmine 2007-9-16   根据定义,UUID(Universally Unique IDentifier,也称GUID)在时 ...

  4. 一个简单的算法,定义一个长度为n的数组,随机顺序存储1至n的的全部正整数,不重复。

    前些天看到.net笔试习题集上的一道小题,要求将1至100内的正整数随机填充到一个长度为100的数组,求一个简单的算法. 今天有空写了一下.代码如下,注释比较详细: using System; usi ...

  5. 手动实现一个虚拟DOM算法

    发现一个好文:<深度剖析:如何实现一个 Virtual DOM 算法> 源码 文章写得非常详细,仔细看了一遍代码,加了一些注释.其实还有有一些地方看的不是很懂(毕竟我菜qaq 先码 有时间 ...

  6. 自己实现一个一致性 Hash 算法

    前言 在前文分布式理论(八)-- Consistent Hash(一致性哈希算法)中,我们讨论了一致性 hash 算法的原理,并说了,我们会自己写一个简单的算法.今天就来写一个. 普通 hash 的结 ...

  7. 一个UUID生成算法的C语言实现——WIN32版本

    源: 一个UUID生成算法的C语言实现——WIN32版本

  8. 一个基于RSA算法的Java数字签名例子

    原文地址:一个基于RSA算法的Java数字签名例子 一.前言: 网络数据安全包括数据的本身的安全性.数据的完整性(防止篡改).数据来源的不可否认性等要素.对数据采用加密算法加密可以保证数据本身的安全性 ...

  9. 能够满足这样要求的哈希算法有很多,其中比较著名并且应用广泛的一个哈希算法,那就是MurmurHash 算法。尽管这个哈希算法在 2008 年才被发明出来,但现在它已经广泛应用到 Redis、MemCache、Cassandra、HBase、Lucene 等众多著名的软件中。

    能够满足这样要求的哈希算法有很多,其中比较著名并且应用广泛的一个哈希算法,那就是MurmurHash 算法.尽管这个哈希算法在 2008 年才被发明出来,但现在它已经广泛应用到 Redis.MemCa ...

随机推荐

  1. (转)PQ分区魔术师中文版分区教程

    PQ分区魔术师中文版分区的图解,图文并茂很多朋友提到硬盘分区,觉得不敢轻易去尝试,怕得不偿失,深度xp系统下载在此分享下pq分区的图解详见下图: 1)这是用的雨林木风系统的光盘,其他系统盘一样 2)首 ...

  2. Yii框架中ActiveRecord使用Relations

    参考文章: http://blog.csdn.net/yjj1s/article/details/6885276 http://www.gowhich.com/blog/38 http://www.c ...

  3. nyoj 116 士兵杀敌(二)【线段树单点更新+求和】

    士兵杀敌(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5   描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军经常 ...

  4. Android开发——新特性与知识点回顾

    Fragment 用途:在一个Activity里切换界面,切换界面时只切换Fragment里面的内容 生命周期方法跟Activity一致,可以理解把其为就是一个Activity 定义布局文件作为Fra ...

  5. 常用对象API、附加:集合补充

    基本数据类型对象包装类: 为了方便操作基本数据类型值,将其封装成了对象,在对象中定义了属性和行为丰富了该数据的操作. 用于描述该对象的类就称为基本数据类型对象包装类. byte——Byte short ...

  6. HTML5实践之歌词同步播放器

    歌曲播放我们会发现他的兼容性不是很好,譬如IE上能播放的flash播放器,再firfox或者chrome上就不是很好的应用了,因为有插件的阻碍!HTML5的出现让这一切成为了可能,但是播放器虽然播放了 ...

  7. Ajax-$.ajax()方法详解

    jquery中的ajax方法参数总是记不住,这里记录一下. 1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为String类型的参数,请求方式(p ...

  8. hdu 4651 Partition (利用五边形定理求解切割数)

    下面内容摘自维基百科: 五边形数定理[编辑] 五边形数定理是一个由欧拉发现的数学定理,描写叙述欧拉函数展开式的特性[1] [2].欧拉函数的展开式例如以下: 亦即 欧拉函数展开后,有些次方项被消去,仅 ...

  9. StirngUtil工具类 之 邮箱注冊 域名不区分大写和小写方法

    /** * 传入邮箱域名所有变为小写,然后拼接前缀返回 *<b>Summary: </b> * emailDomainTransform() * @param domain * ...

  10. CPP: 跨平台生成GUID/UUID

    #ifndef XGUID_H#define XGUID_H #include <string>#include <stdio.h>#ifdef WIN32#include & ...