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

scalaprops.Rand.scala Maven / Gradle / Ivy

package scalaprops

abstract class Rand {
  def nextInt: (Rand, Int)

  def nextLong: (Rand, Long)

  protected[this] final def nextIntFromNextLong: (Rand, Int) = {
    val (r, n) = nextLong
    (r, (n >>> 32).toInt)
  }

  protected[this] final def nextLongFromNextInt: (Rand, Long) = {
    val (_, n1) = nextInt
    val (r, n2) = nextInt
    val x = ((n1 & 0xffffffffL) << 32) | (n2 & 0xffffffffL)
    (r, x)
  }

  def nextDouble: (Rand, Double) =
    Rand.nextDouble(this)

  def chooseLong(from: Long, to: Long): (Rand, Long) = {
    if (from == to) {
      (this.nextInt._1, from)
    } else {
      val min = math.min(from, to)
      val max = math.max(from, to)

      if (Int.MinValue <= min && max <= Int.MaxValue) {
        val (r, i) = choose(min.asInstanceOf[Int], max.asInstanceOf[Int])
        (r, i)
      } else {
        val diff: Long = (max: Long) - (min: Long)
        // `0 < diff` is necessary to check subtraction underflow.
        if (0 < diff && diff < Int.MaxValue) {
          val (r, i) = choose(0, diff.asInstanceOf[Int])
          (r, min + i)
        } else {
          @annotation.tailrec
          def loop(state: Rand): (Rand, Long) = {
            val next = state.nextLong
            if (min <= next._2 && next._2 <= max) {
              next
            } else if (0 < diff) {
              val x = (next._2 % (max - min + 1)) + min
              if (min <= x && x <= max) {
                (next._1, x)
              } else {
                loop(next._1)
              }
            } else {
              loop(next._1)
            }
          }
          loop(this)
        }
      }
    }
  }

  def choose(from: Int, to: Int): (Rand, Int) = {
    if (from == to) {
      (this.nextInt._1, from)
    } else {
      val min = math.min(from, to)
      val max = math.max(from, to)
      @annotation.tailrec
      def loop(state: Rand): (Rand, Int) = {
        val next = state.nextInt
        if (min <= next._2 && next._2 <= max) {
          next
        } else if (0 < (max - min)) {
          val x = (next._2 % (max - min + 2)) + min - 1
          if (min <= x && x <= max) {
            (next._1, x)
          } else {
            loop(next._1)
          }
        } else {
          loop(next._1)
        }
      }
      loop(this)
    }
  }

  def next: Rand =
    nextInt._1

  def reseed(newSeed: Long): Rand
  def setIntSeed(newSeed: Int): Rand
}

object Rand {
  implicit val randGen: Gen[Rand] =
    Gen.gen { (_, r) =>
      val next = r.next
      (next, next)
    }

  implicit val randCogen: Cogen[Rand] =
    new Cogen[Rand] {
      def cogen[B](a: Rand, g: CogenState[B]) =
        CogenState(g.rand.next, Gen.gen((size, _) => g.gen.f(size, a)))
    }

  def standard(s: Long): Rand =
    Platform.randFromLong(s)

  private[scalaprops] final val defaultSeed = 5489

  def fromSeed(seed: Int = defaultSeed): Rand =
    Platform.randFromInt(seed)

  // Generates a random Double in the interval [0, 1)
  def nextDouble(state: Rand): (Rand, Double) = {
    val x = state.nextInt
    val a: Long = (x._2.toLong & 0xffffffffL) >>> 5
    val y = x._1.nextInt
    val b: Long = (y._2.toLong & 0xffffffffL) >>> 6
    val r = (a * 67108864.0 + b) / 9007199254740992.0
    (y._1, r)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy