Ⅰ 哥德巴赫猜想
哥德巴赫1742年给欧拉的信中哥德巴赫提出了以下猜想:任一大于2的偶数都可写成两个质数之和。但是哥德巴赫自己无法证明它,于是就写信请教赫赫有名的大数学家欧拉帮忙证明,但是一直到死,欧拉也无法证明。因现今数学界已经不使用“1也是素数”这个约定,原初猜想的现代陈述为:任一大于5的整数都可写成三个质数之和。欧拉在回信中也提出另一等价版本,即任一大于2的偶数都可写成两个质数之和。今日常见的猜想陈述为欧拉的版本。把命题"任一充分大的偶数都可以表示成为一个素因子个数不超过a个的数与另一个素因子不超过b个的数之和"记作"a+b"。1966年陈景润证明了"1+2"成立,即"任一充分大的偶数都可以表示成二个素数的和,或是一个素数和一个半素数的和"。
今日常见的猜想陈述为欧拉的版本,即任一大于2的偶数都可写成两个素数之和,亦称为“强哥德巴赫猜想”或“关于偶数的哥德巴赫猜想”。
简单来说就是,任何一个大于2的偶数都可以分解成两个素数。
这篇博客会分四个层次,将一个普通代码优化到极限。
Ⅱ 最低级算法
哥德巴赫猜想的验证由三个部分组成:判断质数,判断偶数是否可以分解成两个质数,最后判断一个范围内哥德巴赫猜想是否正确。
以下为最简单最基础的代码,同时也是优化空间最大的👇
#include <stdio.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
typedef unsigned char boolean;
boolean isPrime(int num);
boolean resolve(int num);
void inspect(int ceiling);
void inspect(int ceiling) {
int i;
for (i = 4; i <= ceiling; i += 2) {
if (!resolve(i)) {
printf("哥德巴赫猜想被证伪了!\n");
return;
}
}
printf("哥德巴赫果然很厉害!\n");
}
boolean resolve(int num) {
int i;
if (isPrime(num - 2)) {
return TRUE;
}
for (i = 3; i <= num / 2; i += 2) {
if (isPrime(i) && isPrime(num - i)) {
return TRUE;
}
}
return FALSE;
}
boolean isPrime(int num) {
int i;
for (i = 2; i < num && num % i; i++) {
;
}
return i >= num;
}
int main() {
int ceiling;
long startTime;
long endTime;
printf("请输入验证哥德巴赫猜想的最大数:");
scanf("%d", &ceiling);
startTime = clock();
inspect(ceiling);
endTime = clock();
endTime -= startTime;
printf("消耗时间:%d.%03ds", endTime / 1000, endTime % 1000);
printf("\n");
return 0;
}
测试结果如下,我们要验证100 000以下的偶数是否成立👇
可以看到,100 000以下的数耗时5.991秒,我们再验证1 000 000的👇
可以看到,我的小破电脑居然用了这么久才验证成功,即使只是增了一个0。正经人谁会等一个程序运行这么长时间啊,所以我们要逐步将其优化,将程序优化至一个正常人可以忍受的程度。
Ⅲ 没那么低级算法-> 质数判断算法优化
在最低级的代码中,我们判断质数用的是以下的代码👇
boolean isPrime(int num) {
int i;
for (i = 2; i < num && num % i; i++) {
;
}
return i >= num;
}
尽管已经足够简单,但其仍要进行一个很大的循环,每次分解一个数时都要做两次这样的循环,很浪费时间,所以第一层优化,我们先减少查询质数的循环所消耗的时间。
我之前的循环,要让i = 2一直判断到num - 1,从这里面来判断num是否有因子将其整除,我以120为例子,提供一个新的视角。
120 / 2 = 60&