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.source32; 18 19 import org.apache.commons.rng.core.util.NumberFactory; 20 21 /** 22 * Port from Marsaglia's <a href="http://www.cse.yorku.ca/~oz/marsaglia-rng.html"> 23 * "KISS" algorithm</a>. 24 * This version contains the correction referred to 25 * <a href="https://programmingpraxis.com/2010/10/05/george-marsaglias-random-number-generators/">here</a> 26 * in a reply to the original post. 27 * 28 * @see <a href="https://en.wikipedia.org/wiki/KISS_(algorithm)">KISS (Wikipedia)</a> 29 * @since 1.0 30 */ 31 public class KISSRandom extends IntProvider { 32 /** Size of the seed. */ 33 private static final int SEED_SIZE = 4; 34 /** State variable. */ 35 private int z; 36 /** State variable. */ 37 private int w; 38 /** State variable. */ 39 private int jsr; 40 /** State variable. */ 41 private int jcong; 42 43 /** 44 * Creates a new instance. 45 * 46 * @param seed Seed. 47 * If the length is larger than 4, only the first 4 elements will 48 * be used; if smaller, the remaining elements will be automatically 49 * set. 50 */ 51 public KISSRandom(int[] seed) { 52 setSeedInternal(seed); 53 } 54 55 /** {@inheritDoc} */ 56 @Override 57 protected byte[] getStateInternal() { 58 return composeStateInternal(NumberFactory.makeByteArray(new int[] {z, w, jsr, jcong}), 59 super.getStateInternal()); 60 } 61 62 /** {@inheritDoc} */ 63 @Override 64 protected void setStateInternal(byte[] s) { 65 final byte[][] c = splitStateInternal(s, SEED_SIZE * 4); 66 67 final int[] tmp = NumberFactory.makeIntArray(c[0]); 68 z = tmp[0]; 69 w = tmp[1]; 70 jsr = tmp[2]; 71 jcong = tmp[3]; 72 73 super.setStateInternal(c[1]); 74 } 75 76 /** 77 * Seeds the RNG. 78 * 79 * @param seed Seed. 80 */ 81 private void setSeedInternal(int[] seed) { 82 // Reset the whole state of this RNG (i.e. the 4 state variables). 83 // Filling procedure is not part of the reference code. 84 final int[] tmp = new int[SEED_SIZE]; 85 fillState(tmp, seed); 86 87 z = tmp[0]; 88 w = tmp[1]; 89 jsr = tmp[2]; 90 jcong = tmp[3]; 91 } 92 93 /** {@inheritDoc} */ 94 @Override 95 public int next() { 96 z = computeNew(36969, z); 97 w = computeNew(18000, w); 98 final int mwc = (z << 16) + w; 99 100 // Cf. correction mentioned in the reply to the original post: 101 // https://programmingpraxis.com/2010/10/05/george-marsaglias-random-number-generators/ 102 jsr ^= jsr << 13; 103 jsr ^= jsr >>> 17; 104 jsr ^= jsr << 5; 105 106 jcong = 69069 * jcong + 1234567; 107 108 return (mwc ^ jcong) + jsr; 109 } 110 111 /** 112 * Compute new value. 113 * 114 * @param mult Multiplier. 115 * @param previous Previous value. 116 * @return new value. 117 */ 118 private static int computeNew(int mult, 119 int previous) { 120 return mult * (previous & 65535) + (previous >>> 16); 121 } 122 }