001package squidpony.squidmath; 002 003import squidpony.StringKit; 004 005import java.io.Serializable; 006 007/** 008 * A quasi-random number generator that goes through one of many sub-random sequences found by J.G. van der Corput. 009 * More specifically, this offers the standard family of van der Corput sequences, each defined by a (almost always 010 * prime) base number. Each sequence only changes the state by incrementing it (this works better in the normal usage as 011 * part of a 2D or 3D point generator). The state is internally stored in a 64-bit long that is incremented once per 012 * generated number. The important things to know about this class are: size of state affects speed (prefer smaller 013 * seeds, but quality is sometimes a bit poor at first if you start at 0); the base (when given) should be prime 014 * (smaller bases tend to yield better quality, but oddly, larger bases perform better); this doesn't generate very 015 * random numbers, and is classified as a quasi-random number generator (which can be good for making points that 016 * should not overlap); this is a StatefulRandomness with an additional method for generating quasi-random doubles, 017 * {@link #nextDouble()}; and there are several static methods offered for convenient generation of points on the 018 * related Halton sequence (as well as faster generation of doubles in the base-2 van der Corput sequence, and a special 019 * method that switches which base it uses depending on the index to seem even less clearly-patterned). There are also, 020 * for lack of a better place to put such small code, methods to generate points in the R2 sequence found by Martin 021 * Roberts, which is very similar in 2D to some Halton sequences but has better separation between points. 022 * <br> 023 * This generator allows a base (also called a radix) that changes the sequence significantly; a base should be prime, 024 * and this performs better in terms of time used with larger primes, though quality is also improved by preferring 025 * primes that aren't very large relative to the quantity of numbers expected to be generated. Unfortunately, 026 * performance is not especially similar to conventional PRNGs; smaller (positive) state values are processed more 027 * quickly than larger ones, or most negative states. At least one 64-bit integer modulus and one 64-bit integer 028 * division are required for any number to be produced, and the amount of both of these relatively-non-cheap operations 029 * increases linearly with the number of digits (in the specified base, which is usually not 10) needed to represent 030 * the current state. Since performance is not optimal, and the results are rather strange anyway relative to PRNGs, 031 * this should not be used as a direct substitute for a typical RandomnessSource (however, it is similar to, but simpler 032 * and faster than, {@link SobolQRNG}). So what's it good for? 033 * <br> 034 * A VanDerCorputSequence can be a nice building block for more complicated quasi-randomness, especially for points in 035 * 2D or 3D. There's a simple way that should almost always "just work" as the static method 036 * {@link #halton(int, int, int, int[])} here. If it doesn't meet your needs, there's a little more complexity involved. 037 * Using a VanDerCorputQRNG with base 3 for the x-axis and another VanDerCorputQRNG with base 5 for the y-axis, 038 * requesting a double from each to make points between (0.0, 0.0) and (1.0, 1.0), has an interesting trait that can be 039 * desirable for many kinds of positioning in 2D: once a point has been generated, an identical point will never be 040 * generated until floating-point precision runs out, but more than that, nearby points will almost never be generated 041 * for many generations, and most points will stay at a comfortable distance from each other if the bases are different 042 * and both prime (or, more technically, if they share no common denominators). This is also known as a Halton sequence, 043 * which is a group of sequences of points instead of simply numbers. The choices of 3 and 5 are examples; any two 044 * different primes will technically work for 2D (as well as any two numbers that share no common factor other than 1, 045 * that is, they are relatively coprime), but patterns can be noticeable with primes larger than about 7, with 11 and 13 046 * sometimes acceptable. Three VanDerCorputQRNG sequences could be used for a Halton sequence of 3D 047 * points, using three different prime bases, four for 4D, etc. SobolQRNG can be used for the same purpose, but the 048 * points it generates are typically more closely-aligned to a specific pattern, the pattern is symmetrical between all 049 * four quadrants of the square between (0.0, 0.0) and (1.0, 1.0) in 2D, and it probably extends into higher dimensions. 050 * Using one of the possible Halton sequences gives some more flexibility in the kinds of random-like points produced. 051 * Oddly, using a base-2 van der Corput sequence as the x axis in a Halton sequence and a base-39 van der Corput 052 * sequence as the y axis results in the greatest minimum distance between points found so far while still involving a 053 * base-2 sequence (which is preferential for performance). There, the minimum distance between the first 65536 points 054 * in the [0,1) range is 0.001147395; a runner-up is a y base of 13, which has a minimum distance of 0.000871727 . The 055 * (2,39) Halton sequence is used by {@link #halton(int, int, int)} and {@link #halton(int, int, int, int[])}. 056 * <br> 057 * Created by Tommy Ettinger on 11/18/2016. Uses code adapted from 058 * <a href="https://blog.demofox.org/2017/05/29/when-random-numbers-are-too-random-low-discrepancy-sequences/">Alan Wolfe's blog</a>, 059 * which turned out to be a lot faster than the previous way I had it implemented. 060 */ 061public class VanDerCorputQRNG implements StatefulRandomness, RandomnessSource, Serializable { 062 private static final long serialVersionUID = 6; 063 public long state; 064 public final int base; 065 /** 066 * Constructs a new van der Corput sequence generator with base 7, starting point 37, and scrambling disabled. 067 */ 068 public VanDerCorputQRNG() 069 { 070 base = 7; 071 state = 37; 072 } 073 074 /** 075 * Constructs a new van der Corput sequence generator with the given starting point in the sequence as a seed. 076 * Usually seed should be at least 20 with this constructor, but not drastically larger; 2000 is probably too much. 077 * This will use a base 7 van der Corput sequence and have scrambling disabled. 078 * @param seed the seed as a long that will be used as the starting point in the sequence; ideally positive but low 079 */ 080 public VanDerCorputQRNG(long seed) 081 { 082 base = 7; 083 state = seed; 084 } 085 086 /** 087 * Constructs a new van der Corput sequence generator with the given base (a.k.a. radix; if given a base less than 088 * 2, this will use base 2 instead) and starting point in the sequence as a seed. Good choices for base are between 089 * 10 and 60 or so, and should usually be prime. Good choices for seed are larger than base but not by very much, 090 * and should generally be positive at construction time. 091 * @param base the base or radix used for this VanDerCorputQRNG; for most uses this should be prime but small-ish 092 * @param seed the seed as a long that will be used as the starting point in the sequence; ideally positive but low 093 */ 094 public VanDerCorputQRNG(int base, long seed) 095 { 096 this.base = Math.max(base, 2); 097 state = seed; 098 } 099 100 /** 101 * Gets the next quasi-random long as a fraction of {@link Long#MAX_VALUE}; this can never produce a negative value. 102 * It is extremely unlikely to produce two identical values unless the state is very high or is negative; state 103 * increases by exactly 1 each time this, {@link #next(int)}, or {@link #nextDouble()} is called and can potentially 104 * wrap around to negative values after many generations. 105 * @return a quasi-random non-negative long; may return 0 rarely, probably can't return {@link Long#MAX_VALUE} 106 */ 107 @Override 108 public long nextLong() { 109 long n = ++state & 0x7fffffffffffffffL; 110 if(base <= 2) { 111 return Long.reverse(n) >>> 1; 112 } 113 double denominator = base, res = 0.0; 114 while (n > 0) 115 { 116 res += (n % base) / denominator; 117 n /= base; 118 denominator *= base; 119 } 120 return (long) (res * Long.MAX_VALUE); 121 } 122 123 @Override 124 public int next(int bits) { 125 return (int)(nextLong()) >>> (32 - bits); 126 } 127 128 /** 129 * Gets the next quasi-random double from between 0.0 and 1.0 (normally both exclusive; only if state is negative or 130 * has wrapped around to a negative value can 0.0 ever be produced). It should be nearly impossible for this to 131 * return the same number twice unless floating-point precision has been exhausted or a very large amount of numbers 132 * have already been generated. Certain unusual bases may make this more likely. 133 * @return a quasi-random double that will always be less than 1.0 and will be no lower than 0.0 134 */ 135 public double nextDouble() { 136 long n = ++state & 0x7fffffffffffffffL; 137 if(base <= 2) { 138 return (Long.reverse(n) >>> 11) * 0x1p-53; 139 } 140 double denominator = base, res = 0.0; 141 while (n > 0) 142 { 143 res += (n % base) / denominator; 144 n /= base; 145 denominator *= base; 146 } 147 return res; 148 } 149 150 @Override 151 public VanDerCorputQRNG copy() { 152 return new VanDerCorputQRNG(base, state); 153 } 154 155 @Override 156 public long getState() { 157 return state; 158 } 159 160 @Override 161 public void setState(long state) { 162 this.state = state; 163 } 164 165 @Override 166 public String toString() { 167 return "VanDerCorputQRNG with base " + base + 168 " and state 0x" + StringKit.hex(state) + "L"; 169 } 170 171 @Override 172 public boolean equals(Object o) { 173 if (this == o) return true; 174 if (o == null || getClass() != o.getClass()) return false; 175 176 VanDerCorputQRNG that = (VanDerCorputQRNG) o; 177 178 return state == that.state && base == that.base; 179 180 } 181 182 @Override 183 public int hashCode() { 184 int result = (int) (state ^ (state >>> 32)); 185 result = 31 * result + base | 0; 186 return 31 * result | 0; 187 } 188 189 /** 190 * Convenience method that gets a quasi-random 2D point between integer (0,0) inclusive and (width,height) 191 * exclusive and fills it into point. This is roughly equivalent to creating two VanDerCorputQRNG generators, one 192 * with {@code new VanDerCorputQRNG(2, index)} and the other with 193 * {@code new VanDerCorputQRNG(39, index)}, then getting an x-coordinate from the first with 194 * {@code (int)(nextDouble() * width)} and similarly for y with the other generator. The advantage here is you don't 195 * actually create any objects using this static method, only assigning to point, if valid. You might find an 196 * advantage in using values for index that start higher than 20 or so, but you can pass sequential values for index 197 * and generally get points that won't be near each other; this is not true for all parameters to Halton sequences, 198 * but it is true for this one. 199 * @param width the maximum exclusive bound for the x-positions (index 0) of points this can return 200 * @param height the maximum exclusive bound for the y-positions (index 1) of points this can return 201 * @param index an int that, if unique, positive, and not too large, will usually result in unique points 202 * @param point an int array that will be modified; should have length 2; if null or too small, a new array will be created 203 * @return point after modifications to the first two items, or a new array if point is null or too small 204 */ 205 public static int[] halton(int width, int height, int index, int[] point) 206 { 207 if(point == null || point.length < 2) 208 point = new int[2]; 209 210 double denominator = 39.0, resY = 0.0; 211 int n = (index+1 & 0x7fffffff); 212 while (n > 0) 213 { 214 resY += (n % 39) / denominator; 215 n /= 39; 216 denominator *= 39.0; 217 } 218 point[0] = (int)(width * (Integer.reverse(index + 1) >>> 1) * 0x1p-31); 219 point[1] = (int)(resY * height); 220 return point; 221 } 222 /** 223 * Convenience method that gets a quasi-random Coord between integer (0,0) inclusive and (width,height) exclusive 224 * and gets the corresponding Coord from the Coord pool. This is roughly equivalent to creating two VanDerCorputQRNG 225 * generators, one with {@code new VanDerCorputQRNG(2, index)} and the other with 226 * {@code new VanDerCorputQRNG(39, index)}, then getting an x-coordinate from the first with 227 * {@code (int)(nextDouble() * width)} and similarly for y with the other generator. You might find an advantage in 228 * using values for index that start higher than 20 or so, but you can pass sequential values for index and 229 * generally get points that won't be near each other; this is not true for all parameters to Halton sequences, but 230 * it is true for this one. 231 * @param width the maximum exclusive bound for the x-positions (index 0) of points this can return 232 * @param height the maximum exclusive bound for the y-positions (index 1) of points this can return 233 * @param index an int that, if unique, positive, and not too large, will usually result in unique points 234 * @return point after modifications to the first two items, or a new array if point is null or too small 235 */ 236 public static Coord halton(int width, int height, int index) 237 { 238 return halton(width, height, 0, 0, index); 239 } 240 /** 241 * Convenience method that gets a quasi-random Coord between integer (0,0) inclusive and (width,height) exclusive 242 * and gets the corresponding Coord from the Coord pool. This is roughly equivalent to creating two VanDerCorputQRNG 243 * generators, one with {@code new VanDerCorputQRNG(2, index)} and the other with 244 * {@code new VanDerCorputQRNG(39, index)}, then getting an x-coordinate from the first with 245 * {@code (int)(nextDouble() * width)} and similarly for y with the other generator. You might find an advantage in 246 * using values for index that start higher than 20 or so, but you can pass sequential values for index and 247 * generally get points that won't be near each other; this is not true for all parameters to Halton sequences, but 248 * it is true for this one. 249 * @param width the width of the area this can cover 250 * @param height the height of the area this can cover 251 * @param xOffset the lowest x-coordinate this can produce, and also added to width to get the upper bound on x 252 * @param yOffset the lowest y-coordinate this can produce, and also added to height to get the upper bound on y 253 * @param index an int that, if unique, positive, and not too large, will usually result in unique points 254 * @return point after modifications to the first two items, or a new array if point is null or too small 255 */ 256 public static Coord halton(int width, int height, int xOffset, int yOffset, int index) 257 { 258 double denominator = 39.0, resY = 0.0; 259 int n = (index+1 & 0x7fffffff); 260 while (n > 0) 261 { 262 resY += (n % 39) / denominator; 263 n /= 39; 264 denominator *= 39.0; 265 } 266 return Coord.get((int)(width * (Integer.reverse(index + 1) >>> 1) * 0x1p-31) + xOffset, (int)(resY * height) + yOffset); 267 } 268 269 /** 270 * Convenience method that gets a quasi-random 3D point between integer (0,0,0) inclusive and (width,height,depth) 271 * exclusive. This is roughly equivalent to creating three VanDerCorputQRNG generators, one with 272 * {@code new VanDerCorputQRNG(2, index)} another with {@code new VanDerCorputQRNG(3, index)}, 273 * and another with {@code new VanDerCorputQRNG(5, index)}, then getting an x-coordinate from the first with 274 * {@code (int)(nextDouble() * width)} and similarly for y and z with the other generators. The advantage here is 275 * you don't actually create any objects using this static method, only assigning to point, if valid. You might find 276 * an advantage in using values for index that start higher than 20 or so, but you can pass sequential values for 277 * index and generally get points that won't be near each other; this is not true for all parameters to Halton 278 * sequences, but it is true for this one. 279 * @param width the maximum exclusive bound for the x-positions (index 0) of points this can return 280 * @param height the maximum exclusive bound for the y-positions (index 1) of points this can return 281 * @param depth the maximum exclusive bound for the z-positions (index 2) of points this can return 282 * @param index an int that, if unique, positive, and not too large, will usually result in unique points 283 * @param point an int array that will be modified; should have length 3; if null or too small, a new array will be created 284 * @return point after modifications to the first two items, or a new array if point is null or too small 285 */ 286 public static int[] halton(int width, int height, int depth, int index, int[] point) 287 { 288 if(point == null || point.length < 3) 289 point = new int[3]; 290 291 double denominator = 3.0, resY = 0.0, resZ = 0.0; 292 int n = (index+1 & 0x7fffffff); 293 while (n > 0) 294 { 295 resY += (n % 3) / denominator; 296 n /= 3; 297 denominator *= 3.0; 298 } 299 300 denominator = 5; 301 n = (index+1 & 0x7fffffff); 302 while (n > 0) 303 { 304 resZ += (n % 5) / denominator; 305 n /= 5; 306 denominator *= 5.0; 307 } 308 point[0] = (int)(width * (Integer.reverse(index + 1) >>> 1) * 0x1p-31); 309 point[1] = (int)(resY * height); 310 point[2] = (int)(resZ * depth); 311 return point; 312 } 313 314 /** 315 * Convenience method that gets a quasi-random Coord3D between integer (0,0,0) inclusive and (width,height,depth) 316 * exclusive. This is roughly equivalent to creating three VanDerCorputQRNG generators, one with 317 * {@code new VanDerCorputQRNG(2, index)} another with {@code new VanDerCorputQRNG(3, index)}, 318 * and another with {@code new VanDerCorputQRNG(5, index)}, then getting an x-coordinate from the first with 319 * {@code (int)(nextDouble() * width)} and similarly for y and z with the other generators. This overload always 320 * creates a new Coord3D object, so you might prefer {@link #halton(int, int, int, int, int[])}, which can reuse an 321 * int array. You might find an advantage in using values for index that start higher than 20 or so, but you can 322 * pass sequential values for index and generally get points that won't be near each other; this is not true for all 323 * parameters to Halton sequences, but it is true for this one. 324 * @param width the maximum exclusive bound for the x-positions (index 0) of points this can return 325 * @param height the maximum exclusive bound for the y-positions (index 1) of points this can return 326 * @param depth the maximum exclusive bound for the z-positions (index 2) of points this can return 327 * @param index an int that, if unique, positive, and not too large, will usually result in unique points 328 * @return a new Coord3D with x,y,z between 0,0,0 (inclusive) and width,height,depth (exclusive) 329 */ 330 public static Coord3D halton(int width, int height, int depth, int index) 331 { 332 double denominator = 3.0, resY = 0.0, resZ = 0.0; 333 int n = (index+1 & 0x7fffffff); 334 while (n > 0) 335 { 336 resY += (n % 3) / denominator; 337 n /= 3; 338 denominator *= 3.0; 339 } 340 341 denominator = 5; 342 n = (index+1 & 0x7fffffff); 343 while (n > 0) 344 { 345 resZ += (n % 5) / denominator; 346 n /= 5; 347 denominator *= 5.0; 348 } 349 return new Coord3D((int)(width * (Integer.reverse(index + 1) >>> 1) * 0x1p-31), 350 (int)(resY * height), 351 (int)(resZ * depth)); 352 } 353 354 /** 355 * Convenience method to get a double from the van der Corput sequence with the given {@code base} at the requested 356 * {@code index} without needing to construct a VanDerCorputQRNG. You should use a prime number for base; 2, 3, 5, 357 * and 7 should be among the first choices to ensure optimal quality unless you are scrambling the index yourself. 358 * If speed is the priority, then larger prime bases counter-intuitively perform better than small ones; 0x1337, 359 * 0xDE4D, 0x510B and 0xACED are all probable primes (using {@link java.math.BigInteger#isProbablePrime(int)}) that 360 * may do well here for speed but will likely require some basic scrambling of the index order. This method on its 361 * own does not perform any scrambling on index other than incrementing it and ensuring it is positive (by 362 * discarding the sign bit; for all positive index values other than 0x7FFFFFFF, this has no effect). If you want 363 * to quickly scramble an int index {@code i} for this purpose, try 364 * {@code (i ^ (i << 7 | i >>> 25) ^ (i << 19 | i >>> 13))}, which may compile to SSE instructions on recent 365 * desktop processors and won't risk losing precision on GWT. 366 * <br> 367 * Uses the same algorithm as {@link #determine2(int)} when base is 2, which should offer some speed improvement. 368 * The other bases use code adapted from 369 * <a href="https://blog.demofox.org/2017/05/29/when-random-numbers-are-too-random-low-discrepancy-sequences/">Alan Wolfe's blog</a>, 370 * which turned out to be a lot faster than the previous way I had it implemented. 371 * @param base a prime number to use as the base/radix of the van der Corput sequence 372 * @param index the position in the sequence of the requested base, as a non-negative int 373 * @return a quasi-random double between 0.0 (inclusive) and 1.0 (exclusive). 374 */ 375 public static double determine(final int base, final int index) 376 { 377 if(base <= 2) { 378 return (Integer.reverse(index + 1) >>> 1) * 0x1p-31; 379 } 380 double denominator = base, res = 0.0; 381 int n = (index+1 & 0x7fffffff); 382 while (n > 0) 383 { 384 res += (n % base) / denominator; 385 n /= base; 386 denominator *= base; 387 } 388 return res; 389 } 390 391 /** 392 * Convenience method to get a double from the van der Corput sequence with the base 2 at the requested 393 * {@code index} without needing to construct a VanDerCorputQRNG. This does not perform any scrambling on index 394 * other than incrementing it and ensuring it is positive (by discarding the sign bit; for all positive index values 395 * other than 0x7FFFFFFF ({@link Integer#MAX_VALUE}), this has no effect). 396 * <br> 397 * Because binary manipulation of numbers is easier and more efficient, the technique used by this method is also 398 * used by {@link #determine(int, int)} when base is 2, and should be faster than other bases. 399 * @param index the position in the base-2 van der Corput sequence, as a non-negative int 400 * @return a quasi-random double between 0.0 (inclusive) and 1.0 (exclusive). 401 */ 402 public static double determine2(int index) 403 { 404 return (Integer.reverse(index + 1) >>> 1) * 0x1p-31; 405 } 406 /** 407 * Method to get a double from the van der Corput sequence with the base 2 at a scrambling of the requested 408 * {@code index} without needing to construct a VanDerCorputQRNG. This performs different scrambling on index 409 * than the instance methods on this class perform, and it seems to do well enough while being a little simpler. 410 * This is meant to be usable as an alternative to a different base for a van der Corput sequence when you need two 411 * different sequences, and are already using base 2 via {@link #determine2(int)}. 412 * <br> 413 * Because binary manipulation of numbers is easier and more efficient, this method should be somewhat faster than 414 * the alternatives, like {@link #determine(int, int)} with base 2. It should take only slightly longer to run than 415 * {@link #determine2(int)}, due to the brief amount of time needed to scramble the index. 416 * @param index the position in the sequence of the requested base 417 * @return a quasi-random double between 0.0 (inclusive) and 1.0 (exclusive). 418 */ 419 public static double determine2_scrambled(int index) 420 { 421 return (Integer.reverse(++index ^ (index << 7 | index >>> 25) ^ (index << 19 | index >>> 13)) >>> 1) * 0x1p-31; 422 } 423 424 private static final int[] lowPrimes = {2, 3, 2, 3, 5, 2, 3, 2}; 425 426 /** 427 * Chooses one sequence from the van der Corput sequences with bases 2, 3, and 5, where 5 is used 1/8 of the time, 428 * 3 is used 3/8 of the time, and 2 is used 1/2 of the time, and returns a double from the chosen sequence at the 429 * specified {@code index}. The exact setup used for the choice this makes is potentially fragile, but in certain 430 * circumstances this does better than {@link SobolQRNG} at avoiding extremely close values (the kind that overlap 431 * on actual maps). Speed is not a concern here; this should be very much fast enough for the expected usage in 432 * map generation (it's used in {@link GreasedRegion#quasiRandomSeparated(double)}. 433 * @param index the index to use from one of the sequences; will also be used to select sequence 434 * @return a double from 0.0 (inclusive, but extremely rare) to 1.0 (exclusive); values will tend to spread apart 435 */ 436 public static double determineMixed(int index) 437 { 438 return determine(lowPrimes[index & 7], index); 439 } 440 441 /** 442 * Given any int (0 is allowed), this gets a somewhat-sub-random float from 0.0 (inclusive) to 1.0 (exclusive) 443 * using the same implementation as {@link NumberTools#randomFloat(long)} but with index alterations. Only "weak" 444 * because it lacks the stronger certainty of subsequent numbers being separated that the Van der Corput sequence 445 * has. Not actually sub-random, but should be distributed fairly well (internally uses {@link ThrustAltRNG}'s 446 * algorithm, which does not guarantee that its outputs are unique). 447 * <br> 448 * Not all int values for index will produce unique results, since this produces a float and there are less distinct 449 * floats between 0.0 and 1.0 than there are all ints (1/512 as many floats in that range as ints, specifically). 450 * It should take a while calling this method before you hit an actual collision. 451 * @param index any int 452 * @return a float from 0.0 (inclusive) to 1.0 (exclusive) that should not be closely correlated to index 453 */ 454 public static float weakDetermine(final int index) 455 { 456 return NumberTools.randomFloat((index >>> 19 | index << 13) ^ 0x13A5BA1D); 457 //return NumberTools.longBitsToDouble(0x3ff0000000000000L | ((index<<1|1) * 0x9E3779B97F4A7C15L * ~index 458 // - ((index ^ ~(index * 11L)) * 0x632BE59BD9B4E019L)) >>> 12) - 1.0; 459 //return NumberTools.setExponent( 460 // (NumberTools.setExponent((index<<1|1) * 0.618033988749895, 0x3ff)) 461 // * (0x232BE5 * (~index)), 0x3ff) - 1.0; 462 } 463 464 /** 465 * Like {@link #weakDetermine(int)}, but returns a float between -1.0f and 1.0f, exclusive on both. Uses 466 * {@link NumberTools#randomSignedFloat(long)} internally but alters the index parameter so calls with nearby values 467 * for index are less likely to have nearby results. 468 * @param index any int 469 * @return a sub-random float between -1.0f and 1.0f (both exclusive, unlike some other methods) 470 */ 471 public static float weakSignedDetermine(final int index) { 472 return NumberTools.randomSignedFloat((index >>> 19 | index << 13) ^ 0x13A5BA1D); 473 } 474 475 /** 476 * Similar to {@link #determine(int, int)}, but can take bases that aren't prime and can sometimes produce a 477 * Halton-like sequence with almost-as-good distance between points. The base is allowed to be any odd long, 478 * (negative bases are allowed). The index can technically also be negative, and if this is given 0 it will not 479 * return any specific number (it will vary with the base). This returns a double between 0.0 inclusive and 1.0 480 * exclusive. Better results have been found with larger bases (points tend to be more spread out). It is never as 481 * good at spreading out 2D points as a 2,3 Halton sequence, at least for any bases tried so far. 482 * <br> 483 * Earlier versions of this method wound up only producing points on parallel lines in 2D, never placing points in 484 * between those lines. This sometimes formed a hex-like grid that, as hexagons do, has optimal packing properties, 485 * which made the optimal distance seem very good despite the points having a clear pattern. This can still 486 * sometimes be useful; when you want optimal distance and don't have a case where a clear pattern on a grid is an 487 * issue, it can have high performance. The code for the old way is small, though not simple: 488 * {@code ((base * Integer.reverse(index) << 21) & 0x1fffffffffffffL) * 0x1p-53}, where base is an odd long and 489 * index is any int. It works best in one dimension. 490 * @param base any odd long 491 * @param index any int 492 * @return a double between 0.0 inclusive and 1.0 exclusive 493 */ 494 public static double altDetermine(long base, final int index) { return (((base = (Long.reverse(base + index) ^ 0x5851F42D4C957F2DL) * 0x14057B7EF767814BL) >>> 11) ^ (base >>> 13) ^ (base >>> 14)) * 0x1p-53; } 495// public static double altDetermine(long base, final int index) { return ((((index * 0x5851F42D4C957F2DL + base) * 0x5851F42D4C957F2DL + base) * 0x5851F42D4C957F2DL + base) >>> 11) * 0x1p-53; } 496 497 /** 498 * A quasi-random number generator of doubles between 0.0 inclusive and 1.0 exclusive, but that has issues when it 499 * would be used like a Halton sequence. Only ideal in 1D, this produces well-separated points that are aligned to 500 * parallel hyperplanes when called with different bases and each base used as an axis for more than 1 dimension. 501 * This can produce points with more separation in 2D than a Halton sequence can, but not often. Two bases that do 502 * this when used together are the ints 0xDE4DBEEF and 0x1337D00D (or in decimal, -565330193 and 322424845; note 503 * that 0xDE4DBEEF is a negative integer); they were tried as a gimmick but nothing else turned out better. They do 504 * still produce points on parallel lines, and like all bases, never points between those lines. 505 * <br> 506 * Note, the source of this method is one line, and you may see benefits from copying that code into the call-site 507 * with minor modifications. This returns 508 * {@code (((base * Integer.reverse(index)) << 21) & 0x1fffffffffffffL) * 0x1p-53;}, where base is a long and index 509 * is an int (as in the method signature). The multiplier 0x1p-53 is a very small hexadecimal double literal, using 510 * the same syntax as other parts of SquidLib use for packed floats; using this helps avoid precision loss. If you 511 * want a range larger than 0.0 to 1.0, you can change the multiplier {@code 0x1p-53} to some other constant, like 512 * declaring {@code final double upTo100 = 0x1p-53 * 100.0} before some code that wants quasi-random numbers between 513 * 0.0 inclusive and 100.0 exclusive, then using 514 * {@code (((base * Integer.reverse(index)) << 21) & 0x1fffffffffffffL) * upTo100;} to get those numbers. It isn't 515 * precise to use this technique to get numbers with an upper bound less than 1.0, because 0x1p-53 is about as small 516 * as a double can get with precision intact. In that case, you can use 517 * {@code (((base * Integer.reverse(index)) << 8) & 0xffffffffffL) * smallBound;} where smallBound has been declared 518 * as {@code final double smallBound = 0x1p-40 * 0.05;} (where 0.05 can be switched out for any double between 519 * 1.0/8192.0 and 1.0). 520 * @param base any odd long; the most significant 21 bits (except the sign bit) are effectively ignored 521 * @param index any int; if 0 this will return 0 522 * @return a double between 0.0 inclusive and 1.0 exclusive 523 */ 524 public static double planarDetermine(long base, final int index) { return ((base * Integer.reverse(index) << 21) & 0x1fffffffffffffL) * 0x1p-53; } 525 526 /** 527 * Samples a quasi-random Coord sequence that is almost unique to the given seed, getting a Coord with x between 528 * xOffset (inclusive) and width + xOffset (exclusive), y between yOffset (inclusive) and height + yOffset 529 * (exclusive). The seed is "almost" unique because even seeds are discouraged; there is an identical sequence for 530 * every even seed produced by some odd seed. This generates a not-very random number, reverses its bits as other 531 * methods in this class do, then treats that single 32-bit int as two coordinates on a Z-order curve to get 532 * separate x and y from them. In practice these Coords are very well-dispersed if only a small amount are sampled 533 * and all the index values are close-by, and get closer together as more are sampled. Unlike the Halton sequence, 534 * this has very different results with different seeds (Halton only allows bases to be changed), and doesn't 535 * involve any division, modulus, conditionals, or loops. 536 * @param seed an int seed that should be an odd number 537 * @param width the width of the area this can cover 538 * @param height the height of the area this can cover 539 * @param xOffset the lowest x-coordinate this can produce, and also added to width to get the upper bound on x 540 * @param yOffset the lowest y-coordinate this can produce, and also added to height to get the upper bound on y 541 * @param index the index in the sequence, almost always a positive int that increases by 1 with each call 542 * @return a Coord between (xOffset, yOffset) inclusive and (width+xOffset, height+yOffset) exclusive 543 */ 544 public static Coord haltoid(int seed, int width, int height, int xOffset, int yOffset, int index) 545 { 546 int morton = GreasedRegion.disperseBits(Integer.reverse((seed * 0x2C9277B5 | 1) * (index + 1))); 547 return Coord.get((int)(width * ((morton & 0xffff) * 0x1p-16)) + xOffset, (int)(((morton >>> 16) * 0x1p-16) * height) + yOffset); 548 } 549 /** 550 * Martin Roberts' "unreasonably effective" quasi-random int sequence based on the golden ratio. 551 * See <a href="http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/">his blog</a> for 552 * more detailed info, but this can be summarized as being extremely good at separating outputs at the expense of 553 * seeming less random. Produces an int between offset (inclusive) and offset + span (exclusive), with the int at 554 * each {@code index} likely to be different for at least {@code span / 4} indices (very low spans may offer less of 555 * a guarantee). 556 * <br> 557 * Note, use {@link #roberts(int, int, int, int, int)} for 2D points and this method for 1D values; the same 558 * properties won't be preserved if you use a 1D Roberts sequence in 2D. 559 * @param span the size of the range this can return 560 * @param offset the minimum value this can return 561 * @param index the index of the int in the 1D Roberts sequence; should be greater than 0, but not required to be 562 * @return an int between offset inclusive and offset+span exclusive 563 */ 564 public static int roberts(int span, int offset, int index) 565 { 566 return (int)((index * 0x9E3779B9L & 0xFFFFFFFFL) * span >>> 32) + offset; 567 } 568 569 /** 570 * Martin Roberts' "unreasonably effective" quasi-random point sequence based on a 2D analogue to the golden ratio. 571 * See <a href="http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/">his blog</a> for 572 * more detailed info, but this can be summarized as being extremely good at separating points at the expense of 573 * seeming less random. Produces a Coord with x between xOffset (inclusive) and xOffset + width (exclusive), and y 574 * between yOffset (inclusive) and yOffset + height (exclusive), with the Coord at each {@code index} likely to be 575 * different for at least {@code width * height / 4} indices (very low sizes may offer less of a guarantee). 576 * @param width the x-size of the space this can place a Coord 577 * @param height the y-size of the space this can place a Coord 578 * @param xOffset the minimum x-position of a Coord 579 * @param yOffset the minimum y-position of a Coord 580 * @param index the index of the Coord in the 2D Roberts sequence; should be greater than 0, but not required to be 581 * @return a Coord with x,y between xOffset,yOffset inclusive and xOffset+width,yOffset+height exclusive 582 */ 583 public static Coord roberts(int width, int height, int xOffset, int yOffset, int index) 584 { 585 return Coord.get( 586 (int)((index * 0xC13FA9A9L & 0xFFFFFFFFL) * width >>> 32) + xOffset, 587 (int)((index * 0x91E10DA5L & 0xFFFFFFFFL) * height >>> 32) + yOffset); 588 } 589}