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 NumberFactory.makeByteArray(new int[] { z, w, jsr, jcong }); 59 } 60 61 /** {@inheritDoc} */ 62 @Override 63 protected void setStateInternal(byte[] s) { 64 checkStateSize(s, SEED_SIZE * 4); 65 66 final int[] tmp = NumberFactory.makeIntArray(s); 67 68 z = tmp[0]; 69 w = tmp[1]; 70 jsr = tmp[2]; 71 jcong = tmp[3]; 72 } 73 74 /** 75 * Seeds the RNG. 76 * 77 * @param seed Seed. 78 */ 79 private void setSeedInternal(int[] seed) { 80 // Reset the whole state of this RNG (i.e. the 4 state variables). 81 // Filling procedure is not part of the reference code. 82 final int[] tmp = new int[SEED_SIZE]; 83 fillState(tmp, seed); 84 85 z = tmp[0]; 86 w = tmp[1]; 87 jsr = tmp[2]; 88 jcong = tmp[3]; 89 } 90 91 /** {@inheritDoc} */ 92 @Override 93 public int next() { 94 z = computeNew(36969, z); 95 w = computeNew(18000, w); 96 final int mwc = (z << 16) + w; 97 98 // Cf. correction mentioned in the reply to the original post: 99 // https://programmingpraxis.com/2010/10/05/george-marsaglias-random-number-generators/ 100 jsr ^= jsr << 13; 101 jsr ^= jsr >>> 17; 102 jsr ^= jsr << 5; 103 104 jcong = 69069 * jcong + 1234567; 105 106 return (mwc ^ jcong) + jsr; 107 } 108 109 /** 110 * Compute new value. 111 * 112 * @param mult Multiplier. 113 * @param previous Previous value. 114 * @return new value. 115 */ 116 private int computeNew(int mult, 117 int previous) { 118 return mult * (previous & 65535) + (previous >>> 16); 119 } 120 }