Eratosthenes筛法的F#实现

简介:

什么是Eratosthenes筛法

考虑一个常见的数论问题,指定一个整数,求出不大于该数的所有质数。我们可以先写一个函数来判断某个整数是否为质数,然后用它逐一判断每个整数,而Eratosthenes筛法比这种方法高效得多。

下面举例来说明它的原理。观察下面的彩图(来自wikipedia),这里是检查120以内的所有质数。首先去掉1,因为1既不是质数也不是合数;然后2是质数,那么2的倍数都肯定不是质数了,所以把2的倍数都涂成红色(它们出局了,这里是质数的游戏...);接下来3没有被涂掉,所以3是质数,同理把3的倍数涂成绿色;下一个未涂掉的是5,所以5也是质数,同理把5的倍数涂掉;然后再涂掉7的倍数,剩下的就都是质数了。

怎么,只要看2、3、5、7就够了?这里有两个不那么容易确定的问题,一是如何依次断定3、5、7都是质数;二是为何涂掉7的倍数后就完成了。对于问题一,如果一个整数不能被比它小的所有质数整除(这里就是没被涂掉),那么我们就可以断定它是质数。另外,该筛法的依据是,对于整数n,如果它不能被不大于n的平方根(Sqrt(n))的任何质数所整除,那么n就是质数。这样就解决了问题二,对于120以内的整数,如果它不是质数,那么它必定能被不大于10的质数(也就是2、3、5、7)所整除。

这样我们可以确信上述算法是正确的了,下面来看看如何实现它。

Eratosthenes筛法的C#和F#实现

 

复制代码
C# Code - Eratosthenes筛法
// 返回不大于n的质数构成的数组
public static int[] SieveOfEratosthenes(int n)
{
if (n < 2) { return new int[0]; }

// Init sieve.
bool[] sieve = new bool[n + 1];
for (int i = 2; i < sieve.Length; i++) { sieve[i] = true; }

// Check it.
int upperBound = Convert.ToInt32(Math.Sqrt(n));
for (int i = 2; i <= Math.Sqrt(n); i++)
{
if (sieve[i])
{
for (int j = i + i; j <= n; j += i)
{
sieve[j]
= false;
}
}
}

// Count it.
int count = 0;
for (int i = 2; i < sieve.Length; i++)
{
if (sieve[i])
{
count
++;
}
}

// Generate the result.
int[] primes = new int[count];
int index = 0;
for (int i = 2; i < sieve.Length; i++)
{
if (sieve[i])
{
primes[index
++] = i;
}
}

return primes;
}
复制代码

 

下面是F#实现,其中getInt和main是辅助函数:

 

复制代码
F# Code - Eratosthenes筛法
#light
open System

let generatePrimes n =
match n with
| _ when n < 2 -> [||]
| _ ->
// Init sieve.
let sieve = [| for i in 0 .. n do yield true |]

let isPrime index = sieve.[index]

// Check it.
let upperBound = Convert.ToInt32(Math.Sqrt((float)n))
for i = 2 to upperBound do
if isPrime i then
for j in [i * 2 .. i .. sieve.Length - 1] do
sieve.[j]
<- false

let mutable count = 0
for i = 2 to sieve.Length - 1 do
if isPrime i then
count
<- count + 1

let primes = Array.create count 0
let mutable index = 0
for i = 2 to sieve.Length - 1 do
if isPrime i then
primes.[index]
<- i
index
<- index + 1

primes

let getInt() =
Convert.ToInt32(Console.ReadLine())

let main() =
let i = getInt()
let primes = generatePrimes i
Console.WriteLine(
"find {0} prime(s)", primes.Length)
print_any primes

main()

Console.Read()
复制代码

 

这两段代码也就勉强能实现算法吧,有时间再考虑优化一下。

(要了解本人所写的其它F#随笔请查看 F#系列随笔索引

参考:

Sieve of Eratosthenes


本文转自一个程序员的自省博客园博客,原文链接:http://www.cnblogs.com/anderslly/archive/2008/11/11/fsharp-sieve-of-eratosthenes.html,如需转载请自行联系原作者。

目录
相关文章
|
Kubernetes Java 应用服务中间件
制作容器镜像的最佳实践
制作容器镜像的最佳实践
|
机器学习/深度学习 存储 人工智能
【NLP】Datawhale-AI夏令营Day6-7打卡:大模型
【NLP】Datawhale-AI夏令营Day6-7打卡:大模型
|
8月前
|
安全 UED 索引
鸿蒙特效教程06-可拖拽网格实现教程
本教程适合 HarmonyOS Next 初学者,通过简单到复杂的步骤,一步步实现类似桌面APP中的可拖拽编辑效果。
236 1
鸿蒙特效教程06-可拖拽网格实现教程
|
Web App开发 JavaScript 前端开发
深入浅出Node.js: 打造高效后端服务
【10月更文挑战第39天】在数字化浪潮中,后端开发作为支撑现代Web应用的骨架,扮演着不可或缺的角色。Node.js,作为一种流行的服务器端JavaScript运行环境,因其非阻塞I/O和事件驱动的特性,被广泛应用于构建轻量且高效的后端服务。本文旨在通过浅显易懂的语言,结合生动的比喻和实际代码案例,带领读者深入理解Node.js的核心概念、架构设计及其在后端开发中的应用,进而掌握如何使用Node.js搭建稳定、可扩展的后端服务。无论你是初探后端开发的新手,还是寻求进阶的开发者,这篇文章都将为你提供有价值的指导和启示。
|
网络协议 安全 Shell
[笔记]Windows安全之《一》反弹Shell
Windows安全之《一》反弹Shell
1145 0
[笔记]Windows安全之《一》反弹Shell
|
机器学习/深度学习 自然语言处理 监控
NLP技术有哪些主要任务?
【7月更文挑战第8天】NLP技术有哪些主要任务?
1108 4
|
监控 数据可视化 项目管理
PMP考试技巧(一)
PMP考试技巧
276 1
|
Linux Shell Docker
Alpine Docker 安装 bash
Alpine Linux是一个轻型Linux发行版,它不同于通常的Linux发行版,Alpine采用了musl libc 和 BusyBox以减少系统的体积和运行时的资源消耗。
5956 0
|
存储 数据采集 人工智能
社区供稿 I 基于Qwen-7B的垂域大模型——MindChat(漫谈)心理大模型上线魔搭
心理大模型——漫谈(MindChat)期望从心理咨询、心理评估、心理诊断、心理治疗四个维度帮助人们纾解心理压力与解决心理困惑,提高心理健康水平。
|
前端开发 C# 容器
WPF技术之Command
WPF Command是一种在MVVM(Model-View-ViewModel)模式中用于处理用户界面交互的机制。它可以将用户界面事件(如按钮点击、菜单项选择等)与应用程序逻辑(命令处理)解耦,同时提供了一种便捷的方式来管理和执行命令
553 2