We can face our problem.
We can arrange such facts as we have
with order and method.
我们能够面对我们的问题。
我们可以解决它们,
因为我们有规则和方法。
目录
一、数学准备
1.数学归纳法
设 P(n) 是关于整数 n 的一个命题。例如,P(n) 可以是类似 “n 乘以 (n + 3) 是一个偶数” 这样的一个命题。假设我们要证明:对于所有的正整数 n,P(n) 这个命题都是成立的,也就是说,对于所有的正整数 n,P(n) 为真。实现这一点的一个重要方法是:
(a)给出 P(1) 为真的证明;
(b)假设 P(1)、P(2)、P(3) .... P(n) 都为真,给出 P(n + 1) 也为真的证明;这个证明应该对任何正整数 n 都为真。
2.每个大于 1 的整数都可以写成一个或多个素数的乘积(一个素数被认为是 1 和它自身的乘积)。
证明过程:
当 n = 2 时,2 是素数,且 2 = 1 * 2,结论显然成立;
假设当 n = 2,3,4 .... k 时,结论成立。
当 n = k + 1 时,考虑下列两种情况:
(1)k + 1 是素数,结论成立;
(2)k + 1 是合数
合数的定义:数是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。
由合数的定义可得,存在大于 1 且小于 k +1 的整数 n,m,使得 n * m = k + 1。
显然,n,m 大于 1 且小于 k + 1,符合假设的条件,则 n,m 可以分解为一个或多个素数的乘积,所以 k + 1 也能。
得证。
二、算法分析
本算法分为两个不同的部分:步骤 P1 ~ P8 准备一个500个素数的内部表,而 P9 ~ P11 准备是以 10 列,每列 50 个数的表的形式打印出答案。算法的后边部分用了两个 “缓冲区”,在其中形成行的映像;在打印一个缓冲区内容的同时,往另一个缓冲区送入数。
P1.【开始造表】置 Prime[0] = 2,N = 3,J = 1;(在这个算法中,N 取遍作为素数候选者的奇数;J 记住迄今为止已经求出了多少个素数。)
P2.【N 是素数】置 J = J + 1,Prime[J] = N;
P3.【找到 500 个了?】如果 J = 500,转到 P9;
P4.【增加 N】置 N = N + 2;
P5.【K = 1】置 K = 1;(Prime[K] 将取遍 N 的所有素因子,K 之所以不从 0 开始取,是因为 Prime[0] 等于 2,而我们的 N 取的是奇数,所以 K 从 1 开始取)
P6.【N / Prime[K]?】以 N 除以 Prime[K],设 Q 为商,R 为余数。如果 R = 0(因此 N 不是素数),则转 P4;
P7.【Prime[K] 足够大了吗?】如果 Q <= Prime[K],转 P2;(在这样的情况下,N 必定为素数)
P8.【K 加 1】K + 1,并转 P6;
P9.【打印标题】现在我们已经做好打印表的准备,把打印机推进到下一页,置 Buffer[0] 为标题行并打印此行。置 B = 1,M = 0;
P10.【设置行】以适当格式把 Prime[M],Prime[50 + M],... Prime[450 + M] 放进 Buffer[B] 中;
P11.【打印行】打印 Buffer[B];置 B = 1 - B(因此转到另一个缓冲区);且 M + 1,若 M <= 50,返回 P10,否则算法终止。
WARNING:因为 Knuth 是使用一种叫做 MIXAL 的汇编语言来实现算法P,而我们是使用 C 语言来实现,所以可以省去 P9 ~ P11。
三、算法实现
#include <stdio.h>
#define Numbers 500
int cycles;
int prime_list(int* prime, int num) {
int n, j, k;
int q, r;
int skip = 0;
prime[0] = 2;
n = 3;
for (j = 1; j < num; j++) {
prime[j] = n;
while (n += 2) {
for (k = 2; ; k++) {
cycles += 1;
q = n / prime[k - 1];
r = n % prime[k - 1];
if (r == 0) {
break;
}
if (q <= prime[k - 1]) {
skip = 1;
break;
}
}
if (skip) {
skip = 0;
break;
}
}
}
return 0;
}
int printf_prime(int* prime, int num) {
int i;
printf("First\t\tFive\t\tHunderd\t\tPrimes");
for (i = 0; i < num; i++) {
if (i % 10 == 0) {
printf("\n");
}
printf("%7ld", prime[i]);
}
printf("\n");
return 0;
}
int main() {
int Primes[Numbers];
prime_list(Primes, Numbers);
printf_prime(Primes, Numbers);
printf("\ncycles: %d\n", cycles);
return 0;
}