DotyHumphreySmallFastCounting64.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.rng.core.source64;

  18. import org.apache.commons.rng.core.util.NumberFactory;

  19. /**
  20.  * Implement the Small, Fast, Counting (SFC) 64-bit generator of Chris Doty-Humphrey.
  21.  * The original source is the PractRand test suite by the same author.
  22.  *
  23.  * <p>The state size is 256-bits; the period is a minimum of 2<sup>64</sup> and an
  24.  * average of approximately 2<sup>255</sup>.</p>
  25.  *
  26.  * @see <a href="http://pracrand.sourceforge.net/">PractRand</a>
  27.  * @since 1.3
  28.  */
  29. public class DotyHumphreySmallFastCounting64 extends LongProvider {
  30.     /** Size of the seed. */
  31.     private static final int SEED_SIZE = 3;

  32.     /** State a. */
  33.     private long a;
  34.     /** State b. */
  35.     private long b;
  36.     /** State c. */
  37.     private long c;
  38.     /** Counter. */
  39.     private long counter;

  40.     /**
  41.      * Creates an instance with the given seed.
  42.      *
  43.      * @param seed Initial seed.
  44.      * If the length is larger than 3, only the first 3 elements will
  45.      * be used; if smaller, the remaining elements will be automatically set.
  46.      */
  47.     public DotyHumphreySmallFastCounting64(long[] seed) {
  48.         if (seed.length < SEED_SIZE) {
  49.             final long[] state = new long[SEED_SIZE];
  50.             fillState(state, seed);
  51.             setSeedInternal(state);
  52.         } else {
  53.             setSeedInternal(seed);
  54.         }
  55.     }

  56.     /**
  57.      * Seeds the RNG.
  58.      *
  59.      * @param seed Seed.
  60.      */
  61.     private void setSeedInternal(long[] seed) {
  62.         a = seed[0];
  63.         b = seed[1];
  64.         c = seed[2];
  65.         counter = 1L;
  66.         for (int i = 0; i < 18; i++) {
  67.             next();
  68.         }
  69.     }

  70.     /** {@inheritDoc} */
  71.     @Override
  72.     public final long next() {
  73.         final long tmp = a + b + counter++;
  74.         a = b ^ (b >>> 11);
  75.         b = c + (c << 3);
  76.         c = Long.rotateLeft(c, 24) + tmp;
  77.         return tmp;
  78.     }

  79.     /** {@inheritDoc} */
  80.     @Override
  81.     protected byte[] getStateInternal() {
  82.         return composeStateInternal(NumberFactory.makeByteArray(new long[] {a, b, c, counter}),
  83.                                     super.getStateInternal());
  84.     }

  85.     /** {@inheritDoc} */
  86.     @Override
  87.     protected void setStateInternal(byte[] s) {
  88.         final byte[][] parts = splitStateInternal(s, 4 * 8);

  89.         final long[] tmp = NumberFactory.makeLongArray(parts[0]);
  90.         a = tmp[0];
  91.         b = tmp[1];
  92.         c = tmp[2];
  93.         counter = tmp[3];

  94.         super.setStateInternal(parts[1]);
  95.     }
  96. }