闲来没事了解一下随机算法:
一,生成随机数的算法有几种,常见的包括下面几种:
-
伪随机数生成器:这种算法基于确定性过程生成一系列的数字序列,看起来是随机的。在计算机中,常用的伪随机数生成算法包括线性同余法、梅森旋转算法等。
-
真随机数生成器:这种算法利用物理过程或环境中的不确定性事件来生成随机数。例如,利用硬件设备中的噪声、放射性衰变等物理过程来获取真正的随机数。
-
加密函数:加密函数常常被用来生成随机数。这些函数利用密钥和输入数据的组合来生成看起来随机的输出。例如,可以使用哈希函数,将一个种子值或密钥与实际需要的随机数范围进行组合计算。
-
数学算法:除了上述的算法,还有一些数学方法能够生成随机数。例如,拉格朗日插值、线性变换等。
需要特别注意的是,无论是伪随机数生成器还是真随机数生成器,它们都不是完全的随机。伪随机数生成器是确定性的,它们的输出是基于一个固定的种子或状态值。真随机数生成器虽然使用物理过程,但往往需要通过硬件设备来采集随机性的来源。
二,go语言中实现真随机
在 Go 语言中,要实现真随机数生成,可以使用硬件随机数生成器(Hardware Random Number Generator, HRNG)或者从外部随机源获取数据。
Go 语言的标准库 crypto/rand 提供了一种方式来获取真随机数,具体的实现如下:
package main
import (
"crypto/rand"
"fmt"
"log"
)
func main() {
randomBytes := make([]byte, 4)
_, err := rand.Read(randomBytes)
if err != nil {
log.Fatal(err)
}
randomNumber := int(randomBytes[0])<<24 | int(randomBytes[1])<<16 | int(randomBytes[2])<<8 | int(randomBytes[3])
fmt.Println(randomNumber)
}
在上面的示例中,我们使用了 rand.Read() 函数来从 crypto/rand 包中的默认源获取真随机字节序列。然后,我们将获取到的随机字节转换为一个整数类型的随机数。
请注意,rand.Read() 函数在获取真随机数时可能会阻塞,这取决于底层操作系统的实现和可用的随机源。另外,真随机数生成函数的可用性也取决于操作系统的支持。
因此,如果你需要更可靠和高质量的真随机数,建议使用专门的硬件设备或第三方真随机数服务来获取随机数。同时,确保在生成随机数时采取适当的安全措施和异常处理,以防止出现错误。
三,线性同余算法
线性同余算法是一种常见的伪随机数生成算法,它可以生成一系列看起来随机的数字序列。该算法基于一个递推关系,并使用线性变换来生成下一个随机数。
下面是线性同余算法的基本原理:
定义三个参数:
X0:种子值或初始值,表示生成随机数的起始点。
a:乘法因子,用于控制序列中的间隔。
c:偏移量,用于控制序列中的移动。
生成随机数的递推关系:
Xn = (a * Xn-1 + c) % m,其中 Xn 表示第 n 个随机数,% 表示取模操作,m 表示模数。
通过不断应用递推关系,线性同余算法可以生成一系列伪随机数。
请注意,线性同余算法的质量取决于选择的参数和模数。不当的参数选择可能导致生成的随机数序列具有一些可预测的模式或重复性。
因此,在实际应用中,如果需要高质量的伪随机数序列,建议选择更复杂和安全的伪随机数生成算法,或者使用真随机数生成器。
package main
import (
"strconv"
)
func myRand(seed, kMultiplier, incNum, kModer int) int {
return (kMultiplier*seed + incNum) % kModer
}
func main() {
//seed := 0 // 初始种子值
//a := 1103515245 // 乘数
//c := 12345 // 增量
//m := 1 << 31 // 模数,选择一个大于0的数,一般取 2^31
//n := 10 // 生成的随机数个数
//seed := 11 // 初始种子值
kMultiplier := 3125 // 乘数
incNum := 12345 // 增量
kModer := 34359738337 // 模数,选择一个大于0的数,一般取 2^31
n := 1000000
myMap := make(map[int]int)
i := 1
for {
number := myRand(i, kMultiplier, incNum, kModer)
v, ok := myMap[number]
if ok {
myMap[number] = v + 1
} else {
myMap[number] = 1
}
i++
if i > n {
break
}
}
//for c, v := range myMap {
// println("出现数值:" + strconv.Itoa(c) + " 出现次数:" + strconv.Itoa(v))
//}
numMap := make(map[int]int)
for _, value := range myMap {
a, ok := numMap[value]
if ok {
numMap[value] = a + 1
} else {
numMap[value] = 1
}
}
for c, v := range numMap {
println("出现次数:" + strconv.Itoa(c) + "次 共几个种子数:" + strconv.Itoa(v))
}
}