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