C++判断一个大于2的整数是否是素数

最近在学习乔林老师的C++教学视频。在算法一节有关于判断素数的内容,感觉挺有收获的,就想着跟大家分享一下。现在,让我们一起来学习吧。

1.面对素数合数检验,我们很容易就联想到暴力穷举的算法。
例如以下例程:

/*解法一*/
bool IsPrime_1(unsigned int n)
{
	unsigned int i = 2;
	while (i<n)
	{
		if (n%i == 0)
		{
			return false;
		}
		i++;
	}
	return true;
}

2.接下来,我们给这个算法改进下,提高它的效率。

分析:
如果这个数是合数,那么这个数一定可以写成n=p*q的形式。
这个数一定有一个小于或者等于根号n的因子,那么可以改判断条件i <= (unsigned int)sqrt(n);
现在程序循环次数由2 ~ n -1,直接降低到2 ~ 根号n。效率大大提高。

bool IsPrime_2(unsigned int n)
{
	unsigned int i = 2;
	while (i <= (unsigned int)sqrt(n))
	{
		if (n%i == 0)
		{
			return false;
		}
		i++;
	}
	return true;
}

3.继续来改进这个小算法。

分析:
如果这个数是合数,那么这个数整除2。
接下来从3开始除,不用除以偶数,只除以奇数就可以去遍历。
效率又可以比上一个版本提高一倍。

bool IsPrime_3(unsigned int n)
{
	unsigned int i = 3;
	if (n%i == 0)
	{
		return false;
	}
	while (i <= (unsigned int)sqrt(n))
	{
		if (n%i == 0)
		{
			return false;
		}
		i += 2;
	}
	return true;
}

4.难以发现的隐含bug。

分析:
sqrt(),会得到一个浮点数的结果。
假设:该数字为完全平方数121,经过sqrt()开根号后就是11.000000000。
但是我们学过计算机组成原理都知道,浮点数在计算机内部存储有误差。
那11.000000000就可能被表示为11.000000001。或者10.999999999。
如果是前一种还好,如果是后一种程序就会出大问题咯。因为10.999999999
转换成unsigned int时,会把小数部分省掉,就是10。循环标准由11变成10,当然会出问题。
我们就给它+1来解决这个隐含的bug。

bool IsPrime_4(unsigned int n)
{
	unsigned int i = 3;
	if (n%i == 0)
	{
		return false;
	}
	while (i <= (unsigned int)sqrt(n) + 1)
	{
		if (n%i == 0)
		{
			return false;
		}
		i += 2;
	}
	return true;
}

5.最后的优化。

分析:
我们现在思考,函数传入的参数n是个定值,那么我们只用求一次sqrt(n)就够了,
没必要每次循环都求一个sqrt(n)。这样再也不用重复计算啊sqrt(n)了, 只在进入while()之前
计算一次就够了。这样效率又一次大大提高!

bool IsPrime_5(unsigned int n)
{
	unsigned int i = 3, t = (unsigned int)sqrt(n) + 1;
	if (n%i == 0)
	{
		return false;
	}
	while (i <= t)
	{
		if (n%i == 0)
		{
			return false;
		}
		i += 2;
	}
	return true;
}

ok,完工。这个小小的算法,竟然可以优化这么多内容,感觉程序的世界真的是奇妙无比。

你可能感兴趣的:(C++随笔,C++素数判断)