All Downloads are FREE. Search and download functionalities are using the official Maven repository.

spire.random.rng.MersenneTwister64.scala Maven / Gradle / Ivy

/************************************************************************\
** Project                                                              **
**       ______  ______   __    ______    ____                          **
**      / ____/ / __  /  / /   / __  /   / __/     (c) 2011-2014        **
**     / /__   / /_/ /  / /   / /_/ /   / /_                            **
**    /___  / / ____/  / /   / __  /   / __/   Erik Osheim, Tom Switzer **
**   ____/ / / /      / /   / / | |   / /__                             **
**  /_____/ /_/      /_/   /_/  |_|  /____/     All rights reserved.    **
**                                                                      **
**      Redistribution and use permitted under the MIT license.         **
**                                                                      **
\************************************************************************/


package spire
package random
package rng

import spire.syntax.cfor._
import spire.util.Pack
import java.nio.ByteBuffer
import java.util.Arrays

/**
 * This is a 64-bit Scala implementation of MersenneTwister based on MT19937-64.c.
 *
 * 

MersenneTwister is a fast, 623-dimensionally equidistributed pseudo random number generator * with a 219937 - 1 long period. * *

Reference: * Makoto Matsumoto and Takuji Nishimura: * "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator", * ACM Transactions on Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3--30. * * @see MT19937-64.c * @see Mersenne Twister Home Page * @see Mersenne Twister @ Wikipedia * @author Dušan Kysel */ final class MersenneTwister64 protected[random](mt: Array[Long], mti0: Int = 313) extends LongBasedGenerator { // N + 1 = 313 import MersenneTwister64.{UpperMask, LowerMask, N, M, N_M, N_1, M_N, M_1, BYTES, mag01} private var mti = mti0 def copyInit: MersenneTwister64 = new MersenneTwister64(mt.clone, mti) def getSeedBytes(): Array[Byte] = { val bytes = new Array[Byte](BYTES) val bb = ByteBuffer.wrap(bytes) cfor(0)(_ < N, _ + 1) { i => bb.putLong(mt(i)) } bb.putInt(mti) bytes } def setSeedBytes(bytes: Array[Byte]): Unit = { val bs = if (bytes.length < BYTES) Arrays.copyOf(bytes, BYTES) else bytes val bb = ByteBuffer.wrap(bs) cfor(0)(_ < N, _ + 1) { i => mt(i) = bb.getLong() } mti = bb.getInt } // Generates the next random long in the sequence override def nextLong(): Long = { var x = 0L if (mti >= N) { var kk = 0 while (kk < N_M) { x = (mt(kk) & UpperMask) | (mt(kk + 1) & LowerMask) mt(kk) = mt(kk + M) ^ (x >>> 1) ^ mag01(x) kk += 1 } while (kk < N_1) { x = (mt(kk) & UpperMask) | (mt(kk + 1) & LowerMask) mt(kk) = mt(kk + (M_N)) ^ (x >>> 1) ^ mag01(x) kk += 1 } x = (mt(N_1) & UpperMask) | (mt(0) & LowerMask) mt(N_1) = mt(M_1) ^ (x >>> 1) ^ mag01(x) mti = 0 } x = mt(mti) mti += 1 // Tempering x ^= (x >>> 29) & 0x5555555555555555L x ^= (x << 17) & 0x71D67FFFEDA60000L x ^= (x << 37) & 0xFFF7EEE000000000L x ^= (x >>> 43) x } } object MersenneTwister64 extends GeneratorCompanion[MersenneTwister64, (Array[Long], Int)] { @inline private val UpperMask = 0xFFFFFFFF80000000L // = 0xFFFFFFFFFFFFFFFFL ^ Int.MinValue @inline private val LowerMask = 0x7FFFFFFFL // = Int.MinValue @inline private val N = 312 @inline private val M = 156 @inline private val N_M = N - M @inline private val N_1 = N - 1 @inline private val M_N = M - N @inline private val M_1 = M - 1 @inline private val BYTES = N * 8 + 4 @inline private def mag01(x: Long) = if ((x & 1) == 0) 0L else 0xB5026F5AA96619EL def randomSeed(): (Array[Long], Int) = (Utils.seedFromLong(N, Utils.longFromTime()), N + 1) def fromSeed(seed: (Array[Long], Int)): MersenneTwister64 = seed match { case (mt, mti) => assert(mt.length == N) new MersenneTwister64(mt, mti) } def fromArray(arr: Array[Long]): MersenneTwister64 = fromSeed((Utils.seedFromArray(N, arr), N + 1)) def fromBytes(bytes: Array[Byte]): MersenneTwister64 = fromArray(Pack.longsFromBytes(bytes, bytes.length / 8)) def fromTime(time: Long = System.nanoTime): MersenneTwister64 = fromSeed((Utils.seedFromLong(N, Utils.longFromTime(time)), N + 1)) }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy