【scala原理系列】scala Random原理方法示例源码详解
由来原理
Scala中的Random
类实际上是对Java中的java.util.Random
类的封装。Random
类用于生成伪随机数序列。
java.util.Random
类是基于线性同余法(linear congruential generator)实现的。该算法使用一个线性递归关系来产生下一个随机数,通过对种子值进行一系列的数学运算得到新的种子值,并返回一个新的伪随机数。
具体而言,java.util.Random
类使用了以下公式生成随机数:
seed = (seed * multiplier + addend) & mask
其中seed
为当前种子值,multiplier
和addend
是固定的常数,mask
是一个位掩码,用于限制种子值的范围。
在Scala中,Random
类提供了与java.util.Random
类相似的方法,以便生成各种类型的随机数。它还提供了一些额外的辅助方法,如shuffle()
用于对集合进行乱序操作,以及alphanumeric
用于生成包含字母数字字符的无限流。
需要注意的是,由于Random
类是基于伪随机数生成器实现的,因此生成的随机数序列实际上是可预测的。如果需要更安全的随机数,可以考虑使用SecureRandom
类,它提供了更强的随机性和安全性。
方法总结
Random类中的方法归纳为以下几类:
-
构造函数:
- Random(seed: Long)
- Random(seed: Int)
- Random()
-
生成随机数的方法:
- nextBoolean(): Boolean
- nextBytes(bytes: Array[Byte])
- nextDouble(): Double
- nextFloat(): Float
- nextGaussian(): Double
- nextInt(): Int
- nextInt(n: Int): Int
- nextLong(): Long
- nextString(length: Int): String
- nextPrintableChar(): Char
-
设置种子的方法:
- setSeed(seed: Long)
-
集合操作方法:
- shuffle[T, CC[X] <: TraversableOnce[X]](xs: CC[T])(implicit bf: CanBuildFrom[CC[T], T, CC[T]]): CC[T]
-
辅助方法:
- alphanumeric: Stream[Char] (返回一个无限流,包含伪随机选择的字母数字字符)
示例
package com.test
import scala.util.Random
object RandomExample {
def main(args: Array[String]): Unit = {
val random = new Random()
// 构造函数
val random1 = new Random(123)
val random2 = new Random()
// 生成随机数的方法
val randomBoolean = random.nextBoolean()
val byteArray = new Array[Byte](10)
random.nextBytes(byteArray)
val randomDouble = random.nextDouble()
val randomFloat = random.nextFloat()
val randomGaussian = random.nextGaussian()
val randomNumber = random.nextInt()
val randomRange = random.nextInt(100)
val randomLong = random.nextLong()
val randomString = random.nextString(10)
val randomChar = random.nextPrintableChar()
// 设置种子的方法
random.setSeed(123)
// 集合操作方法
val list = List(1, 2, 3, 4, 5)
val shuffledList = random.shuffle(list)
// 辅助方法
val alphanumericStream = Random.alphanumeric.take(10)
println(s"随机布尔值: $randomBoolean")
println(s"随机字节数组: ${byteArray.mkString(", ")}")
println(s"随机浮点数: $randomDouble")
println(s"随机单精度浮点数: $randomFloat")
println(s"随机高斯分布数: $randomGaussian")
println(s"随机整数: $randomNumber")
println(s"指定范围的随机整数 (0-99): $randomRange")
println(s"随机长整数: $randomLong")
println(s"随机字符串: $randomString")
println(s"随机可打印字符: $randomChar")
println(s"乱序列表: $shuffledList")
println(s"字母数字字符流: ${alphanumericStream.mkString("")}")
}
//
// 随机布尔值: true
// 随机字节数组: 35, -36, -41, -91, 83, 38, -32, -111, 12, -70
// 随机浮点数: 0.5518785149199524
// 随机单精度浮点数: 0.93259364
// 随机高斯分布数: 0.3538112818168405
// 随机整数: 719458198
// 指定范围的随机整数 (0-99): 74
// 随机长整数: 3370252708777509741
// 随机字符串: ?患?崡巍?鈬???
// 随机可打印字符: x
// 乱序列表: List(2, 4, 5, 1, 3)
// 字母数字字符流: JTrme7RjeX
}
中文源码分析
package scala
package util
import scala.collection.mutable.ArrayBuffer
import scala.collection.generic.CanBuildFrom
import scala.collection.immutable.{ List, Stream }
import scala.language.{implicitConversions, higherKinds}
/**
* Random类是一个随机数生成器,提供了一系列的方法用于生成不同类型的随机数。
*
* @param self 一个java.util.Random对象,用于实现具体的随机数生成逻辑
*/
class Random(val self: java.util.Random) extends AnyRef with Serializable {
/** 使用一个long类型的种子创建一个新的随机数生成器 */
def this(seed: Long) = this(new java.util.Random(seed))
/** 使用一个int类型的种子创建一个新的随机数生成器 */
def this(seed: Int) = this(seed.toLong)
/** 创建一个新的随机数生成器 */
def this() = this(new java.util.Random())
/** 从该随机数生成器的序列中返回下一个伪随机、均匀分布的boolean值 */
def nextBoolean(): Boolean = self.nextBoolean()
/** 生成随机字节并将它们放入用户提供的字节数组中 */
def nextBytes(bytes: Array[Byte]) { self.nextBytes(bytes) }
/** 从该随机数生成器的序列中返回下一个伪随机、均匀分布的double值(范围在0.0到1.0之间) */
def nextDouble(): Double = self.nextDouble()
/** 从该随机数生成器的序列中返回下一个伪随机、均匀分布的float值(范围在0.0到1.0之间) */
def nextFloat(): Float = self.nextFloat()
/** 从该随机数生成器的序列中返回下一个伪随机、高斯(“正态”)分布的double值,均值为0.0,标准差为1.0 */
def nextGaussian(): Double = self.nextGaussian()
/** 从该随机数生成器的序列中返回下一个伪随机、均匀分布的int值 */
def nextInt(): Int = self.nextInt()
/** 从该随机数生成器的序列中返回一个伪随机、均匀分布的int值,范围在0(包括)到指定值(不包括)之间 */
def nextInt(n: Int): Int = self.nextInt(n)
/** 从该随机数生成器的序列中返回下一个伪随机、均匀分布的long值 */
def nextLong(): Long = self.nextLong()
/** 返回一个伪随机生成的字符串。该方法并未采取任何措施来保持分布的随机性,
* 如Unicode的可变长度编码等,因此请勿将其用于重要用途。
* 主要用于生成测试数据。
*
* @param length 字符串的长度
* @return 生成的字符串
*/
def nextString(length: Int) = {
def safeChar() = {
val surrogateStart: Int = 0xD800
val res = nextInt(surrogateStart - 1) + 1
res.toChar
}
List.fill(length)(safeChar()).mkString
}
/** 返回一个伪随机、均匀分布的ASCII码在33-126之间的字符 */
def nextPrintableChar(): Char = {
val low = 33
val high = 127
(self.nextInt(high - low) + low).toChar
}
def setSeed(seed: Long) { self.setSeed(seed) }
/** 返回一个以随机顺序排列的相同类型的新集合。
*
* @return 排列后的集合
*/
def shuffle[T, CC[X] <: TraversableOnce[X]](xs: CC[T])(implicit bf: CanBuildFrom[CC[T], T, CC[T]]): CC[T] = {
val buf = new ArrayBuffer[T] ++= xs
def swap(i1: Int, i2: Int) {
val tmp = buf(i1)
buf(i1) = buf(i2)
buf(i2) = tmp
}
for (n <- buf.length to 2 by -1) {
val k = nextInt(n)
swap(n - 1, k)
}
(bf(xs) ++= buf).result()
}
/** 返回一个无限流,其中包含伪随机选择的字母数字字符,
* 均等地从A-Z、a-z和0-9中选择。
*
* @since 2.8
*/
def alphanumeric: Stream[Char] = {
def nextAlphaNum: Char = {
val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
chars charAt (self nextInt chars.length)
}
Stream continually nextAlphaNum
}
}
/** Random对象是scala.util.Random的默认实现,提供了一些与随机数相关的便利方法。
*
* @since 2.8
*/
object Random extends Random {
implicit def javaRandomToRandom(r: java.util.Random): Random = new Random(r)
}