001package squidpony.squidmath; 002 003/** 004 * Performance-oriented white noise generator for 1D, 2D, 3D, 4D, and 6D. Produces noise values from -1.0 inclusive 005 * to 1.0 exclusive. Should produce a completely different double even for extremely-nearby points, so this is not a 006 * kind of continuous noise like {@link SeededNoise}. It is not actually random, and the value is always determined by 007 * the exact double positions (and possibly a long seed) given to it. Even a slight change should drastically alter the 008 * returned value, though below some very small epsilon the results might not be different between two very close points 009 * in space. The output should look like "TV static" if rendered as grayscale pixels. 010 * <br> 011 * Meant for cases where you want to use a different number for every pixel, tile, or other unit of noise generated, 012 * often coupled with another kind of noise but with the result of the WhiteNoise made less significant to add a "fuzzy" 013 * effect to the appearance. 014 * <br> 015 * Implementation is based on {@link CrossHash.Wisp#hash64(double[])}, treating doubles as ints 016 * by using {@link NumberTools#doubleToMixedIntBits(double)}, which XORs the bottom and top halves of the long bits of 017 * each double. Finishes by passing the top 52 bits as a significand to {@link NumberTools#longBitsToDouble(long)}, 018 * using an exponent that allows this to produce numbers between -1.0 and 1.0. Has special treatment for the seed when 019 * present (since it is a long). 020 * <br> 021 * This can also be used as a sort of hashing function that produces a double, if you find a need for such a thing, with 022 * {@link #hash(double...)}. 023 */ 024public class WhiteNoise implements Noise.Noise1D, Noise.Noise2D, Noise.Noise3D, Noise.Noise4D, Noise.Noise6D { 025 public static final WhiteNoise instance = new WhiteNoise(); 026 027 public WhiteNoise() { 028 } 029 030 @Override 031 public double getNoise(double x) { 032 long a = 0x632BE59BD9B4E019L, 033 result = 0x9E3779B97F4A7C94L + 034 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)); 035 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 036 } 037 038 @Override 039 public double getNoiseWithSeed(double x, long seed) { 040 long a = 0x632BE59BD9B4E019L, 041 result = 0x9E3779B97F4A7C94L + 042 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)) 043 + (a ^= 0x8329C6EB9E6AD3E3L * seed); 044 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 045 } 046 047 @Override 048 public double getNoise(double x, double y) { 049 050 long a = 0x632BE59BD9B4E019L, 051 result = 0x9E3779B97F4A7C94L + 052 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)) 053 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(y*0x11.8329C6DFp3)); 054 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 055 } 056 @Override 057 public double getNoiseWithSeed(double x, double y, long seed) { 058 long a = 0x632BE59BD9B4E019L, 059 result = 0x9E3779B97F4A7C94L + 060 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)) 061 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(y*0x11.8329C6DFp3)) 062 + (a ^= 0x8329C6EB9E6AD3E3L * seed); 063 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 064 } 065 066 @Override 067 public double getNoise(double x, double y, double z) { 068 long a = 0x632BE59BD9B4E019L, 069 result = 0x9E3779B97F4A7C94L + 070 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)) 071 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(y*0x11.8329C6DFp3)) 072 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(z*0x11.85157AF5p3)); 073 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 074 } 075 076 @Override 077 public double getNoiseWithSeed(double x, double y, double z, long seed) { 078 long a = 0x632BE59BD9B4E019L, 079 result = 0x9E3779B97F4A7C94L + 080 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)) 081 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(y*0x11.8329C6DFp3)) 082 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(z*0x11.85157AF5p3)) 083 + (a ^= 0x8329C6EB9E6AD3E3L * seed); 084 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 085 } 086 @Override 087 public double getNoise(double x, double y, double z, double w) { 088 long a = 0x632BE59BD9B4E019L, 089 result = 0x9E3779B97F4A7C94L + 090 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)) 091 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(y*0x11.953976F9p3)) 092 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(z*0x11.85157AF5p3)) 093 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(w*0x11.8329C6DFp3)); 094 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 095 } 096 097 @Override 098 public double getNoiseWithSeed(double x, double y, double z, double w, long seed) { 099 long a = 0x632BE59BD9B4E019L, 100 result = 0x9E3779B97F4A7C94L + 101 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)) 102 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(y*0x11.953976F9p3)) 103 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(z*0x11.85157AF5p3)) 104 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(w*0x11.8329C6DFp3)) 105 + (a ^= 0x8329C6EB9E6AD3E3L * seed); 106 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 107 } 108 109 @Override 110 public double getNoise(double x, double y, double z, double w, double u, double v) { 111 long a = 0x632BE59BD9B4E019L, 112 result = 0x9E3779B97F4A7C94L + 113 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)) 114 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(y*0x17.08329C6DFp2)) 115 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(z*0x29.085157AF5p1)) 116 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(w*0x11.85157AF5p3)) 117 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(u*0x17.09E3779B9p2)) 118 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(v*0x29.08329C6DFp1)); 119 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 120 } 121 122 @Override 123 public double getNoiseWithSeed(double x, double y, double z, double w, double u, double v, long seed) { 124 long a = 0x632BE59BD9B4E019L, 125 result = 0x9E3779B97F4A7C94L + 126 (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(x*0x11.9E3779B9p3)) 127 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(y*0x17.08329C6DFp2)) 128 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(z*0x29.085157AF5p1)) 129 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(w*0x11.85157AF5p3)) 130 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(u*0x17.09E3779B9p2)) 131 + (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(v*0x29.08329C6DFp1)) 132 + (a ^= 0x8329C6EB9E6AD3E3L * seed); 133 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 134 } 135 136 /** 137 * Hashes the input double array or vararg and produces a double with unpredictable value, between -1.0 inclusive 138 * and 1.0 exclusive. 139 * @param data an array or vararg of double items; should not include NaN or infinite values but has no other limits 140 * @return an unpredictable double between -1.0 inclusive and 1.0 exclusive 141 */ 142 public static double hash(double... data) { 143 if(data == null) return 0.0; 144 long a = 0x632BE59BD9B4E019L, result = 0x9E3779B97F4A7C94L; 145 double t = 0x13.9E3779B9p-5; 146 int len = data.length; 147 for (int i = 0; i < len; i++) { 148 result += (a ^= 0x8329C6EB9E6AD3E3L * (NumberTools.doubleToMixedIntBits((t *= t - data[i])))); 149 } 150 return NumberTools.longBitsToDouble(((result * (a | 1L) ^ (result >>> 27 | result << 37)) >>> 12) | 0x4000000000000000L) - 3.0; 151 } 152 153}