📜  求素数的小林丸方法

📅  最后修改于: 2021-10-21 06:02:37             🧑  作者: Mango

有人说“伟大的工程在相互竞争的目标之间取得平衡。”我相信这在机械和软件工程中都是正确的。在后者中,竞争目标通常是清晰度、大小和速度。

因此,当南美洲的一位计算机科学家要求我编写一个简单的英语程序时,我认为这是应用这一原则的绝佳机会,该程序基于 Eratosthenes 筛法,可以计算小于 250、000 的素数第二(在沃尔玛的底层计算机上)。

现在普通英语并不是地球上最快的语言,因为当语言的主要目标是自然时,清晰度胜过速度。但是普通英语是一种相当快的语言,通过平衡相互竞争的目标,我们通常可以为摆在我们面前的任何问题找到可接受的解决方案。

在这种情况下,我们首先需要弄清楚著名的埃拉托色尼筛;容易理解。所以我们从维基百科对算法的描述开始……

……用简单的英语写成这样:

To make a list of prime numbers less than or equal to a number:
Create the list of consecutive integers from 2 to the number. \ wiki's #1
Get an entry from the list. \ wiki's #2
Loop. Mark higher multiples of the entry. \ wiki's #3
Get the entry for the next lowest possible prime. If the entry is not nil, repeat. \ wiki's #4

这需要注意清晰度目标。如果您想知道,使之真正起作用的类型定义和支持例程同样清晰:

An entry is a thing with a number and a non-prime flag.
A list is some entries.

To create a list of consecutive integers from a number to another number:
Privatize the number.
Loop.
If the number is greater than the other number, exit.
Create an entry for the number.
Append the entry to the list.
Add 1 to the number.
Repeat.

To create an entry for a number:
Allocate memory for the entry.
Put the number into the entry's number.
Clear the entry's non-prime flag.

To mark higher multiples of an entry:
Privatize the entry.
Loop.
Put the entry's next into the entry.
If the entry is nil, exit.
If the entry's number is evenly divisible by the original entry's number, 
  set the entry's non-prime flag.
Repeat.

To get an entry for the next lowest possible prime:
Put the entry's next into the entry.
If the entry is nil, exit. 
If the entry's non-prime flag is set, repeat.

这么清晰,很好。大小,不错(可执行文件只有 150k)。但是速度呢?用 4 分钟多一点的时间来列出 1 到 250, 000 之间的数字。不好。嗯……柯克船长会怎么做?如果我们为了速度而牺牲一点尺寸会怎样?毕竟,当素数从未改变时,我们为什么还要一遍又一遍地计算它们呢?所以我再次运行了这个程序,这次增加了一个像这样的例程……

To make a prime string from a list:
Put "N" into the prime string.
Loop.
Get an entry from the list.
If the entry is nil, exit.
If the entry's non-prime flag is set, append "N" to the prime string; repeat.
Append "Y" to the prime string.
Repeat.

…制作一个字符串,其中标记了所有素数。然后我将字符串保存在一个文本文件中,并将其粘贴到我称为“用于 1 到 250, 000 之间数字的超快速素数检查器”的库中。这是该库的样子:

The prime string is a string equal to "NYYNYNYNNNYNYNNNYNYNNNYNNNNNYNYNNNNN...

To decide if a number is prime (fast check):
If the number is less than 1, say no.
If the number is greater than the prime string's length, say no.
Put the prime string's first into a byte pointer.
Add the number to the byte pointer.
Subtract 1 from the byte pointer.
If the byte pointer's target is the big-Y byte, say yes.
Say no.

当然,源中的主要字符串比上面显示的要长得多。如果我们使用位而不是“Y”来标记素数,它可能会缩短 8 倍。但不得不这么认真地思考让我头疼。无论如何,这个程序……

To run:
  Start up.
  Write "Working..." on the console.
  Start a timer.
  Get a count of prime numbers less than or equal to 250000.
  Stop the timer.
  Write the count then " prime numbers." on the console.
  Write the timer's string then " milliseconds." on the console.
  Wait for the escape key.
  Shut down.

To get a count of prime numbers less than or equal to a number:
  Privatize the number.
  Clear the count.
  Loop.
  If the number is prime (fast check), add 1 to the count.
  Subtract 1 from the number.
  If the number is less than 2, break.
  Repeat.

……这非常清晰,而且相当(大约 400k),而且速度也非常。它可以在 16 毫秒或更短的时间内计算出小于或等于 250, 000 的 22, 044 个素数。而且,由于它(间接)基于 Eratosthenes 的筛子,它满足原始规范的要求!

我想柯克船长会同意的。