TwoCmres.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 java.util.List;
  19. import java.util.ArrayList;
  20. import org.apache.commons.rng.core.util.NumberFactory;

  21. /**
  22.  * Random number generator designed by Mark D. Overton.
  23.  *
  24.  * <p>It is one of the many generators described by the author in the following article series:</p>
  25.  *  <ul>
  26.  *   <li><a href="http://www.drdobbs.com/tools/fast-high-quality-parallel-random-number/229625477">Part one</a></li>
  27.  *   <li><a href="http://www.drdobbs.com/tools/fast-high-quality-parallel-random-number/231000484">Part two</a></li>
  28.  *  </ul>
  29.  *
  30.  * @since 1.0
  31.  */
  32. public class TwoCmres extends LongProvider {
  33.     /** Error message. */
  34.     private static final String INTERNAL_ERROR_MSG = "Internal error: Please file a bug report";
  35.     /** A small positive integer. */
  36.     private static final byte SEED_GUARD = 9;
  37.     /** Factory of instances of this class. Singleton. */
  38.     private static final Cmres.Factory FACTORY = new Cmres.Factory();
  39.     /** First subcycle generator. */
  40.     private final Cmres x;
  41.     /** Second subcycle generator. */
  42.     private final Cmres y;
  43.     /** State of first subcycle generator. */
  44.     private long xx;
  45.     /** State of second subcycle generator. */
  46.     private long yy;

  47.     /**
  48.      * Creates a new instance.
  49.      *
  50.      * @param seed Initial seed.
  51.      * @param x First subcycle generator.
  52.      * @param y Second subcycle generator.
  53.      */
  54.     private TwoCmres(int seed,
  55.                      Cmres x,
  56.                      Cmres y) {
  57.         this.x = x;
  58.         this.y = y;
  59.         setSeedInternal(seed);
  60.     }

  61.     /**
  62.      * Creates a new instance.
  63.      *
  64.      * @param seed Seed.
  65.      */
  66.     public TwoCmres(Integer seed) {
  67.         this(seed, 0, 1);
  68.     }

  69.     /**
  70.      * Creates a new instance.
  71.      *
  72.      * @param seed Seed.
  73.      * @param i Table entry for first subcycle generator.
  74.      * @param j Table entry for second subcycle generator.
  75.      * @throws IllegalArgumentException if {@code i == j}.
  76.      * @throws IndexOutOfBoundsException if {@code i < 0} or
  77.      * {@code i >= numberOfSubcycleGenerators()}.
  78.      * @throws IndexOutOfBoundsException if {@code j < 0} or
  79.      * {@code j >= numberOfSubcycleGenerators()}.
  80.      */
  81.     public TwoCmres(Integer seed,
  82.                     int i,
  83.                     int j) {
  84.         this(seed, FACTORY.getIfDifferent(i, j), FACTORY.get(j));
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     public long next() {
  89.         xx = x.transform(xx);
  90.         yy = y.transform(yy);

  91.         return xx + yy;
  92.     }

  93.     /** {@inheritDoc} */
  94.     @Override
  95.     public String toString() {
  96.         return super.toString() + " (" + x + " + " + y + ")";
  97.     }

  98.     /**
  99.      * Get the number of subcycle generators.
  100.      *
  101.      * @return the number of subcycle generators.
  102.      */
  103.     public static int numberOfSubcycleGenerators() {
  104.         return FACTORY.numberOfSubcycleGenerators();
  105.     }

  106.     /** {@inheritDoc} */
  107.     @Override
  108.     protected byte[] getStateInternal() {
  109.         return composeStateInternal(NumberFactory.makeByteArray(new long[] {xx, yy}),
  110.                                     super.getStateInternal());
  111.     }

  112.     /** {@inheritDoc} */
  113.     @Override
  114.     protected void setStateInternal(byte[] s) {
  115.         final byte[][] c = splitStateInternal(s, 16);

  116.         final long[] state = NumberFactory.makeLongArray(c[0]);
  117.         xx = state[0];
  118.         yy = state[1];

  119.         super.setStateInternal(c[1]);
  120.     }

  121.     /**
  122.      * @param seed Seed.
  123.      */
  124.     private void setSeedInternal(int seed) {
  125.         // The seeding procedure consists in going away from some
  126.         // point known to be in the cycle.
  127.         // The total number of calls to the "transform" method will
  128.         // not exceed about 130,000 (which is negligible as seeding
  129.         // will not occur more than once in normal usage).

  130.         // Make two positive 16-bits integers from the 32-bit seed.
  131.         // Add the small positive seed guard. The result will never be negative.
  132.         final int xMax = (seed & 0xffff) + (SEED_GUARD & 0xff);
  133.         final int yMax = (seed >>> 16)   + (SEED_GUARD & 0xff);

  134.         xx = x.getStart();
  135.         for (int i = xMax; i > 0; i--) {
  136.             xx = x.transform(xx);
  137.         }

  138.         yy = y.getStart();
  139.         for (int i = yMax; i > 0; i--) {
  140.             yy = y.transform(yy);
  141.         }
  142.     }

  143.     /**
  144.      * Subcycle generator.
  145.      * Class is immutable.
  146.      */
  147.     static class Cmres {
  148.         /** Separator. */
  149.         private static final String SEP = ", ";
  150.         /** Hexadecimal format. */
  151.         private static final String HEX_FORMAT = "0x%016xL";
  152.         /** Cycle start. */
  153.         private final int start;
  154.         /** Multiplier. */
  155.         private final long multiply;
  156.         /** Rotation. */
  157.         private final int rotate;

  158.         /**
  159.          * @param multiply Multiplier.
  160.          * @param rotate Positive number. Must be in {@code [0, 64]}.
  161.          * @param start Cycle start.
  162.          */
  163.         Cmres(long multiply,
  164.               int rotate,
  165.               int start) {
  166.             this.multiply = multiply;
  167.             this.rotate = rotate;
  168.             this.start = start;
  169.         }

  170.         /** {@inheritDoc} */
  171.         @Override
  172.         public String toString() {
  173.             final String m = String.format((java.util.Locale) null, HEX_FORMAT, multiply);
  174.             return "Cmres: [" + m + SEP + rotate + SEP + start + "]";
  175.         }

  176.         /**
  177.          * @return the multiplier.
  178.          */
  179.         public long getMultiply() {
  180.             return multiply;
  181.         }

  182.         /**
  183.          * @return the cycle start.
  184.          */
  185.         public int getStart() {
  186.             return start;
  187.         }

  188.         /**
  189.          * @param state Current state.
  190.          * @return the new state.
  191.          */
  192.         long transform(long state) {
  193.             long s = state;
  194.             s *= multiply;
  195.             s = Long.rotateLeft(s, rotate);
  196.             s -= state;
  197.             return s;
  198.         }

  199.         /** Factory. */
  200.         static class Factory {
  201.             /** List of good "Cmres" subcycle generators. */
  202.             private static final List<Cmres> TABLE = new ArrayList<>();

  203.             //
  204.             // Populates the table.
  205.             // It lists parameters known to be good (provided in
  206.             // the article referred to above).
  207.             // To maintain compatibility, new entries must be added
  208.             // only at the end of the table.
  209.             //
  210.             static {
  211.                 add(0xedce446814d3b3d9L, 33, 0x13b572e7);
  212.                 add(0xc5b3cf786c806df7L, 33, 0x13c8e18a);
  213.                 add(0xdd91bbb8ab9e0e65L, 31, 0x06dd03a6);
  214.                 add(0x7b69342c0790221dL, 31, 0x1646bb8b);
  215.                 add(0x0c72c0d18614c32bL, 33, 0x06014a3d);
  216.                 add(0xd8d98c13bebe26c9L, 33, 0x014e8475);
  217.                 add(0xcb039dc328bbc40fL, 31, 0x008684bd);
  218.                 add(0x858c5ef3c021ed2fL, 32, 0x0dc8d622);
  219.                 add(0x4c8be96bfc23b127L, 33, 0x0b6b20cc);
  220.                 add(0x11eab77f808cf641L, 32, 0x06534421);
  221.                 add(0xbc9bd78810fd28fdL, 31, 0x1d9ba40d);
  222.                 add(0x0f1505c780688cb5L, 33, 0x0b7b7b67);
  223.                 add(0xadc174babc2053afL, 31, 0x267f4197);
  224.                 add(0x900b6b82b31686d9L, 31, 0x023c6985);
  225.                 // Add new entries here.
  226.             }

  227.             /**
  228.              * @return the number of subcycle generators.
  229.              */
  230.             int numberOfSubcycleGenerators() {
  231.                 return TABLE.size();
  232.             }

  233.             /**
  234.              * @param index Index into the list of available generators.
  235.              * @return the subcycle generator entry at index {@code index}.
  236.              */
  237.             Cmres get(int index) {
  238.                 if (index < 0 ||
  239.                     index >= TABLE.size()) {
  240.                     throw new IndexOutOfBoundsException("Out of interval [0, " +
  241.                                                         (TABLE.size() - 1) + "]");
  242.                 }

  243.                 return TABLE.get(index);
  244.             }

  245.             /**
  246.              * Get the generator at {@code index} if the {@code other} index is different.
  247.              *
  248.              * <p>This method exists to raise an exception before invocation of the
  249.              * private constructor; this mitigates Finalizer attacks
  250.              * (see SpotBugs CT_CONSTRUCTOR_THROW).
  251.              *
  252.              * @param index Index into the list of available generators.
  253.              * @param other Other index.
  254.              * @return the subcycle generator entry at index {@code index}.
  255.              */
  256.             Cmres getIfDifferent(int index, int other) {
  257.                 if (index == other) {
  258.                     throw new IllegalArgumentException("Subcycle generators must be different");
  259.                 }
  260.                 return get(index);
  261.             }

  262.             /**
  263.              * Adds an entry to the {@link Factory#TABLE}.
  264.              *
  265.              * @param multiply Multiplier.
  266.              * @param rotate Rotate.
  267.              * @param start Cycle start.
  268.              */
  269.             private static void add(long multiply,
  270.                                     int rotate,
  271.                                     int start) {
  272.                 // Validity check: if there are duplicates, the class initialization
  273.                 // will fail (and the JVM will report "NoClassDefFoundError").
  274.                 checkUnique(TABLE, multiply);

  275.                 TABLE.add(new Cmres(multiply, rotate, start));
  276.             }

  277.             /**
  278.              * Check the multiply parameter is unique (not contained in any entry in the provided
  279.              * table).
  280.              *
  281.              * @param table the table
  282.              * @param multiply the multiply parameter
  283.              */
  284.             static void checkUnique(List<Cmres> table, long multiply) {
  285.                 for (final Cmres sg : table) {
  286.                     if (multiply == sg.getMultiply()) {
  287.                         throw new IllegalStateException(INTERNAL_ERROR_MSG);
  288.                     }
  289.                 }
  290.             }
  291.         }
  292.     }
  293. }