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

scalaprops.TinyMT32.scala Maven / Gradle / Ivy

package scalaprops

import java.math.BigInteger

import scala.annotation.tailrec

/** TinyMT is a pseudo random number generator.
  *
  * 

* To get an instance, call `TinyMT32.getDefault` *

*

* This class supports jump function. User can get an array of pseudo random * number generators by calling `TinyMT32#getDefaultArray` *

* * @author M. Saito * @see [[http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html TinyMT web page]] */ object TinyMT32 { private final case class MutableState( var st0: Int, var st1: Int, var st2: Int, var st3: Int, var param: TinyMT32Parameter ) { def asImmutable: TinyMT32 = new TinyMT32( st0 = st0, st1 = st1, st2 = st2, st3 = st3, parameter = param ) def next(): this.type = { var x = 0 var y = 0 y = st3 x = (st0 & TinyMT32.MASK) ^ st1 ^ st2 x ^= (x << TinyMT32.SH0) y ^= (y >>> TinyMT32.SH0) ^ x st0 = st1 st3 = y st1 = st2 ^ param.getMat1(y) st2 = (x ^ (y << TinyMT32.SH1)) ^ param.getMat2(y) this } } /** bit size of int. */ private val INT_SIZE: Int = 32 /** least long over int. */ private val LONG_LIMIT: Long = 0x100000000L /** initialize shift. */ private val INITIALIZE_SHIFT: Int = 27 /** initialize shift. */ private val INITIALIZE_SHIFT2: Int = 30 /** magic number. */ private val MAGIC_NUMBER1: Int = 1664525 /** magic number. */ private val MAGIC_NUMBER2: Int = 1566083941 /** magic number. */ private val MAGIC_NUMBER3: Int = 1812433253 /** int to float shift. */ private val INT_TO_FLOAT_SHIFT: Int = 9 /** long to double shift. */ private val LONG_TO_DOUBLE_SHIFT: Int = 12 /** hexadecimal base. */ private val HEXA_DECIMAL_BASE: Int = 16 /** int to unsigned long mask. */ private val INT_TO_LONG_MASK: Long = 0xffffffffL /** long to double mask. */ private val LONG_TO_DOUBLE_MASK: Long = 0x3ff0000000000000L /** basic jump step. * every jump step is a multiple of this step. */ private val BASIC_JUMP_STEP: BigInteger = new BigInteger("2").pow(64) /** mask pattern to limit internal size. */ private val MASK: Int = 0x7fffffff /** fixed shift 0. */ private val SH0: Int = 1 /** fixed shift 1. */ private val SH1: Int = 10 /** fixed 8 bit shift. */ private val SH8: Int = 8 /** pre loop before generation. */ private val MIN_LOOP: Int = 8 /** * Factory method which returns the TinyMT with the first generated * parameter of TinyMTDC. * * @param seed * seed of pseudo random numbers. * @return TinyMT with the first parameter. */ def getDefault(seed: String): TinyMT32 = { val defaultParameter = TinyMT32Parameter.getDefaultParameter (new TinyMT32(defaultParameter)).setSeed(seed) } /** * Factory method which returns the TinyMT with the first generated * parameter of TinyMTDC. * * @param seed * seed of pseudo random numbers. * @return TinyMT with the first parameter. */ def getDefault(seed: Long): TinyMT32 = { val defaultParameter = TinyMT32Parameter.getDefaultParameter (new TinyMT32(defaultParameter)).setLongSeed(seed) } /** get default TinyMT32 with seeding by array. * * @param seeds seeds for initialization. * @return random number generator TinyMT32 */ def getDefault(seeds: Array[Int]): TinyMT32 = { val defaultParameter = TinyMT32Parameter.getDefaultParameter new TinyMT32(defaultParameter).setSeed(seeds) } /** * Factory method which returns the TinyMT with the first generated * parameter of TinyMTDC. `System#nanoTime` and * `Thread#getId()` are used for seed. * * @return TinyMT with the first parameter. */ def getDefault(): TinyMT32 = { val seed = new Array[Int](4) val time: Long = System.nanoTime val threadId: Long = Thread.currentThread.getId seed(0) = (time >>> INT_SIZE).toInt seed(1) = time.toInt seed(2) = (threadId >>> INT_SIZE).toInt seed(3) = threadId.toInt val defaultParameter = TinyMT32Parameter.getDefaultParameter new TinyMT32(defaultParameter).setSeed(seed) } /** * make and return an array of TinyMT. Each element has the same * characteristic polynomial with TinyMT gotten by getDefaultMT. Especially, * the first element is just same as default TinyMT. The second element has * the state of jump * 264 steps after the first element. * In other word, the first element will generate the same sequence with the * second element, after jump * 264 pseudo random number * generation. * * @param count * number of TinyMT to be created. * @param seed * seed of first element * @param jump * step is jump * 264 * @return array of TinyMT */ def getDefaultArray(count: Int, seed: Long, jump: Long): Array[TinyMT32] = { val tiny: TinyMT32 = getDefault(seed) tiny.getJumpedArray(count, jump) } /** * Make and return an array of TinyMT. Each element has the same * characteristic polynomial with TinyMT gotten by getDefaultMT. Especially, * the first element is just same as default TinyMT. The second element has * the state of jump * 264 steps after the first element. * In other word, the first element will generate the same sequence with the * second element, after jump * 264 pseudo random number * generation. * * This is equals to TinyMT32.getDefault(seed).getJumpedArray(count, jump); * * @param count * number of TinyMT to be created. * @param seed * seed of first element * @param jump * step is jump * 264 * @return array of TinyMT */ def getDefaultArray(count: Int, seed: String, jump: Long): Array[TinyMT32] = { val tiny = getDefault(seed) tiny.getJumpedArray(count, jump) } /** return TinyMT32 instance whose parameter has ID = 1. * * @param threadId thread ID * @return TinyMT32 instance */ def getThreadLocal(threadId: Long): TinyMT32 = { new TinyMT32(TinyMT32Parameter.getThreadLocalParameter(threadId)) } } /** * @param parameter parameters for this generator. */ final case class TinyMT32( private val st0: Int, private val st1: Int, private val st2: Int, private val st3: Int, private val parameter: TinyMT32Parameter ) extends Rand { private def asMutable: TinyMT32.MutableState = TinyMT32.MutableState( st0 = st0, st1 = st1, st2 = st2, st3 = st3, param = parameter ) /** Constructor from a parameter. * * @param param * a parameter generated by TinyMTDC */ private def this(param: TinyMT32Parameter) { this( st0 = 0, st1 = 0, st2 = 0, st3 = 0, parameter = param ) } def nextInt: (TinyMT32, Int) = { val s = nextState (s, s.output) } override def nextLong: (TinyMT32, Long) = { val (s0, x0) = nextInt val t: Long = (x0: Long) << TinyMT32.INT_SIZE val (s1, x1) = s0.nextInt val x2 = t | (x1 & TinyMT32.INT_TO_LONG_MASK) (s1, x2) } def reseed(seed: Long): TinyMT32 = setLongSeed(seed) def setLongSeed(seed: Long): TinyMT32 = { if ((seed >= 0) && (seed < TinyMT32.LONG_LIMIT)) { setIntSeed(seed.toInt) } else { val tmp = new Array[Int](2) tmp(0) = (seed & 0xffffffff).toInt tmp(1) = (seed >>> TinyMT32.INT_SIZE).toInt setSeed(tmp) } } def setSeed(seed: String): TinyMT32 = { val intSeeds = new Array[Int](seed.length) @tailrec def loop(i: Int): Unit = { if (i < intSeeds.length) { intSeeds(i) = seed.charAt(i) loop(i + 1) } } loop(0) setSeed(intSeeds) } def setSeed(seeds: Array[Int]): TinyMT32 = { val lag: Int = 1 val mid: Int = 1 val size: Int = 4 var i: Int = 0 var j: Int = 0 var count: Int = 0 var r: Int = 0 val keyLength: Int = seeds.length val status = Array[Int](0, parameter.mat1, parameter.mat2, parameter.tmat) if (keyLength + 1 > TinyMT32.MIN_LOOP) { count = keyLength + 1 } else { count = TinyMT32.MIN_LOOP } r = iniFunc1(status(0) ^ status(mid % size) ^ status((size - 1) % size)) status(mid % size) += r r += keyLength status((mid + lag) % size) += r status(0) = r count -= 1 { i = 1 j = 0 while ((j < count) && (j < keyLength)) { r = iniFunc1(status(i % size) ^ status((i + mid) % size) ^ status((i + size - 1) % size)) status((i + mid) % size) += r r += seeds(j) + i status((i + mid + lag) % size) += r status(i % size) = r i = (i + 1) % size j += 1 } } while (j < count) { r = iniFunc1(status(i % size) ^ status((i + mid) % size) ^ status((i + size - 1) % size)) status((i + mid) % size) += r r += i status((i + mid + lag) % size) += r status(i % size) = r i = (i + 1) % size j += 1 } { j = 0 while (j < size) { r = iniFunc2(status(i % size) + status((i + mid) % size) + status((i + size - 1) % size)) status((i + mid) % size) ^= r r -= i status((i + mid + lag) % size) ^= r status(i % size) = r i = (i + 1) % size j += 1 } } val x = new TinyMT32( st0 = status(0), st1 = status(1), st2 = status(2), st3 = status(3), parameter = this.parameter ).periodCertification0 @tailrec def loop(z: TinyMT32.MutableState, i: Int): TinyMT32 = if(i < TinyMT32.MIN_LOOP) { loop(z.next(), i + 1) } else { z.asImmutable } loop(x.asMutable, 0) } /** sub function of initialization. * * @param x input number * @return scrambled integer */ private def iniFunc1(x: Int): Int = (x ^ (x >>> TinyMT32.INITIALIZE_SHIFT)) * TinyMT32.MAGIC_NUMBER1 /** sub function of initialization. * * @param x input number * @return scrambled integer */ private def iniFunc2(x: Int): Int = (x ^ (x >>> TinyMT32.INITIALIZE_SHIFT)) * TinyMT32.MAGIC_NUMBER2 def setIntSeed(seed: Int): TinyMT32 = { val counterMask = 3 val status = new Array[Int](4) status(0) = seed status(1) = parameter.mat1 status(2) = parameter.mat2 status(3) = parameter.tmat { @tailrec def loop0(i: Int): Unit = { if(i < TinyMT32.MIN_LOOP) { status(i & counterMask) ^= i + TinyMT32.MAGIC_NUMBER3 * (status((i - 1) & counterMask) ^ (status((i - 1) & counterMask) >>> TinyMT32.INITIALIZE_SHIFT2)) loop0(i + 1) } } loop0(1) } val x = new TinyMT32( st0 = status(0), st1 = status(1), st2 = status(2), st3 = status(3), parameter = this.parameter ).periodCertification0 @tailrec def loop(i: Int, z: TinyMT32.MutableState): TinyMT32 = if(i < TinyMT32.MIN_LOOP) { loop(i + 1, z.next()) } else { z.asImmutable } loop(0, x.asMutable) } private def periodCertification0: TinyMT32 = { if (((st0 & TinyMT32.MASK) == 0) && (st1 == 0) && (st2 == 0) && (st3 == 0)) { new TinyMT32( st0 = 'T', st1 = 'I', st2 = 'N', st3 = 'Y', parameter = this.parameter ) } else this } /** The state transition function. This function is F2-linear. */ private def nextState: TinyMT32 = { var x = 0 var y = 0 y = st3 x = (st0 & TinyMT32.MASK) ^ st1 ^ st2 x ^= (x << TinyMT32.SH0) y ^= (y >>> TinyMT32.SH0) ^ x val x0 = st1 val x3 = y val x1 = st2 ^ parameter.getMat1(y) val x2 = (x ^ (y << TinyMT32.SH1)) ^ parameter.getMat2(y) new TinyMT32( st0 = x0, st1 = x1, st2 = x2, st3 = x3, parameter = this.parameter ) } /** The output function. * * @return pseudo random number */ private def output: Int = { var t0: Int = 0 var t1: Int = 0 t0 = st3 t1 = st0 + (st2 >>> TinyMT32.SH8) t0 ^= t1 t0 ^= parameter.getTmat(t1) t0 } /** make float random. * * @return float output. */ private def outputFloat: Float = { var t0: Int = 0 var t1: Int = 0 t0 = st3 t1 = st0 + (st2 >>> TinyMT32.SH8) t0 ^= t1 t0 = (t0 >>> TinyMT32.INT_TO_FLOAT_SHIFT) ^ parameter.getTmatFloat(t1) java.lang.Float.intBitsToFloat(t0) - 1.0f } private def add0(that: TinyMT32): TinyMT32 = new TinyMT32( st0 = this.st0 ^ that.st0, st1 = this.st1 ^ that.st1, st2 = this.st2 ^ that.st2, st3 = this.st3 ^ that.st3, parameter = this.parameter ) /** jump function. * * @param pol jump polynomial * @return jumped new TinyMT */ private def jump(pol: F2Polynomial): TinyMT32 = { val degree = pol.degree // TODO avoid allocate new instance each loop @tailrec def loop(i: Int, src: TinyMT32, that: TinyMT32): TinyMT32 = if (i > degree) { that } else if (pol.getCoefficient(i) == 1) { loop(i + 1, src.nextState, that.add0(src)) } else { loop(i + 1, src.nextState, that) } loop(0, this, new TinyMT32(this.parameter)) } /** * Make and return an array of TinyMT. Each element of the array has the * same characteristic polynomial with this. Especially, the first element * is just same as this. The second element has the state of jump * * 264 steps after the first element. In other word, the first * element will generate the same sequence with the second element, after * jump * 264 pseudo random number generation. * *

* Note: Do not call any setSeed methods after jump. Seeding will cancel * the effect of jump. *

* * @param count number of arrays * @param jump jump step * @return jumped array of TinyMT32. */ def getJumpedArray(count: Int, jump: Long): Array[TinyMT32] = { val tiny = new Array[TinyMT32](count) tiny(0) = this val poly = tiny(0).parameter.characteristic val pow = TinyMT32.BASIC_JUMP_STEP.multiply(BigInteger.valueOf(jump)) val jumpPoly = F2Polynomial.X.powerMod(pow, poly) @tailrec def loop(i: Int): Unit = { if (i < count) { tiny(i) = tiny(i - 1).jump(jumpPoly) loop(i + 1) } } loop(1) tiny } override def nextDouble: (TinyMT32, Double) = { val temp = nextLong val x: Long = (temp._2 >>> TinyMT32.LONG_TO_DOUBLE_SHIFT) | TinyMT32.LONG_TO_DOUBLE_MASK (temp._1, java.lang.Double.longBitsToDouble(x) - 1.0) } def nextFloat: (TinyMT32, Float) = { val s = nextState (s, s.outputFloat) } /** return characteristic polynomial in hexadecimal format. */ def getCharacteristic: String = parameter.characteristic.toString(TinyMT32.HEXA_DECIMAL_BASE) /** return ID of TinyMT. ID is not unique in TinyMT. */ def getId: Int = parameter.id /** return Delta of TinyMT. */ def getDelta: Int = parameter.delta /** return Hamming weight of characteristic polynomial of TinyMT. */ def getWeight: Int = parameter.weight }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy