质数判断算法优化 之 (哥德巴赫猜想8位数验证)

质数判断算法优化 之 (哥德巴赫猜想8位数验证)

这是一篇有关解决哥德巴赫猜想10位数验证的的c语言问题,最主要的算法优化在于质数判断。
最终,8位数哥德巴赫猜想验证总共用时5.328秒.期待继续优化。

思维导图先上
在这里插入图片描述

一,明确问题

什么是哥德巴赫猜想?

即任一大于2的偶数都可写成两个素数(也叫质数)之和。
百度百科:https://baike.baidu.com/item/%E5%93%A5%E5%BE%B7%E5%B7%B4%E8%B5%AB%E7%8C%9C%E6%83%B3/72364

二,分析问题

1.质数

定义:质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。

2.质数的范围

大于2的偶数(num),它等于一个数(i)与另一个数的和(num - i)。所以,i 与(num - i)的范围
是质数的范围。

3.质数的判断

判断 i 与(num - i)是不是质数,可以一个函数专门解决。

三,解决问题

1.0解决版本

1)质数范围问题解决:从2遍历到原数

2)质数判断问题解决:Num和所有比它小的数取余

**验证歌德巴赫猜想函数:**从四开始的偶数

void checkGoldBach(int Maxnum) {
	int num;
	for (num = 4; num < Maxnum; num += 2) {   //从4开始的偶数
		if(!canResolve(num)) {
			printf("这个数%d无法分解为两个质数,哥德巴赫也要学学编程",num);
			return;
		}
	}
	printf("哥德巴赫猜想不亏为“数学王冠上的明珠”!\n");
}

分解偶数函数: 从哪个范围里找质数-----从2遍历到原数

boolean canResolve(int num) {
	int i;
	for (i = 3; i < num; i += 2) {   //为什么不是从质数2开始?因为偶数减2必然是偶数,
	                                //所以从3开始,+=2,避免分解偶数
		if (isprime(i) && isprime(num - i)) {
			printf("%d = %d + %d\n",num, i, (num - i) );
			return TRUE;
		}
	}
	return FALSE;
}

判断质数函数: Num和所有比它小的数取余

boolean isprime(int num) {
	int i;
	for (i = 2; i < num && num % i; i++) {
		;    //Num和所有比它小的数取余
	}
	return i >=num;
}

验证:10000以内的哥德巴赫猜想
在这里插入图片描述
但是,效果不好所以,2.0版本就得出世了

2.0版本

1)质数范围问题解决:

思考: 从 i 开始遍历,判断 i 与 (num - i)是不是质数,那么当 i 大于 (num / 2)时,遍历此时无意义。
例如: 偶数18 先判断 3 与 15,接着 5 与 13 ,(假设·继续)接着 7 与 11, 接着 9 和 9 ,
接着 11 与 7 此时就无意义了。两个质数最大都为原数的一半,例如 6 = 3 + 3, 10 = 5 + 5.

所以,此处只用遍历到原数的一半
在这里插入图片描述

2)质数判断问题解决:

思考: (i = 2; i <num && num % i; i++), 从 i 遍历 到 num 太浪费时间。 如果 i 是偶数,偶数如果是质数的因数,那么 2 必定是,所以可以 把偶数排除。
换个说法,原数是10000,
如果 2 不是它的因数,则 5000也不是它的因数,那么在5001 ~ 10000也肯定找不到它的因数,
同样,3不是他的因数,那么3333也不是他的因数,则3334 ~ 5000 里也不存在它的因数。
于是,4 与 2500 ,5与 2000等等
直到,10000^0.5 = 100 是,此时100 ~ 10000以后的数都不需要找因数,只用看2 到 100.
所以,从 2遍历到原数的开方,就足够。

在这里插入图片描述
运行
在这里插入图片描述

3.0版本?

不不,不是的。细心的你可能发现了,boolean,这是什么东东?
一个真假的定义。1 代表TRUE ,0代表 FALSE,增强代码可读性。建立在一个.h文件里。
直接建立在同一文件夹就行。
在这里插入图片描述

#ifndef _MEC_H_
#define _MEC_H_

typedef unsigned char boolean;   //用于真假声明
#define		TRUE		1     
#define		FALSE		0
#define		NOT_FOUND	-1

#endif

记得在调用此库文件。
在这里插入图片描述

真 3.0版本

1)质数范围问题解决:还有更好的吗?也许。

2)质数判断问题解决:

引入一个思想,自幂数查找里讲过,以空间换时间,建立一个质数池子。怎么建?
看图:

在这里插入图片描述初步池子是弄好了,虽然很大。那么怎么筛选呢?
介绍一个方法 -----质数筛选法(爱拉陶斯芬筛法)
筛选的主要方法:
1.划去2的倍数;
2.划去3的倍数;
3 划去5的倍数;(4的倍数同为2的倍数,已被划去)
4.划去7的倍数;(6的倍数同为3的倍数,已被划去)
5.划去11的倍数;(8和10的倍数同为2的倍数,而9的倍数也是3的倍数)
所以验证一个数是否是素数,可以用它来除以2,3,5,7,11…)

刚才上面笔者聊到先把偶数去除,也就是该方法的雏形,
你看,2 的倍数,偶数一定不是质数, 3 的倍数也一定不是质数。如此如此。
相当于,一个数是质数,那么就可以断定他的倍数不是质数。

而且
在这里插入图片描述接下来

在这里插入图片描述构建好质数池子之后,可以使用了。
在这里插入图片描述
运行:
在这里插入图片描述

4.0版本?

是真的,不过先介绍下位运算。
在这里插入图片描述具体有关位运算会在专门文章里写一写。感觉一时半会讲不清楚。先用吧
位运算文章链接:凶悍的位运算

每一个字节都是从0~7标注下标。
在这里插入图片描述在这里插入图片描述

void screenPrime(int count) {
	int prime = 2;
	unsigned int index;   //  
	unsigned int i;
	int lastNum;

	for (index = 4; index < count; index += 2) {   
		SETB(primePool[index >> 3], index & 7);	//偶数置为1;位运算法SETB:把某一字节的指定位给置1
	}
	lastNum = (int) (sqrt(count) + 1); 
	for (index = 3; index <= lastNum; index += 2) {
	// 3的倍数置为1,接着5的倍数置为1.....
		if (!GETB(primePool[(unsigned int) index >> 3], index & 7)) {
			for (i = index * index; i < count; i += index) {
				// inde*index,这里涉及一个跳转问题,具体看质数的爱拉陶斯芬筛法。
				SETB(primePool[i >> 3], i & 7);
			}
		}
	}
}

位运算带来的变化:
在这里插入图片描述
疯狂运用位运算,
在这里插入图片描述
最终上场:主函数的的故事

int main() {
	int Maxnum;
	int i;
	long startTime;
	long midTime;
	long endTime;

	
	printf("请输入查找最大范围:");
	scanf("%d", &Maxnum);
	
	primePool = (boolean *) calloc(sizeof(boolean), (num + 7) >> 3);
	// 4到8要一个字节,9到16要两个字节。于是(4,8)+ 7 = (11,15)/ 8 == 1
	// (9, 16) + 7 = (16, 23) / 8 == 2  所以使用(num + 7) >> 3
	startTime = clock();
	screenPrime(Maxnum);
	midTime = clock();
	checkGoldBach(Maxnum);
	endTime = clock();

	midTime -= startTime;
	endTime -= startTime;

	printf("建质数池子耗时%d.%03d,总共耗时:%d.%03d\n", midTime / 1000, midTime %1000
		, endTime / 1000, endTime % 1000);
	
	free(primePool);

	return 0;

}

最后运行。
在这里插入图片描述时间上同3.0差不太多,但空间上效率却节省了3.0的87.5%的空间。完结散花!!!

三,总结

1.算法优化需要做好数学分析。方法比想法有效。

2.函数功能的单一化。越纯粹越好编写。

3.不断优化,追求卓越。接触新的,好的想法。

感谢指导老师:铁血教主
笔者水平有限,目前只能描述以上问题,如果有其他情况,可以留言,有错误,请指教,有继续优化的,请分享,谢谢!

2019年11月30日 图书馆

发布了9 篇原创文章 · 获赞 3 · 访问量 1107

猜你喜欢

转载自blog.csdn.net/Ayydead/article/details/103317107
今日推荐