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

com.jejking.rprng.rng.EightByteStringOps.scala Maven / Gradle / Ivy

The newest version!
package com.jejking.rprng.rng

/**
  * Functions to operate on an [[EightByteString]] with a view
  * to supporting RNG operations.
  */
object EightByteStringOps {

  private val DOUBLE_UNIT: Double =  1.0 / (1L << 53)

  /**
    * Converts to an [[Int]] - effectively takes the first four bytes
    * and converts these to the expected signed 32 bit integer.
    * @param eightByteString input
    * @return converted int
    */
    def toInt(eightByteString: EightByteString): Int = {
    eightByteString.byteString.toByteBuffer.asIntBuffer().get()
  }

  /**
    * Converts to an [[Int]], scaling down to a value between zero (inclusive)
    * and the upper bound (exclusive).
    * @param eightByteString input
    * @param upperBound exclusive upper bound
    * @return converted int
    */
  def toInt(eightByteString: EightByteString, upperBound: Int): Int = {
    require(upperBound > 0, s"Bound must be strictly positive, but was $upperBound")

    val result: Int = (toDoubleBetweenZeroAndOne(eightByteString) * upperBound).toInt
    if (result < upperBound) {
      result
    } else {
      result - 1
    }
  }

  /**
    * Converts to an int, scaled down to be between the lower bound (inclusive)
    * and the upper bound (exclusive). In the edge case that lower bound is [[Int.MinValue]]
    * and the upper bound is [[Int.MaxValue]] then the behaviour is the same as [[EightByteStringOps.toInt()]]
    * with no parameters.
    *
    * @param eightByteString input
    * @param lowerBound inclusive lower bound
    * @param upperBound exclusive upper bound
    * @return converted int
    */
  def toInt(eightByteString: EightByteString, lowerBound: Int, upperBound: Int): Int = {
    require(lowerBound < upperBound, s"lowerBound (${lowerBound} must be less than upperBound ${upperBound}")

    if (lowerBound == Int.MinValue && upperBound == Int.MaxValue) {
      toInt(eightByteString)
    } else {
      toInt(eightByteString, (upperBound - lowerBound).abs) + lowerBound
    }
  }

  /**
    * Converts to a [[Double]] using the full eight bytes.
    * @param eightByteString input
    * @return converted double
    */
  def toDouble(eightByteString: EightByteString): Double = {
    eightByteString.byteString.toByteBuffer.asDoubleBuffer().get()
  }

  /**
    * Converts to a [[Double]], scaled down to be between zero and one.
    * @param eightByteString input
    * @return scaled down double
    */
  def toDoubleBetweenZeroAndOne(eightByteString: EightByteString): Double = {
    /*
     Note that the left most 53 bits of a 64 bit double are the fractional part.
     So bit-shifting 11 to the left removes the exponent and we can then multiply
     by the DOUBLE_UNIT constant which ensures the resulting double is between 0 and 1.
     */

    (toLong(eightByteString) >>> 11) * DOUBLE_UNIT
  }

  /**
    * Converts to a [[Long]] using the full eight bytes.
    * @param eightByteString input
    * @return converted to a long
    */
  def toLong(eightByteString: EightByteString): Long = {
    eightByteString.byteString.toByteBuffer.asLongBuffer().get()
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy