/* Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.bigdata.util; /** * PseudoRandom is derived from an algorithm used to create a dissolve * graphics effect. * * Given a maximum number it generates all numbers from 1 to that number * in a deterministic but pseudorandom order. * * It is therefore particularly useful for test cases. * * See: http://www.mactech.com/articles/mactech/Vol.06/06.12/SafeDissolve/index.html * */ public class PseudoRandom { final private int m_mask;// = 0; private int m_next = 1; final private int m_max; private static final int[] s_masks = { 0x03, 0x06, 0x0C, 0x14, 0x30, 0x60, 0xB8, 0x0110, 0x0240, 0x0500, 0x0CA0, 0x1B00, 0x3500, 0x6000, 0xB400, 0x00012000, 0x00020400, 0x00072000, 0x00090000, 0x00140000, 0x00300000, 0x00400000, 0x00D80000, 0x01200000, 0x03880000, 0x07200000, 0x09000000, 0x14000000, 0x32800000, 0x48000000, 0xA3000000}; /** * Create a pseudo random number generator which will visit each integer in * a half-open range. * * @param range * The exclusive upper bound of the half-open range (0:range]. * @param next * The next number to visit in (0:range]. */ public PseudoRandom(final int range, final int next) { this(range); if (next < 0 || next >= range) throw new IllegalArgumentException(); m_next = next + 1; } /** * Create a pseudo random number generator which will visit each integer in * a half-open range. The first visited value will be <code>1</code>. * * @param range * The exclusive upper bound of the half-open range (0:range]. */ public PseudoRandom(final int range) { int m_mask = 0; for (int m = 0; m < s_masks.length; m++) { if (s_masks[m] > range) { m_mask = s_masks[m]; break; } } this.m_mask = m_mask; m_max = range; } public int next() { if ((m_next & 1) == 1) m_next = (m_next >> 1) ^ m_mask; else m_next = (m_next >> 1); if (m_next > m_max) return next(); else return m_next - 1; } /** * The next number modulo the range. * * @param range * The range. * @return The number. * * @throws IllegalArgumentException * if the range is negative. * @throws IllegalStateException * if the range is greater than the range specified to the * constructor (ie., the generated could not produce all numbers * in the given range). */ public int nextInt(final int range) { if (range == 0) return 0; if (range < 0) throw new IllegalArgumentException(); if (range > m_max) throw new IllegalStateException( "Range exceeds max range of generator"); return next() % range; } /** * Reset the pseudo random generator to a state where it has just visited * <i>prev</i>. * * @param prev * The "previous" value. * * @return The next value in the pseudo random sequence after <i>prev</i>. */ public int next(final int prev) { if (prev < 0 || prev >= m_max) throw new IllegalArgumentException(); m_next = prev + 1; return next(); } public void nextBytes(byte[] key, final int prev) { m_next = prev; nextBytes(key); } public void nextBytes(byte[] key) { for (int i = 0; i < key.length; i++) { key[i] = (byte) next(); } } }