001/* 002 * Java Genetic Algorithm Library (jenetics-7.0.0). 003 * Copyright (c) 2007-2022 Franz Wilhelmstötter 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 * Author: 018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com) 019 */ 020package io.jenetics.internal.math; 021 022import static java.lang.Math.abs; 023import static io.jenetics.internal.util.Requires.probability; 024 025import java.util.random.RandomGenerator; 026import java.util.stream.IntStream; 027 028/** 029 * Some random helper functions. 030 * 031 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 032 * @since 1.4 033 * @version 7.0 034 */ 035public final class Randoms { 036 private Randoms() {} 037 038 public static byte nextByte(final RandomGenerator random) { 039 return (byte)random.nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE + 1); 040 } 041 042 public static char nextChar(final RandomGenerator random) { 043 char c = '\0'; 044 do { 045 c = (char)random.nextInt( 046 Character.MIN_VALUE, 047 Character.MAX_VALUE + 1 048 ); 049 } while (!Character.isLetterOrDigit(c)); 050 051 return c; 052 } 053 054 public static short nextShort(final RandomGenerator random) { 055 return (short)random.nextInt(Short.MIN_VALUE, Short.MAX_VALUE + 1); 056 } 057 058 public static String nextASCIIString( 059 final int length, 060 final RandomGenerator random 061 ) { 062 final char[] chars = new char[length]; 063 for (int i = 0; i < length; ++i) { 064 chars[i] = (char)random.nextInt(32, 127); 065 } 066 067 return new String(chars); 068 } 069 070 public static String nextASCIIString(final RandomGenerator random) { 071 return nextASCIIString(random.nextInt(5, 20), random); 072 } 073 074 /* 075 * Conversion methods used by the 'RandomGenerator' engine from the JDK. 076 */ 077 078 public static float toFloat(final int a) { 079 return (a >>> 8)/(float)(1 << 24); 080 } 081 082 public static float toFloat(final long a) { 083 return (int)(a >>> 40)/(float)(1 << 24); 084 } 085 086 public static double toDouble(final long a) { 087 return (((a >>> 38) << 27) + ((int)a >>> 5))/(double)(1L << 53); 088 } 089 090 public static double toDouble(final int a, final int b) { 091 return (((long)(a >>> 6) << 27) + (b >>> 5))/(double)(1L << 53); 092 } 093 094 095 /* 096 * Conversion methods used by the Apache Commons BitStreamGenerator. 097 */ 098 099 public static float toFloat2(final int a) { 100 return (a >>> 9)*0x1.0p-23f; 101 } 102 103 public static float toFloat2(final long a) { 104 return (int)(a >>> 41)*0x1.0p-23f; 105 } 106 107 public static double toDouble2(final long a) { 108 return (a & 0xFFFFFFFFFFFFFL)*0x1.0p-52d; 109 } 110 111 public static double toDouble2(final int a, final int b) { 112 return (((long)(a >>> 6) << 26) | (b >>> 6))*0x1.0p-52d; 113 } 114 115 /** 116 * Create an {@code IntStream} which creates random indexes within the 117 * given range and the index probability. 118 * 119 * @since 3.0 120 * 121 * @param random the random engine used for calculating the random 122 * indexes 123 * @param start the start index (inclusively) 124 * @param end the end index (exclusively) 125 * @param p the index selection probability 126 * @return an new random index stream 127 * @throws IllegalArgumentException if {@code p} is not a 128 * valid probability. 129 */ 130 public static IntStream indexes( 131 final RandomGenerator random, 132 final int start, 133 final int end, 134 final double p 135 ) { 136 probability(p); 137 final int P = Probabilities.toInt(p); 138 139 return equals(p, 0, 1E-20) 140 ? IntStream.empty() 141 : equals(p, 1, 1E-20) 142 ? IntStream.range(start, end) 143 : IntStream.range(start, end) 144 .filter(i -> random.nextInt() < P); 145 } 146 147 private static boolean 148 equals(final double a, final double b, final double delta) { 149 return abs(a - b) <= delta; 150 } 151 152 /** 153 * Create an {@code IntStream} which creates random indexes within the 154 * given range and the index probability. 155 * 156 * @since 3.0 157 * 158 * @param random the random engine used for calculating the random 159 * indexes 160 * @param n the end index (exclusively). The start index is zero. 161 * @param p the index selection probability 162 * @return an new random index stream 163 * @throws IllegalArgumentException if {@code p} is not a 164 * valid probability. 165 * @throws NullPointerException if the given {@code random} 166 * engine is {@code null}. 167 */ 168 public static IntStream indexes( 169 final RandomGenerator random, 170 final int n, 171 final double p 172 ) { 173 return indexes(random, 0, n, p); 174 } 175 176 /** 177 * Create a new <em>seed</em> byte array of the given length. 178 * 179 * @see #seed(byte[]) 180 * @see #seed() 181 * 182 * @param length the length of the returned byte array. 183 * @return a new <em>seed</em> byte array of the given length 184 * @throws NegativeArraySizeException if the given length is smaller 185 * than zero. 186 */ 187 public static byte[] seedBytes(final int length) { 188 return seed(new byte[length]); 189 } 190 191 /** 192 * Fills the given byte array with random bytes, created by successive 193 * calls of the {@link #seed()} method. 194 * 195 * @see #seed() 196 * 197 * @param seed the byte array seed to fill with random bytes. 198 * @return the given byte array, for method chaining. 199 * @throws NullPointerException if the {@code seed} array is 200 * {@code null}. 201 */ 202 public static byte[] seed(final byte[] seed) { 203 for (int i = 0, len = seed.length; i < len;) { 204 int n = Math.min(len - i, Long.SIZE/Byte.SIZE); 205 206 for (long x = seed(); n-- > 0; x >>= Byte.SIZE) { 207 seed[i++] = (byte)x; 208 } 209 } 210 211 return seed; 212 } 213 214 /** 215 * Calculating a 64 bit seed value which can be used for initializing 216 * PRNGs. This method uses a combination of {@code System.nanoTime()} 217 * and {@code new Object().hashCode()} calls to create a reasonable safe 218 * seed value: 219 * 220 * <pre>{@code 221 * public static long seed() { 222 * return seed(System.nanoTime()); 223 * } 224 * }</pre> 225 * 226 * This method passes all the statistical tests of the 227 * <a href="http://www.phy.duke.edu/~rgb/General/dieharder.php"> 228 * dieharder</a> test suite—executed on a linux machine with 229 * JDK version 1.7. <em>Since there is no prove that this will the case 230 * for every Java version and OS, it is recommended to only use this 231 * method for seeding other PRNGs.</em> 232 * 233 * @see #seed(long) 234 * 235 * @return the random seed value. 236 */ 237 public static long seed() { 238 return seed(System.nanoTime()); 239 } 240 241 /** 242 * Uses the given {@code base} value to create a reasonable safe seed 243 * value. This is done by combining it with values of 244 * {@code new Object().hashCode()}: 245 * 246 * <pre>{@code 247 * public static long seed(final long base) { 248 * final long objectHashSeed = ((long)(new Object().hashCode()) << 32) | 249 * new Object().hashCode(); 250 * long seed = base^objectHashSeed; 251 * seed ^= seed << 17; 252 * seed ^= seed >>> 31; 253 * seed ^= seed << 8; 254 * return seed; 255 * } 256 * }</pre> 257 * 258 * @param base the base value of the seed to create 259 * @return the created seed value. 260 */ 261 public static long seed(final long base) { 262 return mix(base, ObjectSeed.seed()); 263 } 264 265 private static long mix(final long a, final long b) { 266 long c = a^b; 267 c ^= c << 17; 268 c ^= c >>> 31; 269 c ^= c << 8; 270 return c; 271 } 272 273 private static final class ObjectSeed { 274 private static long seed() { 275 return (long)new ObjectSeed().hashCode() << 32 | 276 new ObjectSeed().hashCode(); 277 } 278 } 279 280}