golang 查找素数
素数的定义
素数又称为质数,指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数
2是最小的质数
算法
倍数筛选 [j=2, i*j<=n, j++]
二次筛选 [j=i*i, j<=n, j+=i]
线性筛选
创建长度为 (n -2 + 1) 的数组, 初始值都为 true
遍历[2-n] , 每次将 i 的倍数的下标设置为 false
暴力枚举
开方 因数都是成对出现,
比如,100的因数有:1和100、2和50、4和25、5和20、10和10
即成对的因数,其中一个必然小于等于100的开平方,另一个大于等于100的开平方
因此只要判断2~sqrt(n)的因数即可埃拉托斯特尼(Eratosthenes)
最后遍历数组中为 true 的元素就是素数
素数定理
素数的分布是越往后越稀疏。或者说,素数的密度是越来越低。而素数定理,
说白了就是数学家找到了一些公式,用来估计某个范围内的素数,大概有几个。
在这些公式中,最简洁的就是 x/ln(x).假设要估计1,000,000以内有多少质数,
用该公式算出是72,382个,而实际有78,498个,误差约8个百分点。
该公式的特点是:估算的范围越大,偏差率越小。
一般用x/ln x来估计某个范围内素数的个数(误差小于15%)
实现
package prime
import (
"math"
)
// IsPrime judge whether the given number is prime
type IsPrime func(n uint64) bool
// IsPrimeByRangeEnum judge whether the given number is prime
func IsPrimeByRangeEnum(n uint64) bool {
if n < 2 {
return false
}
for i := uint64(2); i < n; i++ {
if n%i == 0 {
return false
}
}
return true
}
// IsPrimeBySqrtRangeEnum judge whether the given number is prime
func IsPrimeBySqrtRangeEnum(n uint64) bool {
if n < 2 {
return false
}
for i, l := uint64(2), uint64(math.Sqrt(float64(n))); i <= l; i++ {
if n%i == 0 {
return false
}
}
return true
}
// NPrime 获取一个[2-n] 内的素数
func NPrime(n uint64, isPrime IsPrime) (ps []uint64) {
ps = make([]uint64, 0)
if n < 2 {
return
}
for i := uint64(2); i <= n; i++ {
if isPrime(i) {
ps = append(ps, i)
}
}
return
}
// NPrimeEratosthenes 埃拉托斯特尼, 最优 + 倍数筛选
func NPrimeEratosthenes(n uint64) (ps []uint64) {
ps = make([]uint64, 0)
if n < 2 {
return ps
}
N := make([]bool, n+1) // false: 素数, true: 不是素数
for i, l := uint64(2), uint64(math.Sqrt(float64(n))); i <= l; i++ {
if N[i] == false {
for j := uint64(2); i*j <= n; j++ {
N[i*j] = true // 倍数筛选: 同一元素会重复删除
}
}
}
for i, l := uint64(2), n+1; i < l; i++ {
if N[i] == false {
ps = append(ps, i)
}
}
return ps
}
// NPrimeEratosthenes2 埃拉托斯特尼 + 二次筛选法
func NPrimeEratosthenes2(n uint64) (ps []uint64) {
ps = make([]uint64, 0)
if n < 2 {
return ps
}
N := make([]bool, n+1) // false: 素数, true: 不是素数
for i, l := uint64(2), uint64(math.Sqrt(float64(n))); i <= l; i++ {
if N[i] == false {
for j := i * i; j <= n; j += i {
N[j] = true // 二次筛选法: 假设每次i是素数,则下一个起点是 i*i ,把后面 [i*i, i*(i+1), i*(i+2), ..., n] 全部移除
}
}
}
for i, l := uint64(2), n+1; i < l; i++ {
if N[i] == false {
ps = append(ps, i)
}
}
return ps
}
// NPrimeEratosthenesLine 埃拉托斯特尼 + 线性筛选
func NPrimeEratosthenesLine(n uint64) (ps []uint64) {
ps = make([]uint64, 0)
if n < 2 {
return ps
}
N := make([]bool, n+1) // false: 素数, true: 不是素数
P := make([]uint64, n+1) // 保存素数
count := uint64(0) // 素数的个数
for i := uint64(2); i <= n; i++ {
if N[i] == false {
P[count] = i
count++
}
for j := uint64(0); j < count && P[j]*i <= n; j++ {
N[P[j]*i] = true
a := make([]uint64, n+1)
for i, v := range N {
if v {
a[i] = 1
}
}
if i%P[j] == 0 { // 保证每个合数只会被它的最小质因数筛去,因此每个数只会被标记一次,所以时间复杂度是O(n)
break
}
}
}
for i, l := uint64(2), n+1; i < l; i++ {
if N[i] == false {
ps = append(ps, i)
}
}
return ps
}复制
// 基准测试
var N = uint64(100000)
func BenchmarkNprimeIsPrime(b *testing.B) {
for i := 0; i < b.N; i++ {
NPrime(N, IsPrimeByRangeEnum)
}
}
func BenchmarkNprimeIsPrimeBySqrtRangeEnum(b *testing.B) {
for i := 0; i < b.N; i++ {
NPrime(N, IsPrimeBySqrtRangeEnum)
}
}
func BenchmarkNPrimeEratosthenes(b *testing.B) {
for i := 0; i < b.N; i++ {
NPrimeEratosthenes(N)
}
}
func BenchmarkNPrimeEratosthenes2(b *testing.B) {
for i := 0; i < b.N; i++ {
NPrimeEratosthenes2(N)
}
}
func BenchmarkNPrimeEratosthenesLine(b *testing.B) {
for i := 0; i < b.N; i++ {
NPrimeEratosthenesLine(N)
}
}复制
测试结果:
goos: darwin
goarch: amd64
pkg: github.com/feiquan123/algorithm/prime
// 暴力计算 n*n
BenchmarkNprimeIsPrime-8 1 3182596148 ns/op
// 暴力计算 n*sqrt(n)
BenchmarkNprimeIsPrimeBySqrtRangeEnum-8 55 20153547 ns/op
// 埃拉托斯特尼 - 倍数筛选
BenchmarkNPrimeEratosthenes-8 3261 334561 ns/op
// 埃拉托斯特尼 - 二次筛选
BenchmarkNPrimeEratosthenes2-8 3382 338191 ns/op
// 埃拉托斯特尼 - 线性筛选
BenchmarkNPrimeEratosthenesLine-8 1 23504143006 ns/op
PASS
ok github.com/feiquan123/algorithm/prime 30.136s复制
文章转载自编程之恋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
数据库国产化替代深化:DBA的机遇与挑战
代晓磊
1222次阅读
2025-04-27 16:53:22
2025年4月国产数据库中标情况一览:4个千万元级项目,GaussDB与OceanBase大放异彩!
通讯员
690次阅读
2025-04-30 15:24:06
数据库,没有关税却有壁垒
多明戈教你玩狼人杀
590次阅读
2025-04-11 09:38:42
国产数据库需要扩大场景覆盖面才能在竞争中更有优势
白鳝的洞穴
575次阅读
2025-04-14 09:40:20
【活动】分享你的压箱底干货文档,三篇解锁进阶奖励!
墨天轮编辑部
496次阅读
2025-04-17 17:02:24
一页概览:Oracle GoldenGate
甲骨文云技术
471次阅读
2025-04-30 12:17:56
GoldenDB数据库v7.2焕新发布,助力全行业数据库平滑替代
GoldenDB分布式数据库
466次阅读
2025-04-30 12:17:50
优炫数据库成功入围新疆维吾尔自治区行政事业单位数据库2025年框架协议采购!
优炫软件
355次阅读
2025-04-18 10:01:22
国产数据库图谱又上新|82篇精选内容全览达梦数据库
墨天轮编辑部
269次阅读
2025-04-23 12:04:21
MySQL 30 周年庆!MySQL 8.4 认证免费考!这次是认真的。。。
数据库运维之道
247次阅读
2025-04-28 11:01:25