├── .gitignore ├── src └── roquen │ ├── adt │ └── package-info.java │ ├── vm │ ├── package-info.java │ ├── VMQuery.java │ ├── FatOaf.java │ └── UnsafeUtils.java │ ├── info │ ├── package-info.java │ └── HsIntrinsics.java │ ├── concurrent │ ├── package-info.java │ └── ConcurrentUtils.java │ ├── math │ ├── package-info.java │ ├── rng │ │ ├── discrete │ │ │ ├── package-info.java │ │ │ ├── DiscreteMethod.java │ │ │ ├── AliasMethodFlat.java │ │ │ ├── AliasMethodFixedPoint.java │ │ │ ├── RandomSelect.java │ │ │ └── AliasMethod.java │ │ ├── XorPlus128.java │ │ ├── XorShift32.java │ │ ├── PRNG64.java │ │ ├── package-info.java │ │ ├── PRNG32.java │ │ ├── LCG64.java │ │ ├── XorShift64.java │ │ ├── LCG32.java │ │ ├── TestDist.java │ │ ├── XorStar64.java │ │ ├── XorWow64.java │ │ ├── XorStar32.java │ │ ├── XorWow32.java │ │ ├── BidirectionalLCG.java │ │ └── PRNG.java │ ├── seq │ │ ├── package-info.java │ │ ├── FloatSequence.java │ │ ├── IntegerSequence.java │ │ ├── PermutedSequence.java │ │ ├── PermutedSequencePOT.java │ │ └── TestIntSequence.java │ ├── test │ │ ├── package-info.java │ │ ├── FloatError32.java │ │ └── FloatError64.java │ ├── lds │ │ ├── package-info.java │ │ ├── LDS.java │ │ ├── Sobol1D.java │ │ ├── SobolFixed2D.java │ │ ├── SobolFixed3D.java │ │ ├── Sobol2D.java │ │ └── Sobol3D.java │ ├── sfc │ │ ├── MortonIndex2D.java │ │ ├── RowLinearIndex2D.java │ │ ├── Index2D.java │ │ ├── Morton3D.java │ │ ├── Morton2DBase.java │ │ └── Morton2D.java │ ├── Int64.java │ ├── Trig64.java │ ├── Trig32.java │ ├── Int32.java │ ├── Float64.java │ └── Float32.java │ ├── wiki │ ├── dvar │ │ ├── package-info.java │ │ ├── Entity.java │ │ ├── UserVar.java │ │ └── GameObject.java │ └── RngDiscreteDist.java │ ├── blackbox │ └── package-info.java │ ├── fake │ ├── package-info.java │ ├── Vect2i.java │ ├── Vect3i.java │ ├── Vect3f.java │ └── Vect2f.java │ ├── util │ ├── FloatPairArray.java │ ├── IntPairArray.java │ ├── IntPair.java │ ├── FloatPair.java │ └── Generics.java │ ├── package-info.java │ ├── pr0n │ ├── package-info.java │ ├── Deceiver.java │ └── Dissembler.java │ ├── hash │ ├── package-info.java │ └── MurmurHash2.java │ ├── interp │ ├── RayGrid3D.java │ ├── IndexedRayGrid2D.java │ ├── RayGrid2D.java │ ├── DDA2D.java │ └── DDA3D.java │ └── pg │ └── noise │ ├── ValueNoise.java │ ├── SimplexNoise3D.java │ └── Noise.java ├── README.md ├── .settings └── org.eclipse.core.resources.prefs ├── .classpath ├── .project └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | # temp files 2 | *~ 3 | 4 | bin/ -------------------------------------------------------------------------------- /src/roquen/adt/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package roquen.adt; -------------------------------------------------------------------------------- /src/roquen/vm/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package roquen.vm; -------------------------------------------------------------------------------- /src/roquen/info/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package roquen.info; -------------------------------------------------------------------------------- /src/roquen/concurrent/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package roquen.concurrent; -------------------------------------------------------------------------------- /src/roquen/math/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Blah 3 | */ 4 | 5 | package roquen.math; 6 | -------------------------------------------------------------------------------- /src/roquen/wiki/dvar/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package roquen.wiki.dvar; 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JGO-Grabbag 2 | =========== 3 | 4 | non library of java source targeting game development 5 | -------------------------------------------------------------------------------- /src/roquen/math/rng/discrete/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package roquen.math.rng.discrete; 5 | -------------------------------------------------------------------------------- /src/roquen/math/seq/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Integer sequences 3 | */ 4 | 5 | package roquen.math.seq; 6 | -------------------------------------------------------------------------------- /src/roquen/blackbox/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Supposed to contain blackbox testing. 3 | */ 4 | package roquen.blackbox; -------------------------------------------------------------------------------- /src/roquen/math/rng/XorPlus128.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roquendm/JGO-Grabbag/HEAD/src/roquen/math/rng/XorPlus128.java -------------------------------------------------------------------------------- /src/roquen/math/rng/XorShift32.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roquendm/JGO-Grabbag/HEAD/src/roquen/math/rng/XorShift32.java -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/roquen/wiki/complex/C2D.java=UTF-8 3 | -------------------------------------------------------------------------------- /src/roquen/fake/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Stub classes to be replaced with the 'real' ones. 3 | */ 4 | 5 | package roquen.fake; 6 | -------------------------------------------------------------------------------- /src/roquen/math/test/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Helper routines for testing floating point values. 3 | */ 4 | package roquen.math.test; -------------------------------------------------------------------------------- /src/roquen/math/seq/FloatSequence.java: -------------------------------------------------------------------------------- 1 | package roquen.math.seq; 2 | 3 | public interface FloatSequence 4 | { 5 | public float nextFloat(); 6 | } 7 | -------------------------------------------------------------------------------- /src/roquen/math/seq/IntegerSequence.java: -------------------------------------------------------------------------------- 1 | package roquen.math.seq; 2 | 3 | public interface IntegerSequence 4 | { 5 | public int nextInt(); 6 | } 7 | -------------------------------------------------------------------------------- /src/roquen/util/FloatPairArray.java: -------------------------------------------------------------------------------- 1 | package roquen.util; 2 | 3 | public class FloatPairArray 4 | { 5 | public T[] t; 6 | public float[] f; 7 | } 8 | -------------------------------------------------------------------------------- /src/roquen/util/IntPairArray.java: -------------------------------------------------------------------------------- 1 | package roquen.util; 2 | 3 | public class IntPairArray 4 | { 5 | public T[] t; 6 | public float[] f; 7 | } 8 | -------------------------------------------------------------------------------- /src/roquen/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Currently anything here is PD with no warrant...if you use it, it's your 3 | * problem. 4 | */ 5 | 6 | package roquen; 7 | -------------------------------------------------------------------------------- /src/roquen/pr0n/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Everything in the 'roquen' packages are use at your risk. 3 | * Source is this package should make you feel dirty to look 4 | * at and you're a nut case to actually use it. 5 | */ 6 | package roquen.pr0n; -------------------------------------------------------------------------------- /src/roquen/math/rng/discrete/DiscreteMethod.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng.discrete; 2 | 3 | /** 4 | * 5 | */ 6 | abstract public class DiscreteMethod 7 | { 8 | /** */ 9 | public abstract int nextInt(roquen.math.rng.PRNG rng); 10 | } 11 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/roquen/hash/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Utilities for building hashes. All base method classes should provide 3 | * the same static utility methods so a static import allows for a compile 4 | * time choice of technique. 5 | */ 6 | 7 | package roquen.hash; 8 | -------------------------------------------------------------------------------- /src/roquen/math/lds/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Low-discrepancy sequences (quasi random numbers) 3 | *

4 | * JGO wiki page 5 | */ 6 | 7 | package roquen.math.lds; 8 | -------------------------------------------------------------------------------- /src/roquen/math/lds/LDS.java: -------------------------------------------------------------------------------- 1 | package roquen.math.lds; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | public abstract class LDS 6 | { 7 | /** atomic count-down for parameterless constructors */ 8 | protected static AtomicInteger mix = new AtomicInteger(-1); 9 | } 10 | -------------------------------------------------------------------------------- /src/roquen/math/rng/PRNG64.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | /** 4 | * Basic class of random number generators that operate on 64-bit 5 | * integer data chunks. 6 | */ 7 | public abstract class PRNG64 extends PRNG 8 | { 9 | @Override 10 | public final int nextInt() { return (int)(nextLong() >>> 32); } 11 | } 12 | -------------------------------------------------------------------------------- /src/roquen/math/rng/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains a reasonable selection of pseudo random number 3 | * generators targeting game runtimes. 4 | *

5 | * For rational see: JGO wiki page 6 | * 7 | */ 8 | 9 | package roquen.math.rng; 10 | -------------------------------------------------------------------------------- /src/roquen/fake/Vect2i.java: -------------------------------------------------------------------------------- 1 | package roquen.fake; 2 | 3 | import static roquen.hash.MurmurHash2.*; 4 | 5 | public class Vect2i { 6 | public int x, y; 7 | 8 | /** */ 9 | private static final int HASH = hashMakeSeed(0); 10 | 11 | @Override 12 | public int hashCode() 13 | { 14 | return hashComplete(hashAdd(HASH,x,y)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/roquen/fake/Vect3i.java: -------------------------------------------------------------------------------- 1 | package roquen.fake; 2 | 3 | import static roquen.hash.MurmurHash2.*; 4 | 5 | public class Vect3i { 6 | public int x,y,z; 7 | 8 | /** */ 9 | private static final int HASH = hashMakeSeed(0); 10 | 11 | @Override 12 | public int hashCode() 13 | { 14 | return hashComplete(hashAdd(HASH,x,y,z)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/roquen/math/rng/PRNG32.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | /** 4 | * Basic class of random number generators that operate on 32-bit 5 | * integer data chunks. 6 | */ 7 | public abstract class PRNG32 extends PRNG 8 | { 9 | @Override 10 | public final long nextLong() 11 | { 12 | long r = nextInt(); 13 | return (r<<32) | nextInt(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | JGO-Grabbag 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/roquen/math/sfc/MortonIndex2D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.sfc; 2 | 3 | /** 4 | * Represents 2D coordinates as an index using a Morton/Z-order/Lebesgue curve. 5 | */ 6 | public class MortonIndex2D extends Morton2DBase 7 | { 8 | @Override 9 | public final void set(MortonIndex2D v) 10 | { 11 | sx = v.sx; 12 | sy = v.sy; 13 | } 14 | 15 | @Override 16 | public final int getIndex() 17 | { 18 | return sx|sy; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/roquen/fake/Vect3f.java: -------------------------------------------------------------------------------- 1 | package roquen.fake; 2 | 3 | import static roquen.hash.MurmurHash2.*; 4 | 5 | public class Vect3f { 6 | public float x,y,z; 7 | 8 | /** */ 9 | private static final int HASH = hashMakeSeed(0); 10 | 11 | @Override 12 | public int hashCode() 13 | { 14 | return hashComplete(hashAdd(HASH,x,y,z)); 15 | } 16 | 17 | public final float dot(Vect3f v) 18 | { 19 | return x*v.x + y*v.y + z*v.z; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/roquen/fake/Vect2f.java: -------------------------------------------------------------------------------- 1 | package roquen.fake; 2 | 3 | import static roquen.hash.MurmurHash2.*; 4 | 5 | public class Vect2f { 6 | public float x,y; 7 | 8 | public Vect2f set(float x, float y) 9 | { 10 | this.x=x; this.y=y; 11 | return this; 12 | } 13 | 14 | 15 | /** */ 16 | private static final int HASH = hashMakeSeed(0); 17 | 18 | @Override 19 | public int hashCode() 20 | { 21 | return hashComplete(hashAdd(HASH,x,y)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/roquen/wiki/dvar/Entity.java: -------------------------------------------------------------------------------- 1 | package roquen.wiki.dvar; 2 | 3 | // fake stub base class 4 | public class Entity extends GameObject 5 | { 6 | // the 'class' of this entity 7 | final ArchType type; 8 | 9 | Entity(ArchType def) 10 | { 11 | type = def; 12 | } 13 | 14 | public void runAI() { 15 | // put any preconditions that apply to everyone here 16 | 17 | // invoke the open class method 18 | type.aiMethod.run(this); 19 | 20 | // put any postconditions that apply to everyone here 21 | } 22 | 23 | // no entity proxy 24 | public static final Entity NILL = new Entity(ArchType.NILL); 25 | } 26 | -------------------------------------------------------------------------------- /src/roquen/concurrent/ConcurrentUtils.java: -------------------------------------------------------------------------------- 1 | package roquen.concurrent; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | /** 6 | * http://g.oswego.edu/dl/jmm/cookbook.html 7 | */ 8 | public enum ConcurrentUtils 9 | { 10 | ; 11 | // 12 | private static volatile int dummy; 13 | private static final AtomicInteger ai = new AtomicInteger(); 14 | 15 | 16 | public static int loadLoadBarrier() 17 | { 18 | return dummy; 19 | } 20 | 21 | public static void loadStoreBarrier() 22 | { 23 | dummy = 0; 24 | } 25 | 26 | public static void storeStoreBarrier() 27 | { 28 | ai.lazySet(-1); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/roquen/util/IntPair.java: -------------------------------------------------------------------------------- 1 | package roquen.util; 2 | 3 | public class IntPair implements Comparable> 4 | { 5 | public T data; 6 | public int value; 7 | 8 | @Override 9 | public int compareTo(IntPair o) { 10 | return value - o.value; 11 | } 12 | 13 | public static void sort(java.util.List> list) 14 | { 15 | java.util.Collections.sort(list); 16 | } 17 | 18 | public static IntPairArray flatten(java.util.List> list) 19 | { 20 | int len = list.size(); 21 | int i = 0; 22 | 23 | IntPairArray r = new IntPairArray<>(); 24 | r.t = Generics.newArray(len); 25 | r.f = new float[len]; 26 | 27 | for(IntPair e : list) { 28 | r.t[i] = e.data; 29 | r.f[i] = e.value; 30 | i++; 31 | } 32 | 33 | return r; 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/roquen/math/rng/LCG64.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | /*** 4 | * Basic power-of-two 64-bit LCG. 5 | * References: 6 | *

  • "Tables of linear congruential generators of different sizes and good lattice structure", Pierre L'Ecuyer, 1999.
  • 7 | */ 8 | public final class LCG64 extends PRNG64 9 | { 10 | /** state data */ 11 | private long data; 12 | 13 | public LCG64() 14 | { 15 | setSeed((mix.getAndDecrement() ^ System.nanoTime())); 16 | } 17 | 18 | public LCG64(long seed) 19 | { 20 | setSeed(seed); 21 | } 22 | 23 | @Override 24 | public final void setSeed(long seed) 25 | { 26 | data = seed; 27 | } 28 | 29 | @Override 30 | public final long getSeed() 31 | { 32 | return data; 33 | } 34 | 35 | @Override 36 | public final long nextLong() 37 | { 38 | data = 3935559000370003845L * data + 0x61C8864680b583EBL; 39 | 40 | return data; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/roquen/math/rng/XorShift64.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | 4 | /* Implementation notes: 5 | * SmallCrush failure: [13,7,17] 6 | * 8 MatrixRank eps 7 | */ 8 | 9 | /*** 10 | * Basic XorShift (64-bit) generator. 11 | *

    12 | * Period: 264-1, 13 | *

    14 | */ 15 | 16 | public final class XorShift64 extends PRNG64 17 | { 18 | private long data; 19 | 20 | public XorShift64() 21 | { 22 | setSeed((mix.getAndDecrement() ^ System.nanoTime())); 23 | } 24 | 25 | public XorShift64(long seed) 26 | { 27 | setSeed(seed); 28 | } 29 | 30 | @Override 31 | public final long nextLong() 32 | { 33 | data ^= (data << 13); 34 | data ^= (data >>> 7); 35 | data ^= (data << 17); 36 | return data; 37 | } 38 | 39 | @Override 40 | public void setSeed(long seed) { 41 | if (seed == 0) seed = Long.MIN_VALUE; 42 | data = seed; 43 | } 44 | 45 | @Override 46 | public long getSeed() { 47 | return data; 48 | } 49 | } -------------------------------------------------------------------------------- /src/roquen/math/Int64.java: -------------------------------------------------------------------------------- 1 | package roquen.math; 2 | 3 | public enum Int64 4 | { 5 | ; 6 | 7 | // The basic bit-hacks can just be copied from Int32. 8 | // Note that HotSpot as of this writing performs less 9 | // optimizations for 64-bit integers than 32-bit.. 10 | // sigh. 11 | 12 | public static long parity(long x) 13 | { 14 | if (Int32.hasPopCount) 15 | return Long.bitCount(x) & 1; 16 | 17 | long p; 18 | x = (x ^ (x >>> 1)); 19 | x = (x ^ (x >>> 2)) & 0x1111111111111111L; 20 | x = x*0x1111111111111111L; 21 | p = (x >> 60) & 1; 22 | 23 | return p; 24 | } 25 | 26 | /** Computes 'a' such that a*x = 1 for odd integers 'x' */ 27 | public static final long modInverse(long x) 28 | { 29 | // newton's 30 | long r = (x*x)+x - 1; 31 | long t = x*r; 32 | r *= 2-t; t = x*r; 33 | r *= 2-t; t = x*r; 34 | r *= 2-t; t = x*r; 35 | r *= 2-t; 36 | return r; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/roquen/math/rng/LCG32.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | /*** 4 | * Basic power-of-two 32-bit LCG. 5 | * References: 6 | *

  • "Tables of linear congruential generators of different sizes and good lattice structure", Pierre L'Ecuyer, 1999.
  • 7 | */ 8 | public final class LCG32 extends PRNG32 9 | { 10 | /** state data */ 11 | private int data; 12 | 13 | public LCG32() 14 | { 15 | setSeed((mix.getAndDecrement() ^ System.nanoTime())); 16 | } 17 | 18 | public LCG32(int seed) 19 | { 20 | setSeed(seed); 21 | } 22 | 23 | public LCG32(long seed) 24 | { 25 | setSeed(seed); 26 | } 27 | 28 | @Override 29 | public final void setSeed(long seed) 30 | { 31 | data = (int)seed; 32 | } 33 | 34 | @Override 35 | public final long getSeed() 36 | { 37 | return data; 38 | } 39 | 40 | @Override 41 | public final int nextInt() 42 | { 43 | data = 0xac549d55 * data + 0x61c88647; 44 | 45 | return data; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/roquen/math/rng/TestDist.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | /** 4 | * Some distributions intended for testing purposes. Most are not 5 | * even approaching an optimal implementation. 6 | */ 7 | public enum TestDist { 8 | ; 9 | 10 | /** 11 | * Returns a number with one bit set from 'mask' with 12 | * equal probability. 13 | */ 14 | public static int oneInMask(PRNG rng, int bits) 15 | { 16 | int len = Integer.bitCount(bits); 17 | @SuppressWarnings("unused") 18 | int val = rng.nextIntFast(len); 19 | 20 | 21 | return 0; 22 | } 23 | 24 | public static int oneInPot(PRNG rng, int pow) 25 | { 26 | return 1 << (rng.nextInt() >>> (32-pow)); 27 | } 28 | 29 | public static void main(String[] args) 30 | { 31 | XorStar64 rng = new XorStar64(); 32 | 33 | for(int i=0; i<32; i++) { 34 | int r = oneInPot(rng, 2); 35 | System.out.printf("%32s\n", Integer.toBinaryString(r)); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/roquen/math/seq/PermutedSequence.java: -------------------------------------------------------------------------------- 1 | package roquen.math.seq; 2 | 3 | /** 4 | * Computes permuted (random) integers on [0, n) visiting each element exactly once. 5 | *

    6 | * Implementation is a simple rejection method built on top of {@link #PermutedSequencePOT} 7 | */ 8 | public class PermutedSequence extends PermutedSequencePOT 9 | { 10 | private int length; 11 | 12 | public PermutedSequence(int length) { 13 | super(); 14 | setLength(length); 15 | } 16 | 17 | /** Sets the length of the sequence */ 18 | @Override 19 | public void setLength(int length) 20 | { 21 | int npow2 = roquen.math.Int32.ceilingLog2(length); 22 | 23 | this.length = length; 24 | 25 | super.setLength(npow2); 26 | } 27 | 28 | @Override 29 | public int nextInt() 30 | { 31 | int r; 32 | 33 | // This will loop (on average) no more than twice per call. 34 | do { 35 | r = super.nextInt(); 36 | if (r < length) 37 | return r; 38 | } while(true); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/roquen/util/FloatPair.java: -------------------------------------------------------------------------------- 1 | package roquen.util; 2 | 3 | public class FloatPair implements Comparable> 4 | { 5 | public T data; 6 | public float value; 7 | 8 | public FloatPair(T e, float v) 9 | { 10 | data = e; 11 | value = v; 12 | } 13 | 14 | @Override 15 | public int compareTo(FloatPair o) { 16 | float d = value - o.value; 17 | if (d < 0) return -1; 18 | if (d > 0) return 1; 19 | return 0; 20 | } 21 | 22 | public static void sort(java.util.List> list) 23 | { 24 | java.util.Collections.sort(list); 25 | } 26 | 27 | public static FloatPairArray flatten(java.util.List> list) 28 | { 29 | int len = list.size(); 30 | int i = 0; 31 | 32 | FloatPairArray r = new FloatPairArray<>(); 33 | r.t = Generics.newArray(len); 34 | r.f = new float[len]; 35 | 36 | for(FloatPair e : list) { 37 | r.t[i] = e.data; 38 | r.f[i] = e.value; 39 | i++; 40 | } 41 | 42 | return r; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/roquen/math/rng/XorStar64.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | /*** 4 | *

    5 | * Period: 264-1, 6 | *

    7 | * References: 8 | *

  • "Xorshift RNGs", George Marsaglia, 2003.
  • 9 | *
  • "Tables of linear congruential generators of different sizes and good lattice structure", Pierre L'Ecuyer, 1999.
  • 10 | *
  • "An experimental exploration of Marsaglia's xorshift generators, scrambled"
  • , 11 | * Sebastiano Vigna, 2014 12 | */ 13 | 14 | public final class XorStar64 extends PRNG64 15 | { 16 | private long data; 17 | 18 | public XorStar64() 19 | { 20 | setSeed((mix.getAndDecrement() ^ System.nanoTime())); 21 | } 22 | 23 | public XorStar64(long seed) 24 | { 25 | setSeed(seed); 26 | } 27 | 28 | @Override 29 | public final long nextLong() 30 | { 31 | data ^= (data >>> 12); 32 | data ^= (data << 25); 33 | data ^= (data >>> 27); 34 | return data * 2685821657736338717L; 35 | } 36 | 37 | @Override 38 | public void setSeed(long seed) { 39 | if (seed == 0) seed = Long.MIN_VALUE; 40 | data = seed; 41 | } 42 | 43 | @Override 44 | public long getSeed() { 45 | return data; 46 | } 47 | } -------------------------------------------------------------------------------- /src/roquen/pr0n/Deceiver.java: -------------------------------------------------------------------------------- 1 | package roquen.pr0n; 2 | 3 | /** 4 | * Template class for lying to the JVM about the type of an 5 | * array. Cannot be directly loaded, {@link Dissembler} must 6 | * loaded first. It works converting the casting check into 7 | * nops and loading the class via 8 | * {@link sun.misc.Unsafe#defineClass(String, byte[], int, int, ClassLoader, java.security.ProtectionDomain) Unsafe.defineClass} 9 | * to bypass the verifier. 10 | *

    11 | * Doing this is very dangerous since once the compiler sees 12 | * calling code it will be likely to notice that the references 13 | * to multiple views of the same array are alias and removable. 14 | * It will then be in untested cases of the backend compiler. 15 | */ 16 | 17 | // On HotSpot this could extend sun.reflect.MagicAccessorImpl 18 | // which is a backend class to avoid verification. 19 | @SuppressWarnings("restriction") 20 | public enum Deceiver 21 | { 22 | ; 23 | 24 | static { 25 | // Fail straight away if not loaded properly. 26 | ClassLoader loader = Deceiver.class.getClassLoader(); 27 | if (loader != null) 28 | throw new Error("Dissembler must be loaded by Deceiver"); 29 | } 30 | 31 | public static byte[] asB(Object obj) { return (byte[])obj; } 32 | public static int[] asI(Object obj) { return (int[])obj; } 33 | public static float[] asF(Object obj) { return (float[])obj; } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Unless otherwise stated all code falls into the public domain 3 | 4 | ----- 5 | 6 | This is free and unencumbered software released into the public domain. 7 | 8 | Anyone is free to copy, modify, publish, use, compile, sell, or 9 | distribute this software, either in source code form or as a compiled 10 | binary, for any purpose, commercial or non-commercial, and by any 11 | means. 12 | 13 | In jurisdictions that recognize copyright laws, the author or authors 14 | of this software dedicate any and all copyright interest in the 15 | software to the public domain. We make this dedication for the benefit 16 | of the public at large and to the detriment of our heirs and 17 | successors. We intend this dedication to be an overt act of 18 | relinquishment in perpetuity of all present and future rights to this 19 | software under copyright law. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | OTHER DEALINGS IN THE SOFTWARE. 28 | 29 | For more information, please refer to -------------------------------------------------------------------------------- /src/roquen/math/seq/PermutedSequencePOT.java: -------------------------------------------------------------------------------- 1 | package roquen.math.seq; 2 | 3 | 4 | // http://www.java-gaming.org/topics/iterate-each-element-of-a-collection-randomly-once-only/26646/msg/234580/view.html#msg234580 5 | 6 | /** 7 | * Computes permuted (random) integers on [0,2n) visiting each element exactly once. 8 | */ 9 | public class PermutedSequencePOT implements IntegerSequence 10 | { 11 | private static roquen.math.rng.XorShift32 rng = new roquen.math.rng.XorShift32(); 12 | 13 | private int m; 14 | private int a; 15 | private int mask; 16 | private int v; 17 | 18 | protected PermutedSequencePOT() {} 19 | 20 | public PermutedSequencePOT(int length) 21 | { 22 | setLength(length); 23 | } 24 | 25 | /** Set the length of the sequence. Must be a power-of-two. */ 26 | public void setLength(int length) 27 | { 28 | mask = length-1; 29 | reset(); 30 | 31 | assert((length & mask)==0); 32 | } 33 | 34 | /** Create a new permutation of the current length. */ 35 | public void reset() 36 | { 37 | // this is all overkill 38 | m = (rng.nextInt()<<3)|5; // anything such that (m & 7)==5 39 | a = (rng.nextInt()<<1)|1; // any odd value 40 | v = (rng.nextInt()); // basically sets the offset that zero will appear 41 | } 42 | 43 | 44 | /** Returns the next integer in the sequence. */ 45 | @Override 46 | public int nextInt() 47 | { 48 | v = (m*v + a) & mask; 49 | 50 | return v; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/roquen/math/lds/Sobol1D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.lds; 2 | 3 | /** 4 | * 5 | */ 6 | public final class Sobol1D extends LDS implements roquen.math.seq.FloatSequence 7 | { 8 | // state data 9 | private int i,d0; 10 | 11 | private final void updateState() 12 | { 13 | int c = Integer.numberOfTrailingZeros(~i); 14 | d0 ^= 0x80000000 >>> c; 15 | i += 1; 16 | } 17 | 18 | /** Return current index into the stream. */ 19 | public final int getPos() { return i; } 20 | 21 | /** Move 'num' positions forward or backward in the stream. */ 22 | public final void seek(int num) 23 | { 24 | int n = i + num; 25 | int a = i ^ (i >>> 1); 26 | int b = n ^ (n >>> 1); 27 | int d = a ^ b; 28 | 29 | int c = 0; 30 | 31 | while(d != 0) { 32 | if ((d & 1) != 0) { 33 | d0 ^= 0x80000000 >>> c; 34 | } 35 | d >>>= 1; 36 | c += 1; 37 | } 38 | 39 | i = n; 40 | } 41 | 42 | public Sobol1D() { seed((int)(mix.getAndDecrement() ^ System.nanoTime())); } 43 | 44 | public Sobol1D(int seed) 45 | { 46 | seed(seed); 47 | } 48 | 49 | /** Sets the seed and resets the stream. */ 50 | public final void seed(int s0) 51 | { 52 | d0 = s0; 53 | i = 0; 54 | } 55 | 56 | /** Returns the next value in the sequence. */ 57 | @Override 58 | public final float nextFloat() 59 | { 60 | float r = (d0 >>> 8) * 0x1p-24f; 61 | updateState(); 62 | return r; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/roquen/math/sfc/RowLinearIndex2D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.sfc; 2 | 3 | import roquen.fake.Vect2i; 4 | 5 | /** 6 | * Trivial indexing scheme for drop-in-replacement testing of apple-to-apples (almost) 7 | */ 8 | public final class RowLinearIndex2D extends Index2D 9 | { 10 | private final int D; 11 | 12 | public RowLinearIndex2D(int dim) 13 | { 14 | D = dim; 15 | } 16 | 17 | @Override 18 | public final void set(Vect2i v) 19 | { 20 | sx = v.x; sy = v.y; 21 | } 22 | 23 | @Override 24 | public void set(RowLinearIndex2D v) 25 | { 26 | sx = v.sx; 27 | sy = v.sy; 28 | } 29 | 30 | @Override 31 | public final void get(Vect2i v) 32 | { 33 | v.x = sx; 34 | v.y = sy; 35 | } 36 | 37 | @Override public final void setX(int x) { sx = x; } 38 | @Override public final void setY(int y) { sy = y; } 39 | @Override public final int getX() { return sx; } 40 | @Override public final int getY() { return sy; } 41 | @Override public final void incY() { sy += 1; } 42 | @Override public final void decY() { sy -= 1; } 43 | @Override public final void incX() { sx += 1; } 44 | @Override public final void decX() { sx -= 1; } 45 | 46 | @Override 47 | public void add(RowLinearIndex2D v) 48 | { 49 | sx += v.sx; 50 | sy += v.sy; 51 | } 52 | 53 | @Override 54 | public void sub(RowLinearIndex2D v) 55 | { 56 | sx -= v.sx; 57 | sy -= v.sy; 58 | } 59 | 60 | @Override 61 | public int getIndex() { 62 | return D*sy+sx; 63 | } 64 | 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/roquen/math/rng/XorWow64.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | 4 | /*** 5 | * 64-bit XorShift generator combined with a Weyl. 6 | *

    7 | * Period: 2128-264 ~= 2128 8 | *

    9 | * This generator requires 128 bits of state data. So one 10 | * cannot retrieve and restore complete state via {@link #getSeed()}. 11 | * The second half of the state needs to be retrieved via {@link #getSeed2()} 12 | * and use {@link #setSeed(long, long)} to reset the stream to a given 13 | * position. 14 | */ 15 | public final class XorWow64 extends PRNG64 16 | { 17 | private long data; 18 | private long weyl; 19 | 20 | /** Same constant as XorWow32, just scaled to 64-bits */ 21 | private static final long WEYL = 0x61C8864680b583EBL; 22 | 23 | public XorWow64() 24 | { 25 | setSeed(mix.getAndDecrement(), System.nanoTime()); 26 | } 27 | 28 | public XorWow64(long data1, long data2) 29 | { 30 | setSeed(data1, data2); 31 | } 32 | 33 | @Override 34 | public final long nextLong() 35 | { 36 | data ^= (data << 13); 37 | data ^= (data >>> 7); 38 | data ^= (data << 17); 39 | weyl += WEYL; 40 | 41 | // NOTE: other mixes are possible. See XorWow32. 42 | return data + weyl; 43 | } 44 | 45 | @Override 46 | public final void setSeed(long seed) 47 | { 48 | data = seed | 1; 49 | weyl = 0x5db3d743 ^ (seed & 1); 50 | } 51 | 52 | public final void setSeed(long data1, long data2) 53 | { 54 | if (data1 == 0) data1 = WEYL; 55 | data = data1; 56 | weyl = data2; 57 | } 58 | 59 | @Override 60 | public final long getSeed() { 61 | return data; 62 | } 63 | 64 | public final long getSeed2() { return weyl; } 65 | } -------------------------------------------------------------------------------- /src/roquen/interp/RayGrid3D.java: -------------------------------------------------------------------------------- 1 | package roquen.interp; 2 | 3 | import roquen.fake.Vect3f; 4 | 5 | /** 6 | * For performing in-order walks of cells on a uniform 3D grid which 7 | * are crossed by a line segment or ray. For more details see {@link RayGrid2D} 8 | */ 9 | public class RayGrid3D { 10 | private double cx,cy,cz; 11 | private double ax,ay,az; 12 | private int ux,uy,uz; 13 | 14 | /** Current cell coordinate */ 15 | public int x,y,z; 16 | 17 | public void set(Vect3f p0, Vect3f p1) 18 | { 19 | // the coordinate of the first cell 20 | x = (int)Math.floor(p0.x); 21 | y = (int)Math.floor(p0.y); 22 | z = (int)Math.floor(p0.y); 23 | 24 | // direction of the ray 25 | double dx = p1.x-p0.x; 26 | double dy = p1.y-p0.y; 27 | double dz = p1.z-p0.z; 28 | 29 | // amount to move in each direction to cross a 30 | // cell boundary. 31 | cx = 1/dx; 32 | cy = 1/dy; 33 | cz = 1/dz; 34 | 35 | // cross time accumulators. Initialized to 36 | // the first cross time. 37 | ax = cx * (1.0-(p0.x-x)); 38 | ay = cy * (1.0-(p0.y-y)); 39 | az = cz * (1.0-(p0.z-z)); 40 | 41 | // step amounts for each direction 42 | ux = dx >= 0 ? 1 : -1; 43 | uy = dy >= 0 ? 1 : -1; 44 | uz = dz >= 0 ? 1 : -1; 45 | } 46 | 47 | public void update() 48 | { 49 | // the next cell is the one with the smallest 50 | // crossing time. 51 | if (ax < ay) { 52 | if (ax < az) { 53 | ax += cx; 54 | x += ux; 55 | } 56 | } else if (ax < az) { 57 | ay += cy; 58 | y += uy; 59 | return; 60 | } 61 | az += cz; 62 | z += uz; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/roquen/math/rng/XorStar32.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | // Implementation notes: 4 | // SmallCrush failures starting with seeds of popcount=1 5 | // (L13,R17,L5, {741103597,1597334677}): 6 | // 1 BirthdaySpacings 7 | // XorWow is performing better on tests. 8 | /*** 9 | * This needs testing. Both base XorShift choice and multiplier. 10 | * Currently of no interest. XorWow32 has same dep-chain length 11 | * and performs better at testing. 12 | * 13 | *

    14 | * Period: 232-1, 15 | *

    16 | * References: 17 | *

  • "Xorshift RNGs", George Marsaglia, 2003.
  • 18 | *
  • "Tables of linear congruential generators of different sizes and good lattice structure", Pierre L'Ecuyer, 1999.
  • 19 | *
  • "An experimental exploration of Marsaglia's xorshift generators, scrambled"
  • , 20 | * Sebastiano Vigna, 2014 21 | */ 22 | public final class XorStar32 extends PRNG32 23 | { 24 | /** state data of xorshift */ 25 | private int data; 26 | 27 | public XorStar32() 28 | { 29 | setSeed((mix.getAndDecrement() ^ System.nanoTime())); 30 | } 31 | 32 | public XorStar32(int seed) 33 | { 34 | setSeed(seed); 35 | } 36 | 37 | public XorStar32(long seed) 38 | { 39 | setSeed(seed); 40 | } 41 | 42 | @Override 43 | public final void setSeed(long seed) 44 | { 45 | int lo = (int)(seed); 46 | 47 | // xorshift state must never be zero. 48 | if (lo==0) lo = 0x92d68ca2; 49 | 50 | data = lo; 51 | } 52 | 53 | @Override 54 | public final long getSeed() 55 | { 56 | return data; 57 | } 58 | 59 | @Override 60 | public final int nextInt() 61 | { 62 | data ^= (data << 13); 63 | data ^= (data >>> 17); 64 | data ^= (data << 15); 65 | return data * 1597334677; 66 | //return data * 741103597; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/roquen/math/sfc/Index2D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.sfc; 2 | 3 | import roquen.fake.Vect2i; 4 | 5 | /** 6 | * Base class of maintaining a 2-to-1 representation of a 2D coordinate. 7 | */ 8 | public abstract class Index2D> 9 | { 10 | /** Scattered version of x. Publicly visible for copy/storage/restoring. */ 11 | public int sx; 12 | 13 | /** Scattered version of y. Publicly visible for copy/storage/restoring. */ 14 | public int sy; 15 | 16 | /** Returns the current index */ 17 | public abstract int getIndex(); 18 | 19 | /** Copies the represented coordinate 'v' into this. */ 20 | public abstract void set(T v); 21 | 22 | /** Set the represented 2D coordinate */ 23 | public abstract void set(Vect2i v); 24 | 25 | /** Sets the represented X coordinate */ 26 | public abstract void setX(int x); 27 | 28 | /** Sets the represented X coordinate */ 29 | public abstract void setY(int y); 30 | 31 | public void set(int x, int y) 32 | { 33 | setX(x); setY(y); 34 | } 35 | 36 | /** Fill 'v' with the represented 2D coordinate */ 37 | public abstract void get(Vect2i v); 38 | 39 | /** Gets the represented X coordinate */ 40 | public abstract int getX(); 41 | 42 | /** Gets the represented Y coordinate */ 43 | public abstract int getY(); 44 | 45 | /** Increment the represented X coordinate: (x, y) -> (x+1, y) */ 46 | public abstract void incX(); 47 | 48 | /** Decrement the represented X coordinate: (x, y) -> (x+1, y) */ 49 | public abstract void decX(); 50 | 51 | /** Increment the represented Y coordinate: (x, y) -> (x, y+1) */ 52 | public abstract void incY(); 53 | 54 | /** Decrement the represented Y coordinate: (x, y) -> (x, y+1) */ 55 | public abstract void decY(); 56 | 57 | /** */ 58 | public abstract void add(T v); 59 | 60 | /** */ 61 | public abstract void sub(T v); 62 | } 63 | -------------------------------------------------------------------------------- /src/roquen/math/rng/XorWow32.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | // Implementation notes: 4 | // Passes SmallCrush 5 | 6 | /*** 7 | * 32-bit XorShift generator combined with a Weyl. 8 | *

    9 | * Period: 264-232 ~= 264 10 | */ 11 | public final class XorWow32 extends PRNG32 12 | { 13 | /** state data of xorshift */ 14 | private int data; 15 | 16 | /** state data of Weyl */ 17 | private int weyl; 18 | 19 | /** 20 | * Weyl increment. This value must be odd, but some 21 | * choices are much better than others. 22 | * The choice here is from Richard Brent (see paper) 23 | *

    24 | * 231(3-sqrt(5)) = 0x61c88647 25 | */ 26 | private static final int WEYL = 0x61c88647; 27 | 28 | public XorWow32() 29 | { 30 | setSeed((mix.getAndDecrement() ^ System.nanoTime())); 31 | } 32 | 33 | public XorWow32(int seed) 34 | { 35 | setSeed(seed); 36 | } 37 | 38 | public XorWow32(long seed) 39 | { 40 | setSeed(seed); 41 | } 42 | 43 | @Override 44 | public final void setSeed(long seed) 45 | { 46 | int lo = (int)(seed); 47 | 48 | // xorshift state must never be zero. 49 | if (lo==0) lo = 0x92d68ca2; 50 | 51 | data = lo; 52 | 53 | int hi = (int)(seed >>> 32); 54 | 55 | data = lo; 56 | weyl = hi|1; // must be odd 57 | } 58 | 59 | 60 | @Override 61 | public final long getSeed() 62 | { 63 | long r = data; 64 | 65 | r |= weyl << 32; 66 | 67 | return r; 68 | } 69 | 70 | @Override 71 | public final int nextInt() 72 | { 73 | data ^= (data << 13); 74 | data ^= (data >>> 17); 75 | data ^= (data << 15); 76 | weyl += WEYL; 77 | 78 | // NOTE: Other mixes are possible, such as an xor 79 | // instead of addition. Some authors would suggest 80 | // replacing 'OP weyl' with 'OP (weyl ^ (weyl>>>16))'. 81 | return data + weyl; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/roquen/math/lds/SobolFixed2D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.lds; 2 | 3 | /** 4 | * Sobol sequence generator in 2D for a predefined length. 5 | */ 6 | public final class SobolFixed2D extends LDS 7 | { 8 | // state data 9 | private int i,d0; 10 | 11 | private float rlength; 12 | 13 | private final void updateState() 14 | { 15 | d0 ^= 0x80000000 >>> Integer.numberOfTrailingZeros(~i); 16 | i += 1; 17 | } 18 | 19 | /** Set the needed length of the sequence */ 20 | public final void setLength(int length) 21 | { 22 | rlength = 1.f/length; 23 | } 24 | 25 | /** Return current index into the stream. */ 26 | public final int getPos() { return i; } 27 | 28 | public SobolFixed2D(int length) 29 | { 30 | setLength(length); 31 | } 32 | 33 | /** Sets seed value for the second dimension and resets the stream. */ 34 | public final void seed(int s0) 35 | { 36 | d0 = s0; 37 | i = 0; 38 | } 39 | 40 | public final void next(roquen.fake.Vect2f v) 41 | { 42 | v.x = i * rlength; 43 | v.y = (d0 >>> 8) * 0x1p-24f; 44 | } 45 | 46 | /** Sets the two elements of 'v' starting of 'off' to the next value. */ 47 | public final void next(float[] v, int off) 48 | { 49 | v[off++] = i * rlength; 50 | v[off++] = (d0 >>> 8) * 0x1p-24f; 51 | updateState(); 52 | } 53 | 54 | /** Sets the first two elements of 'v' to the next value. */ 55 | public final void next(float[] v) { next(v, 0); } 56 | 57 | /** Puts the next value (two elements) into 'fb'. */ 58 | public final void next(java.nio.FloatBuffer fb) 59 | { 60 | fb.put(i * rlength); 61 | fb.put((d0 >>> 8) * 0x1p-24f); 62 | updateState(); 63 | } 64 | 65 | /** Puts the next value (two elements) into 'fb' at the specified offset. */ 66 | public final void next(java.nio.FloatBuffer fb, int off) 67 | { 68 | fb.put(off++, i * rlength); 69 | fb.put(off, (d0 >>> 8) * 0x1p-24f); 70 | updateState(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/roquen/math/Trig64.java: -------------------------------------------------------------------------------- 1 | package roquen.math; 2 | 3 | /** 4 | * 5 | */ 6 | public enum Trig64 7 | { 8 | ; 9 | 10 | // SEE: the same Trig32 implementation for potentially more information 11 | 12 | /** 13 | * Reduces input angle on [0, 2pi] to equivalent value on [-pi,pi]. 14 | *

    15 | * The reduction is exact. 16 | */ 17 | public static final double reduceTwoPi(double a) 18 | { 19 | if (a <= Math.PI) return a; 20 | return 2*Math.PI - a; 21 | } 22 | 23 | 24 | /** 25 | * Returns sin(a) given cos(a) and a on [-pi,pi]. 26 | *

    27 | * computed as: sign(sa) sqrt(1-cos2) 28 | */ 29 | public static final double sinPmPi(double cos, double sa) 30 | { 31 | long sx = (Double.doubleToRawLongBits(sa) >>> 63) << 63; 32 | double r = Math.sqrt(1.0-cos*cos); 33 | long ir = Double.doubleToRawLongBits(r) ^ sx; 34 | return Double.longBitsToDouble(ir); 35 | } 36 | 37 | /** 38 | * Returns sin(a) given cos(a) and a on [-pi,pi]. 39 | *

    40 | * computed as: sign(sa) sqrt((1-cos)(1+cos)) 41 | *

    42 | * Result is within 1-ulp of correct 43 | */ 44 | public static final double sinPmPiHq(double cos, double sa) 45 | { 46 | long sx = (Double.doubleToRawLongBits(sa) >>> 63) << 63; 47 | double r = Math.sqrt((1.0-cos)*(1.0+cos)); 48 | long ir = Double.doubleToRawLongBits(r) ^ sx; 49 | return Double.longBitsToDouble(ir); 50 | } 51 | 52 | /** 53 | * Returns sin(a) given cos(a) and a on [0,pi]. 54 | *

    55 | * computed as: sqrt(1-cos2) 56 | * @see {@link #sinPiHq(double)} 57 | */ 58 | public static final double sinPi(double cos) 59 | { 60 | return Math.sqrt(1.0-cos*cos); 61 | } 62 | 63 | /** 64 | * Returns sin(a) given cos(a) and a on [0,pi]. 65 | *

    66 | * computed as: sqrt((1-cos)(1+cos)) 67 | *

    68 | * Result is within 1-ulp of correct and has 69 | * the same dependency chain length as {@link #sinPi(double)} 70 | */ 71 | public static final double sinPiHq(double cos) 72 | { 73 | return Math.sqrt((1.0-cos)*(1.0+cos)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/roquen/vm/VMQuery.java: -------------------------------------------------------------------------------- 1 | package roquen.vm; 2 | 3 | import java.io.*; 4 | import java.lang.management.*; 5 | 6 | import com.sun.management.*; 7 | 8 | // tossed together for some testing...might be useful in the future. 9 | public enum VMQuery 10 | { 11 | ; 12 | private static final HotSpotDiagnosticMXBean bean; 13 | 14 | private static VMOption none = new VMOption("none", "null", false, VMOption.Origin.DEFAULT); 15 | 16 | static { 17 | HotSpotDiagnosticMXBean r = null; 18 | 19 | try { 20 | r = ManagementFactory.newPlatformMXBeanProxy( 21 | ManagementFactory.getPlatformMBeanServer(), 22 | "com.sun.management:type=HotSpotDiagnostic", 23 | HotSpotDiagnosticMXBean.class); 24 | } catch (IOException e) { 25 | 26 | e.printStackTrace(); 27 | } 28 | bean = r; 29 | } 30 | 31 | public static VMOption getOption(String name) 32 | { 33 | try { 34 | return bean.getVMOption(name); 35 | } 36 | catch(Throwable t) { /* */ } 37 | 38 | return none; 39 | } 40 | 41 | public static boolean getBooleanOption(String name) 42 | { 43 | return Boolean.parseBoolean(getOption(name).getValue()); 44 | } 45 | 46 | public static int getIntOption(String name) 47 | { 48 | return Integer.parseInt(getOption(name).getValue()); 49 | } 50 | 51 | public static String getStringOption(String name) 52 | { 53 | return getOption(name).getValue(); 54 | } 55 | 56 | public static boolean isCompressedOops() 57 | { 58 | return getBooleanOption("UseCompressedOops"); 59 | } 60 | 61 | public static boolean isCompressedClassPointer() 62 | { 63 | return getBooleanOption("UseCompressedClassPointers"); 64 | } 65 | 66 | //------------ 67 | public static void dumpAll() 68 | { 69 | javax.management.MBeanServer server = ManagementFactory.getPlatformMBeanServer(); 70 | java.util.Set list = server.queryMBeans(null, null); 71 | 72 | for(javax.management.ObjectInstance oi : list) { 73 | System.out.println("class: " + oi.getClassName()); 74 | System.out.println("object: " + oi.getObjectName()); 75 | } 76 | } 77 | 78 | 79 | public static void main(String[] args) 80 | { 81 | dumpAll(); 82 | //System.out.println(getOption("PrintC")); 83 | System.out.println(getOption("PrintCompilation2")); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/roquen/interp/IndexedRayGrid2D.java: -------------------------------------------------------------------------------- 1 | package roquen.interp; 2 | 3 | import roquen.fake.Vect2f; 4 | import roquen.math.sfc.*; 5 | 6 | /** 7 | * An example abstraction for testing if using alternate indexing is a win. 8 | */ 9 | 10 | public class IndexedRayGrid2D // could extends WhatEver once an indexing scheme is choice 11 | { 12 | private double cx,cy; 13 | private double ax,ay; 14 | private boolean ux,uy; 15 | 16 | // TODO: go away in production if this was used 17 | private final Index2D map; 18 | 19 | // TODO: go away in production if this was used 20 | public IndexedRayGrid2D(Index2D map) 21 | { 22 | this.map = map; 23 | } 24 | 25 | public int set(float x0, float y0, float x1, float y1) 26 | { 27 | // the coordinate of the first cell 28 | // TODO: change to floor if for some reason you want negative coordinates 29 | int x = (int)x0; //(int)Math.floor(p0.x); 30 | int y = (int)y0; //(int)Math.floor(p0.y); 31 | 32 | map.setX(x); 33 | map.setY(y); 34 | 35 | // direction of the ray 36 | double dx = x1-x0; 37 | double dy = y1-y0; 38 | 39 | // amount to move in each direction to cross a 40 | // cell boundary. 41 | cx = 1/dx; 42 | cy = 1/dy; 43 | 44 | // cross time accumulators. Initialized to 45 | // the first cross time. 46 | ax = cx * (1.0-(x0-x)); 47 | ay = cy * (1.0-(y0-y)); 48 | 49 | // movement directions 50 | ux = dx >= 0; 51 | uy = dy >= 0; 52 | 53 | // TODO: temp hack 54 | int ex = (int)x1; 55 | int ey = (int)y1; 56 | int nx = Math.abs(ex-x); 57 | int ny = Math.abs(ey-y); 58 | int n; 59 | 60 | // todo: compute number of off major axis steps 61 | if (nx > ny) { 62 | n = nx; 63 | } else { 64 | n = ny; 65 | } 66 | 67 | return n; 68 | } 69 | 70 | public int set(Vect2f p0, Vect2f p1) 71 | { 72 | return set(p0.x,p0.y,p1.x,p1.y); 73 | } 74 | 75 | public void update() 76 | { 77 | // the next cell is the one with the smallest 78 | // crossing time. 79 | if (ax < ay) { 80 | ax += cx; 81 | if (ux) map.incX(); else map.decX(); 82 | } else { 83 | ay += cy; 84 | if (uy) map.incY(); else map.decY(); 85 | } 86 | } 87 | 88 | public int getIndex() 89 | { 90 | return map.getIndex(); 91 | } 92 | 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/roquen/interp/RayGrid2D.java: -------------------------------------------------------------------------------- 1 | package roquen.interp; 2 | 3 | import roquen.fake.Vect2f; 4 | 5 | /** 6 | * For performing in-order walks of cells on a uniform 2D grid which 7 | * are crossed by a line segment or ray. All covered cells are visited 8 | * however it does not provide supercoverage. Supercoverage is when 9 | * all four cells are visited in the case where the ray passes through 10 | * a corner. For a corner case this will visit three out of four. At 11 | * each step the next cell will be either a horizontal or vertical move 12 | * so in the extreme pathological case this will visit "false positive" 13 | * cells, the worst case situation begin a 45 degree angle ray 14 | * perfectly through corners where half the visited cells will be 15 | * "false positives". These false positives only occur when hitting 16 | * a corner so is of no concern unless the use-case is something like 17 | * rayshooting from the center of a cell in only horizontal, vertical or 18 | * diagonal directions which isn't the intended usage. 19 | *

    20 | * Passed in values make the assumption that the extent of cells are 21 | * of one unit. User code scaling is required for other sizes. 22 | */ 23 | public class RayGrid2D 24 | { 25 | private double cx,cy; 26 | private double ax,ay; 27 | private int ux,uy; 28 | 29 | /** Current cell coordinate */ 30 | public int x,y; 31 | 32 | public void set(Vect2f p0, Vect2f p1) 33 | { 34 | // the coordinate of the first cell 35 | // TODO: change to floor if for some reason you want negative coordinates 36 | x = (int)p0.x; //(int)Math.floor(p0.x); 37 | y = (int)p0.y; //(int)Math.floor(p0.y); 38 | 39 | // direction of the ray 40 | double dx = p1.x-p0.x; 41 | double dy = p1.y-p0.y; 42 | 43 | // amount to move in each direction to cross a 44 | // cell boundary. 45 | cx = 1/dx; 46 | cy = 1/dy; 47 | 48 | // cross time accumulators. Initialized to 49 | // the first cross time. 50 | ax = cx * (1.0-(p0.x-x)); 51 | ay = cy * (1.0-(p0.y-y)); 52 | 53 | // step amounts for each direction 54 | ux = dx >= 0 ? 1 : -1; 55 | uy = dy >= 0 ? 1 : -1; 56 | } 57 | 58 | public void update() 59 | { 60 | // the next cell is the one with the smallest 61 | // crossing time. 62 | if (ax < ay) { 63 | ax += cx; 64 | x += ux; 65 | } else { 66 | ay += cy; 67 | y += uy; 68 | } 69 | } 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/roquen/math/lds/SobolFixed3D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.lds; 2 | 3 | /** 4 | * Sobol sequence generator in 3D for a predefined length. 5 | */ 6 | public final class SobolFixed3D extends LDS 7 | { 8 | // state data 9 | private int i,d0,d1; 10 | 11 | // direction table 12 | private static final int[] D; 13 | 14 | private float rlength; 15 | 16 | static { 17 | D = new int[33]; 18 | 19 | int c = D[0] = 1 << 31; 20 | 21 | for(int i=1; i<32; i++) { 22 | c = c ^ (c >>> 1); 23 | D[i] = c; 24 | } 25 | 26 | // TODO: what about -1? index 32 27 | } 28 | 29 | private final void updateState() 30 | { 31 | int c = Integer.numberOfTrailingZeros(~i); 32 | d1 ^= D[c]; 33 | d0 ^= 0x80000000 >>> c; 34 | i += 1; 35 | } 36 | 37 | /** Return current index into the stream. */ 38 | public final int getPos() { return i; } 39 | 40 | /** Set the needed length of the sequence */ 41 | public final void setLength(int length) 42 | { 43 | rlength = 1.f/length; 44 | } 45 | 46 | public SobolFixed3D(int length) 47 | { 48 | setLength(length); 49 | } 50 | 51 | /** Sets seed values for the second and third dimensions and resets the stream. */ 52 | public final void seed(int s0, int s1) 53 | { 54 | d0 = s0; 55 | d1 = s1; 56 | i = 0; 57 | } 58 | 59 | public final void next(roquen.fake.Vect3f v) 60 | { 61 | v.x = i * rlength; 62 | v.y = (d0 >>> 8) * 0x1p-24f; 63 | v.z = (d1 >>> 8) * 0x1p-24f; 64 | } 65 | 66 | /** Sets the three elements of 'v' starting of 'off' to the next value. */ 67 | public final void next(float[] v, int off) 68 | { 69 | v[off++] = i * rlength; 70 | v[off++] = (d0 >>> 8) * 0x1p-24f; 71 | v[off++] = (d1 >>> 8) * 0x1p-24f; 72 | updateState(); 73 | } 74 | 75 | /** Sets the first three elements of 'v' to the next value. */ 76 | public final void next(float[] v) { next(v, 0); } 77 | 78 | /** Puts the next value (two elements) into 'fb'. */ 79 | public final void next(java.nio.FloatBuffer fb) 80 | { 81 | fb.put(i * rlength); 82 | fb.put((d0 >>> 8) * 0x1p-24f); 83 | fb.put((d1 >>> 8) * 0x1p-24f); 84 | updateState(); 85 | } 86 | 87 | /** Puts the next value (two elements) into 'fb' at the specified offset. */ 88 | public final void next(java.nio.FloatBuffer fb, int off) 89 | { 90 | fb.put(off++, i * rlength); 91 | fb.put(off++, (d0 >>> 8) * 0x1p-24f); 92 | fb.put(off, (d1 >>> 8) * 0x1p-24f); 93 | updateState(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/roquen/math/sfc/Morton3D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.sfc; 2 | 3 | import roquen.fake.Vect3i; 4 | 5 | /** 6 | * Static utilities for 3-to-1 mappings based on Morton/Z-Order/Lebesgue curve. 7 | */ 8 | public enum Morton3D { 9 | ; 10 | 11 | public static int encode5(Vect3i v) 12 | { 13 | return encode5(v.x,v.y,v.z); 14 | } 15 | 16 | public static int encode5(int x, int y, int z) 17 | { 18 | //x &= 0x0000001f; y &= 0x0000001f; z &= 0x0000001f; 19 | x *= 0x01041041; y *= 0x01041041; z *= 0x01041041; 20 | x &= 0x10204081; y &= 0x10204081; z &= 0x10204081; 21 | x *= 0x00011111; y *= 0x00011111; z *= 0x00011111; 22 | x &= 0x12490000; y &= 0x12490000; z &= 0x12490000; 23 | return((x >>> 16) | (y >>> 15) | (z >>> 14)); 24 | } 25 | 26 | public static void decode5(Vect3i v, int code) 27 | { 28 | int x = code; 29 | int y = code >>> 1; 30 | int z = code >>> 2; 31 | x &= 0x00001249; y &= 0x00001249; z &= 0x00001249; 32 | x |= (x >>> 2); y |= (y >>> 2); z |= (z >>> 2); 33 | x &= 0x000010c3; y &= 0x000010c3; z &= 0x000010c3; 34 | x |= (x >>> 4); y |= (y >>> 4); z |= (z >>> 4); 35 | x &= 0x0000100f; y &= 0x0000100f; z &= 0x0000100f; 36 | x |= (x >>> 8); y |= (y >>> 8); z |= (z >>> 8); 37 | x &= 0x0000001f; y &= 0x0000001f; z &= 0x0000001f; 38 | v.x = x; 39 | v.y = y; 40 | v.z = z; 41 | } 42 | 43 | public static int encode10(Vect3i v) 44 | { 45 | return encode10(v.x,v.y,v.z); 46 | } 47 | 48 | public static int encode10(int x, int y, int z) 49 | { 50 | //x &= 0x000003ff; y &= 0x000003ff; z &= 0x000003ff; 51 | x |= (x << 16); y |= (y << 16); z |= (z << 16); 52 | x &= 0x030000ff; y &= 0x030000ff; z &= 0x030000ff; 53 | x |= (x << 8); y |= (y << 8); z |= (z << 8); 54 | x &= 0x0300f00f; y &= 0x0300f00f; z &= 0x0300f00f; 55 | x |= (x << 4); y |= (y << 4); z |= (z << 4); 56 | x &= 0x030c30c3; y &= 0x030c30c3; z &= 0x030c30c3; 57 | x |= (x << 2); y |= (y << 2); z |= (z << 2); 58 | x &= 0x09249249; y &= 0x09249249; z &= 0x09249249; 59 | return(x | (y << 1) | (z << 2)); 60 | } 61 | 62 | public static void decode10(Vect3i v, int code) 63 | { 64 | int x = code; 65 | int y = code >>> 1; 66 | int z = code >>> 2; 67 | x &= 0x09249249; y &= 0x09249249; z &= 0x09249249; 68 | x |= (x >>> 2); y |= (y >>> 2); z |= (z >>> 2); 69 | x &= 0x030c30c3; y &= 0x030c30c3; z &= 0x030c30c3; 70 | x |= (x >>> 4); y |= (y >>> 4); z |= (z >>> 4); 71 | x &= 0x0300f00f; y &= 0x0300f00f; z &= 0x0300f00f; 72 | x |= (x >>> 8); y |= (y >>> 8); z |= (z >>> 8); 73 | x &= 0x030000ff; y &= 0x030000ff; z &= 0x030000ff; 74 | x |= (x >>> 16); y |= (y >>> 16); z |= (z >>> 16); 75 | x &= 0x000003ff; y &= 0x000003ff; z &= 0x000003ff; 76 | v.x = x; 77 | v.y = y; 78 | v.z = z; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/roquen/pg/noise/ValueNoise.java: -------------------------------------------------------------------------------- 1 | package roquen.pg.noise; 2 | 3 | public final class ValueNoise extends Noise 4 | { 5 | 6 | private static final float mix(int x) 7 | { 8 | int h = hashM2(x); 9 | 10 | return normalizeI(h); 11 | } 12 | 13 | /** Sample 1D function */ 14 | public static final float eval(float x) 15 | { 16 | int ix = pseudoFloor(x); 17 | float dx = ease(x-ix); 18 | float r0 = mix(ix); 19 | float r1 = mix(ix+1); 20 | 21 | return lerp(dx, r0, r1); 22 | } 23 | 24 | private static final float mix(int x, int y) 25 | { 26 | return normalizeI(hashM2(x,y)); 27 | } 28 | 29 | /** Sample 2D function */ 30 | public static final float eval(float x, float y) 31 | { 32 | // get the coordinate of the cell 33 | int ix = pseudoFloor(x); 34 | int iy = pseudoFloor(y); 35 | 36 | // compute the offset into the cell, then weight it 37 | x = ease(x-ix); 38 | y = ease(y-iy); 39 | 40 | // compute hash values for the four vertices of the cell and 41 | // convert into a uniform float 42 | float r00 = mix(ix, iy); 43 | float r10 = mix(ix+1, iy); 44 | float r01 = mix(ix, iy+1); 45 | float r11 = mix(ix+1, iy+1); 46 | 47 | float xb = lerp(x, r00, r10); // lerp bottom edge 48 | float xt = lerp(x, r01, r11); // lerp top edge 49 | 50 | return lerp(y, xb, xt); // lerp the two edges into the final result 51 | } 52 | 53 | private static final float mix(int x, int y, int z) 54 | { 55 | int h = hashM2(x,y,z); 56 | 57 | return normalizeI(h); 58 | } 59 | 60 | /** Sample 3D function */ 61 | public static final float eval(float x, float y, float z) 62 | { 63 | float t0,t1,t2,t3,t4; 64 | 65 | // lower left hand coordinate of cell 66 | int ix = pseudoFloor(x); 67 | int iy = pseudoFloor(y); 68 | int iz = pseudoFloor(z); 69 | 70 | // offset into cell, then convert to weighting value 71 | x = ease(x-ix); 72 | y = ease(y-iy); 73 | z = ease(z-iz); 74 | 75 | // bottom edge of forward face 76 | t0 = mix(ix, iy, iz); 77 | t1 = mix(ix+1, iy, iz); 78 | t2 = lerp(x, t0, t1); 79 | 80 | // top edge of forward face 81 | t0 = mix(ix, iy+1, iz); 82 | t1 = mix(ix+1, iy+1, iz); 83 | t3 = lerp(x, t0, t1); 84 | t3 = lerp(y, t2, t3); // final result in forward face 85 | 86 | // bottom edge of back face 87 | t0 = mix(ix, iy, iz+1); 88 | t1 = mix(ix+1, iy, iz+1); 89 | t2 = lerp(x, t0, t1); 90 | 91 | // top edge of back face 92 | t0 = mix(ix, iy+1, iz+1); 93 | t1 = mix(ix+1, iy+1, iz+1); 94 | t4 = lerp(x, t0, t1); 95 | t4 = lerp(y, t2, t4); 96 | 97 | return lerp(z, t3, t4); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/roquen/math/sfc/Morton2DBase.java: -------------------------------------------------------------------------------- 1 | package roquen.math.sfc; 2 | 3 | import static roquen.math.sfc.Morton2D.*; 4 | import roquen.fake.Vect2i; 5 | 6 | /** implements manipulations of scattered coordinates */ 7 | abstract class Morton2DBase> extends Index2D 8 | { 9 | // probably would make sense to modify to prefer faster updates than 10 | // get operations. scattered x,y in same bit positions and do the 11 | // shift for combine in get. 12 | 13 | @Override 14 | public void set(T v) 15 | { 16 | sx = v.sx; 17 | sy = v.sy; 18 | } 19 | 20 | @Override 21 | public final void set(Vect2i v) 22 | { 23 | //sx = (int)((v.x * 0x0101010101010101L & 0x8040201008040201L) * 0x0102040810204081L >>> 49) & 0x5555; 24 | //sy = (int)((v.y * 0x0101010101010101L & 0x8040201008040201L) * 0x0102040810204081L >>> 48) & 0xAAAA; 25 | 26 | setX(v.x); 27 | setY(v.y); 28 | } 29 | 30 | @Override 31 | public final void setX(int x) 32 | { 33 | //sx = (int)((x * 0x0101010101010101L & 0x8040201008040201L) * 0x0102040810204081L >>> 49) & 0x5555; 34 | sx = scatter1(x); 35 | } 36 | 37 | @Override 38 | public final void setY(int y) 39 | { 40 | //sy = (int)((y * 0x0101010101010101L & 0x8040201008040201L) * 0x0102040810204081L >>> 48) & 0xAAAA; 41 | sy = scatter1(y) << 1; 42 | } 43 | 44 | @Override 45 | public final void get(Vect2i v) 46 | { 47 | v.x = gather1_(sx); 48 | v.y = gather1_(sy>>>1); 49 | } 50 | 51 | @Override 52 | public final int getX() 53 | { 54 | return gather1_(sx); 55 | } 56 | 57 | @Override 58 | public final int getY() 59 | { 60 | return gather1_(sy>>>1); 61 | } 62 | 63 | 64 | @Override 65 | public void incY() 66 | { 67 | sy +=MASK_X+2; sy &= MASK_Y; 68 | //int mx = Morton2D.MASK_X; 69 | //int my = mx+mx; 70 | //sy |= mx; sy += 2; sy &= my; 71 | } 72 | 73 | @Override 74 | public void decY() 75 | { 76 | sy -= 2; sy &= Morton2D.MASK_Y; 77 | } 78 | 79 | protected final int INC_X = MASK_Y+1; 80 | 81 | @Override 82 | public void incX() 83 | { 84 | //sx |= MASK_Y; sx += 1; sx &= MASK_X; 85 | int a = INC_X; 86 | int m = a >>> 1; 87 | 88 | sx += a; 89 | sx &= m; 90 | } 91 | 92 | @Override 93 | public void decX() 94 | { 95 | sx -= 1; sx &= MASK_X; 96 | } 97 | 98 | @Override 99 | public void add(T v) { 100 | int mx = MASK_X; 101 | int my = mx << 1; // MASK_Y; 102 | sy += v.sy + mx; 103 | sx += v.sx + my; 104 | sy &= my; 105 | sx &= mx; 106 | } 107 | 108 | @Override 109 | public void sub(T v) 110 | { 111 | int mx = MASK_X; 112 | int my = mx << 1; // MASK_Y; 113 | 114 | sx -= v.sx; 115 | sy -= v.sy; 116 | 117 | sy &= my; 118 | sx &= mx; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/roquen/math/lds/Sobol2D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.lds; 2 | 3 | /** 4 | * 5 | */ 6 | public final class Sobol2D extends LDS 7 | { 8 | // state data 9 | private int i,d0,d1; 10 | 11 | // direction table 12 | private static final int[] D; 13 | 14 | static { 15 | D = new int[33]; 16 | 17 | int c = D[0] = 1 << 31; 18 | 19 | for(int i=1; i<32; i++) { 20 | c = c ^ (c >>> 1); 21 | D[i] = c; 22 | } 23 | 24 | // TODO: what about -1? index 32 25 | } 26 | 27 | private final void updateState() 28 | { 29 | int c = Integer.numberOfTrailingZeros(~i); 30 | d1 ^= D[c]; 31 | d0 ^= 0x80000000 >>> c; 32 | i += 1; 33 | } 34 | 35 | /** Return current index into the stream. */ 36 | public final int getPos() { return i; } 37 | 38 | /** Move 'num' positions forward or backward in the stream. */ 39 | public final void seek(int num) 40 | { 41 | int n = i + num; 42 | int a = i ^ (i >>> 1); 43 | int b = n ^ (n >>> 1); 44 | int d = a ^ b; 45 | 46 | int c = 0; 47 | 48 | while(d != 0) { 49 | if ((d & 1) != 0) { 50 | d0 ^= 0x80000000 >>> c; 51 | d1 ^= D[c]; 52 | } 53 | d >>>= 1; 54 | c += 1; 55 | } 56 | 57 | i = n; 58 | } 59 | 60 | 61 | public Sobol2D() 62 | { 63 | long t = System.nanoTime(); 64 | int m = mix.getAndDecrement(); 65 | int x = (int)t; 66 | int y = (int)(t * 2685821657736338717L); 67 | 68 | // TODO: y value sucks...hash 69 | seed(m^x, m^y); 70 | } 71 | 72 | public Sobol2D(int seedX, int seedY) 73 | { 74 | seed(seedX, seedY); 75 | } 76 | 77 | /** Sets seed values for the two dimensions and resets the stream. */ 78 | public final void seed(int s0, int s1) 79 | { 80 | d0 = s0; 81 | d1 = s1; 82 | i = 0; 83 | } 84 | 85 | public final void next(roquen.fake.Vect2f v) 86 | { 87 | v.x = (d0 >>> 8) * 0x1p-24f; 88 | v.y = (d1 >>> 8) * 0x1p-24f; 89 | } 90 | 91 | 92 | /** Sets the two elements of 'v' starting of 'off' to the next value. */ 93 | public final void next(float[] v, int off) 94 | { 95 | v[off++] = (d0 >>> 8) * 0x1p-24f; 96 | v[off++] = (d1 >>> 8) * 0x1p-24f; 97 | updateState(); 98 | } 99 | 100 | /** Sets the first two elements of 'v' to the next value. */ 101 | public final void next(float[] v) { next(v, 0); } 102 | 103 | /** Puts the next value (two elements) into 'fb' */ 104 | public final void next(java.nio.FloatBuffer fb) 105 | { 106 | fb.put((d0 >>> 8) * 0x1p-24f); 107 | fb.put((d1 >>> 8) * 0x1p-24f); 108 | updateState(); 109 | } 110 | 111 | /** Puts the next value (two elements) into 'fb' at the specified offset. */ 112 | public final void next(java.nio.FloatBuffer fb, int off) 113 | { 114 | fb.put(off, (d0 >>> 8) * 0x1p-24f); 115 | fb.put(off+1, (d1 >>> 8) * 0x1p-24f); 116 | updateState(); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/roquen/math/test/FloatError32.java: -------------------------------------------------------------------------------- 1 | package roquen.math.test; 2 | 3 | import roquen.math.Float32; 4 | 5 | public enum FloatError32 6 | { 7 | ; 8 | 9 | /** 10 | * Given 32 uniformly distributed bits 'bit' returns 11 | * a float uniformly distributed on [-{@link Float#MAX_VALUE}, {@link Float#MAX_VALUE}] 12 | */ 13 | public static final float finiteDomain(int bits) 14 | { 15 | bits &= 0xBFFFFFFF; 16 | return Float.intBitsToFloat(bits); 17 | } 18 | 19 | /** 20 | * Given 32 uniformly distributed bits 'bit' returns 21 | * a float uniformly distributed on [0, {@link Float#MAX_VALUE}] 22 | */ 23 | public static final float positiveFiniteDomain(int bits) 24 | { 25 | bits >>>= 2; 26 | return Float.intBitsToFloat(bits); 27 | } 28 | 29 | /** 30 | * Returns the approximate number of ulp's that returned result 'r' 31 | * is with respect to expected result 'e' 32 | *

    33 | * abs(e-r)/ulp(e) 34 | */ 35 | public static float ulpDiff(float e, float r) 36 | { 37 | // ignores the rounding produced by the subtraction 38 | return Float32.abs(e-r)/Math.ulp(e); 39 | } 40 | 41 | // 2^-24 + ulp(2^24) 42 | private static final float ULP_0 = 0x1.000002p-24f; 43 | 44 | /** 45 | * Returns the size of the ulp in 'f' if |f| >= 2-101. 46 | * Otherwise returns zero. 47 | */ 48 | public static strictfp float approxUlp(float f) 49 | { 50 | return (f+f*ULP_0)-f; 51 | } 52 | 53 | 54 | /** 55 | * Checks if a returned result 'r' is with 'n' ulp of the expected 'e' 56 | *

    57 | * abs(e-r) <= n*ulp(e) 58 | */ 59 | public static boolean withinULP(float e, float r, float n) 60 | { 61 | // ignores the rounding produced by the subtraction 62 | return Float32.abs(e-r) <= n*Math.ulp(e); 63 | } 64 | 65 | /** 66 | * Checks if a returned result 'r' is with 'n' ulp of the expected 'e' 67 | *

    68 | * abs(e-r) <= n*{@link #approxUlp(float) approxUlp(e)} 69 | *

    70 | * NOTE: approxUlp returns zero for small 'e' 71 | */ 72 | public static boolean withinApproxULP(float e, float r, float n) 73 | { 74 | // ignores the rounding produced by the subtraction 75 | return Float32.abs(e-r) <= n*approxUlp(e); 76 | } 77 | 78 | /** Returns sqrt(a2+b2) without overflow or underflow. */ 79 | public static final strictfp float pythagoreanSum(float a, float b) 80 | { 81 | double da = a; 82 | double db = b; 83 | return (float)Math.sqrt(da*da + db*db); 84 | } 85 | 86 | /** 87 | * Returns sqrt(sum(a[i]2) without intermediate overflow or underflow. 88 | *

    89 | * Explodes if: a.length < 2 90 | */ 91 | public static final float pythagoreanSum(float[] a) 92 | { 93 | double da = a[0]; 94 | double db = a[1]; 95 | double s = Math.sqrt(da*da + db*db); 96 | int e = a.length; 97 | 98 | for(int i=2; i= 0) and (x/2 <= y <= 2x) 26 | // then: floating point op (y-x) is exact. 27 | 28 | // x = |a|, x on [pi, 2pi] 29 | // y = 2pi 30 | // a = 2pi - a, a > 0 31 | // a = 32 | 33 | float s = Float.intBitsToFloat(aa);// TODO: complete 34 | float b = (float)(2*Math.PI)-Float.intBitsToFloat(aa); 35 | 36 | //return a; 37 | } 38 | */ 39 | 40 | /** 41 | * Reduces input angle on [0, 2pi] to equivalent value on [-pi,pi]. 42 | *

    43 | * The reduction is exact. 44 | */ 45 | public static final float reduceTwoPi(float a) 46 | { 47 | if (a <= (float)Math.PI) return a; 48 | 49 | // Sterbenz theorem show this subtraction is exact 50 | return (float)(2*Math.PI) - a; 51 | } 52 | 53 | 54 | /** 55 | * Returns sin(a) given cos(a) and a on [-pi,pi], where 56 | * 'sa' is any value with same sign as 'a'. 57 | *

    58 | * computed as: sign(sa) sqrt(1-cos2) 59 | */ 60 | public static final float sinPmPi(float cos, float sa) 61 | { 62 | // TODO: examine the multiply version as well 63 | int sx = Float.floatToRawIntBits(sa) & 0x80000000; 64 | float r = (float)Math.sqrt(1.f-cos*cos); 65 | int ir = Float.floatToRawIntBits(r) ^ sx; 66 | return Float.intBitsToFloat(ir); 67 | } 68 | 69 | 70 | /** 71 | * Returns sin(a) given cos(a) and a on [-pi,pi], where 72 | * 'sa' is any value with same sign as 'a'. 73 | *

    74 | * computed as: sign(sa) sqrt((1-cos)(1+cos)) 75 | *

    76 | * Result is within 1-ulp of correct 77 | */ 78 | 79 | public static final float sinPmPiHq(float cos, float sa) 80 | { 81 | // SEE: sinPmPi - multiply maybe 82 | int sx = Float.floatToRawIntBits(sa) & 0x80000000; 83 | float r = (float)Math.sqrt((1.f-cos)*(1.f+cos)); 84 | int ir = Float.floatToRawIntBits(r) ^ sx; 85 | return Float.intBitsToFloat(ir); 86 | } 87 | 88 | /** 89 | * Returns sin(a) given cos(a) and a on [0,pi]. 90 | *

    91 | * computed as: sqrt(1-cos2) 92 | * @see {@link #sinPiHq(float)} 93 | */ 94 | public static final float sinPi(float cos) 95 | { 96 | return (float)Math.sqrt(1.f-cos*cos); 97 | } 98 | 99 | /** 100 | * Returns sin(a) given cos(a) and a on [0, pi]. 101 | *

    102 | * computed as: sqrt((1-cos)(1+cos)) 103 | *

    104 | * Result is within 1-ulp of correct and has 105 | * the same dependency chain length as 106 | * {@link #sinPi(float)} 107 | */ 108 | public static final float sinPiHq(float cos) 109 | { 110 | return (float)Math.sqrt((1.f-cos)*(1.f+cos)); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/roquen/math/test/FloatError64.java: -------------------------------------------------------------------------------- 1 | package roquen.math.test; 2 | 3 | import roquen.math.Float64; 4 | 5 | public enum FloatError64 6 | { 7 | ; 8 | 9 | /** 10 | * Given 64 uniformly distributed bits 'bit' returns 11 | * a double uniformly distributed on [-{@link Double#MAX_VALUE}, {@link Double#MAX_VALUE}] 12 | */ 13 | public static final double finiteDomain(long bits) 14 | { 15 | bits &= 0xBFFFFFFF_FFFFFFFFL; 16 | return Double.longBitsToDouble(bits); 17 | } 18 | 19 | /** 20 | * Given 64 uniformly distributed bits 'bit' returns 21 | * a double uniformly distributed on [0, {@link Double#MAX_VALUE}] 22 | */ 23 | public static final double positiveFiniteDomain(long bits) 24 | { 25 | bits >>>= 2; 26 | return Double.longBitsToDouble(bits); 27 | } 28 | 29 | /** 30 | * Returns the approximate number of ulp's that returned result 'r' 31 | * is with respect to expected result 'e' 32 | *

    33 | * abs(e-r)/ulp(e) 34 | */ 35 | public static final double ulpDiff(double e, double r) 36 | { 37 | // ignores the rounding produced by the subtraction 38 | return Float64.abs(e-r)/Math.ulp(e); 39 | } 40 | 41 | /** 42 | * Checks if a returned result 'r' is with 'n' ulp of the expected 'e' 43 | *

    44 | * abs(e-r) <= n*ulp(e) 45 | */ 46 | public static final boolean withinULP(double e, double r, double n) 47 | { 48 | // ignores the rounding produced by the subtraction 49 | return Float64.abs(e-r) <= n*Math.ulp(e); 50 | } 51 | 52 | // 2^-53 + ulp(2^-53) 53 | private static final double ULP_0 = 0x1.0000000000001p-53; 54 | 55 | /** 56 | * Returns the size of the ulp in 'f' if |f| >= 2-969, 57 | * otherwise returns zero. 58 | */ 59 | public static strictfp double approxUlp(double f) 60 | { 61 | return (f+f*ULP_0)-f; 62 | } 63 | 64 | /** 65 | * Checks if a returns result 'r' is with 'n' ulp of the expected 'e'. 66 | *

    67 | * abs(e-r) <= n*{@link #approxUlp(double) approxUlp(e)} 68 | *

    69 | * NOTE: approxUlp returns zero for small 'e' 70 | */ 71 | public static boolean withinApproxULP(double e, double r, double n) 72 | { 73 | // ignores the rounding produced by the subtraction 74 | return Float64.abs(e-r) <= n*approxUlp(e); 75 | } 76 | 77 | /** Returns sqrt(a2+b2) without overflow or underflow. */ 78 | public static final double pythagoreanSum(double a, double b) 79 | { 80 | return Math.hypot(a, b); 81 | } 82 | 83 | /** 84 | * Returns sqrt(sum(a[i]2) without intermediate overflow or underflow. 85 | *

    86 | * Explodes if: a.length < 2 87 | *

    88 | * @see Math#hypot(double, double) 89 | */ 90 | public static final double pythagoreanSum(double[] a) 91 | { 92 | double s = Math.hypot(a[0], a[1]); 93 | int e = a.length; 94 | 95 | for(int i=2; isqrt(a2-b2) without intermediate overflow or underflow. */ 102 | public static final double pythagoreanDiff(double a, double b) 103 | { 104 | b = b/a; 105 | return Math.abs(a)*Math.sqrt((1.0-b)*(1.0+b)); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/roquen/interp/DDA2D.java: -------------------------------------------------------------------------------- 1 | package roquen.interp; 2 | 3 | import roquen.fake.Vect2f; 4 | 5 | /** 6 | * For performing in-order walks of cells on a uniform 2D grid which 7 | * are crossed by a line segment or ray. It is equivalent to a 8 | * Bresenham's line walk. The basic mechanism is to determine a major 9 | * axis and walk a connected set of cells along that axis. 10 | *

    11 | * Passed in values make the assumption that the extent of cells are 12 | * of one unit. User code scaling is required for other sizes. 13 | *

    14 | * The name is actually a misnomer as the computation is in floating 15 | * point. This drastically reduces the complexity of the update. 16 | */ 17 | public class DDA2D { 18 | /** 19 | * use-case specific cell offset. default=0 (lower left). 20 | * set to .5 for center of cell for example. 21 | */ 22 | private double offset; 23 | 24 | /** current number of steps (integer) */ 25 | private double step; 26 | 27 | /** inverse the number of steps (one rounding error) */ 28 | private double in; 29 | 30 | /** coordinate of cell containing the first point (integer) */ 31 | private double x0,y0; 32 | 33 | /** integer displacement from first to last cell (integer) */ 34 | private double dx,dy; 35 | 36 | /** current step (cell) coordinate, includes fractional */ 37 | public double x,y; 38 | 39 | public int set(float sx, float sy, float ex, float ey) 40 | { 41 | // find the cell coordinate of the end points 42 | x0 = Math.floor(sx); 43 | y0 = Math.floor(sy); 44 | 45 | double x1 = Math.floor(ex); 46 | double y1 = Math.floor(ey); 47 | 48 | // initialize current cell coordinate 49 | x = x0 + offset; 50 | y = y0 + offset; 51 | step = 1; 52 | 53 | // calculate the deltas and find the maximum magnitude 54 | dx = x1-x0; 55 | dy = y1-y0; 56 | 57 | double ax = Math.abs(dx); 58 | double ay = Math.abs(dy); 59 | double n = ax > ay ? ax : ay; 60 | 61 | // calculate the step values 62 | in = 1.0/n; 63 | 64 | return (int)n; 65 | } 66 | 67 | /** 68 | * Sets the instance to iterate over all cells covered 69 | * by the line segment from p0 to p1 in order. Return 70 | * the number of steps required. 71 | *

    72 | * The fields ({@link #x}, {@link #y}) are 73 | * set to the first cell coordinate. 74 | */ 75 | public int set(Vect2f p0, Vect2f p1) 76 | { 77 | return set(p0.x,p0.y,p1.x,p1.y); 78 | } 79 | 80 | public final void setCenteredMode(boolean mode) 81 | { 82 | if (mode) 83 | offset = 0.5; 84 | else 85 | offset = 0.0; 86 | } 87 | 88 | /** 89 | * Updates ({@link #x}, {@link #y}) to the next cell 90 | * coordinate, including fractional parts. 91 | *

    92 | * In the default mode (no center) taking the floor is the 93 | * coordinate of the cell. If they are insured to be positive, 94 | * then truncate (cast) to integers. 95 | *

    96 | * Calling more times than the required number of steps will 97 | * continue to visit cells in the same direction. 98 | */ 99 | public void next() 100 | { 101 | // formulation for no compounding of errors across steps 102 | double n = step*in; 103 | x = x0 + n*dx; 104 | y = y0 + n*dy; 105 | step += 1; 106 | } 107 | } -------------------------------------------------------------------------------- /src/roquen/math/rng/BidirectionalLCG.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng; 2 | 3 | /** 4 | * A 32-bit power-of-two LCG generator which can move both directions in the 5 | * sequence. 6 | */ 7 | public class BidirectionalLCG extends PRNG32 { 8 | 9 | /** state data */ 10 | private int data; 11 | 12 | /** true if moving forward in the stream and false if move backward. */ 13 | private boolean forward = true; 14 | 15 | private final int mf; // forward multiplier 16 | private final int mr; // reverse multiplier 17 | private final int a; // additive constant 18 | 19 | 20 | // length of this table must currently be a power-of-two. 21 | // each "pair" are connected such that the second "must" 22 | // be an inverse modulo of the first. 23 | protected static final int[] mult = 24 | { 25 | 0xac549d55, 0xfe4677fd, 26 | 0x01c8e815, 0x608fa73d, 27 | 0x01ed0675, 0xd5c019dd, 28 | 0x41c64e6d, 0xeeb9eb65, 29 | }; 30 | 31 | protected static final int mask = (mult.length>>1)-1; 32 | protected static final int shift = 32-Integer.numberOfLeadingZeros(mask); 33 | 34 | /** 35 | * Number of multipliers in the set. 36 | */ 37 | public static int getNumM() 38 | { 39 | return mult.length; 40 | } 41 | 42 | protected static final int getAdditive(int set) 43 | { 44 | int r; 45 | 46 | // drop the bits used to select the multiplier 47 | r = set >>> shift; 48 | 49 | // maybe a weyl generator would be a better choice. 50 | r = Integer.reverse(r); 51 | r = r + 1234; 52 | 53 | // the return value "must" be odd 54 | return r | 1; 55 | } 56 | 57 | /** 58 | * 59 | */ 60 | public BidirectionalLCG(int set) 61 | { 62 | int t = (set & mask) << 1; 63 | 64 | // Set the multiplicative constants. 65 | mf = mult[t ]; 66 | mr = mult[t+1]; 67 | 68 | // The addition must be odd. 69 | a = getAdditive(set); 70 | } 71 | 72 | /** 73 | * 74 | */ 75 | public BidirectionalLCG(int set, int add) 76 | { 77 | set = (set & mask) << 1; 78 | mf = mult[set ]; 79 | mr = mult[set+1]; 80 | a = add | 1; 81 | } 82 | 83 | 84 | public final void setState(int seed, boolean forward) 85 | { 86 | this.data = seed; 87 | this.forward = forward; 88 | } 89 | 90 | /** 91 | * Returns the next 32-bit integer in the sequence in the 92 | * current direction. 93 | *

    94 | * Low order bits have a shorter period than higher order 95 | * ones. Therefore using the highest bits possible is 96 | * desirable. 97 | */ 98 | @Override 99 | public final int nextInt() 100 | { 101 | // TODO: this can be rewritten to be not 102 | if (forward) 103 | data = mf * data + a; 104 | else 105 | data = (data - a) * mr; 106 | 107 | return data; 108 | } 109 | 110 | /** Toggles the current direction of the sequence. */ 111 | public final boolean flip() 112 | { 113 | nextInt(); 114 | forward = !forward; 115 | 116 | return forward; 117 | } 118 | 119 | /** Returns true if the sequence is currently moving forward. */ 120 | public final boolean isForward() 121 | { 122 | return forward; 123 | } 124 | 125 | @Override 126 | public final void setSeed(long seed) { 127 | data = (int)seed; 128 | } 129 | 130 | @Override 131 | public final long getSeed() { 132 | return data; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/roquen/interp/DDA3D.java: -------------------------------------------------------------------------------- 1 | package roquen.interp; 2 | 3 | import roquen.fake.Vect3f; 4 | 5 | /** 6 | * For performing in-order walks of cells on a uniform 3D grid which 7 | * are crossed by a line segment or ray. It is equivalent to a 8 | * Bresenham's line walk. 9 | *

    10 | * Passed in values make the assumption that the extent of cells are 11 | * of one unit. User code scaling is required for other sizes. 12 | *

    13 | * The name is actually a misnomer as the computation is in floating 14 | * point. This drastically reduces the complexity of the update. 15 | */ 16 | public class DDA3D { 17 | // NOTE: Computation is in doubles. Usage requires little memory 18 | // motion and the extra bits allow for larger grids. 19 | 20 | /** 21 | * use-case specific cell offset. default=0 (lower left). 22 | * set to .5 for center of cell for example. 23 | */ 24 | private double offset; 25 | 26 | /** current number of steps (integer) */ 27 | private double step; 28 | 29 | /** inverse the number of steps (one rounding error) */ 30 | private double in; 31 | 32 | /** coordinate of cell containing the first point (integer) */ 33 | private double x0,y0,z0; 34 | 35 | /** integer displacement from first to last cell (integer) */ 36 | private double dx,dy,dz; 37 | 38 | /** current step (cell) coordinate, includes fractional */ 39 | public double x,y,z; 40 | 41 | /** 42 | * Sets the instance to iterate over all cells covered 43 | * by the line segment from p0 to p1 in order. Return 44 | * the number of steps required. 45 | *

    46 | * The fields ({@link #x}, {@link #y}, {@link #z}) are 47 | * set to the first cell coordinate. 48 | */ 49 | public int set(Vect3f p0, Vect3f p1) 50 | { 51 | // find the cell coordinate of the end points 52 | x0 = Math.floor(p0.x); 53 | y0 = Math.floor(p0.y); 54 | z0 = Math.floor(p0.z); 55 | 56 | double x1 = Math.floor(p1.x); 57 | double y1 = Math.floor(p1.y); 58 | double z1 = Math.floor(p1.z); 59 | 60 | // initialize current cell coordinate 61 | x = x0 + offset; 62 | y = y0 + offset; 63 | z = z0 + offset; 64 | step = 1; 65 | 66 | // calculate the deltas and find the maximum magnitude 67 | dx = x1-x0; 68 | dy = y1-y0; 69 | dz = z1-z0; 70 | 71 | double ax = Math.abs(dx); 72 | double ay = Math.abs(dy); 73 | double az = Math.abs(dz); 74 | double n = ax > ay ? ax : ay; 75 | if (az > n) n = dz; 76 | 77 | // calculate the step values 78 | in = 1.0/n; 79 | 80 | return (int)n; 81 | } 82 | 83 | public final void setCenteredMode(boolean mode) 84 | { 85 | if (mode) 86 | offset = 0.5; 87 | else 88 | offset = 0.0; 89 | } 90 | 91 | /** 92 | * Updates ({@link #x}, {@link #y}, {@link #z}) to the next cell 93 | * coordinate, including fractional parts. 94 | *

    95 | * In the default mode (no center) taking the floor is the 96 | * coordinate of the cell. If they are insured to be positive, 97 | * then truncate (cast) to integers. 98 | *

    99 | * Calling more times than the required number of steps will 100 | * continue to visit cells in the same direction. 101 | */ 102 | public void next() 103 | { 104 | // formulation for no compounding of errors across steps 105 | double n = step*in; 106 | x = x0 + n*dx; 107 | y = y0 + n*dy; 108 | z = z0 + n*dz; 109 | step += 1; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/roquen/wiki/dvar/UserVar.java: -------------------------------------------------------------------------------- 1 | package roquen.wiki.dvar; 2 | 3 | /** 4 | * Minimal example of implementing a limited form of prototype based variables. 5 | */ 6 | 7 | abstract class UserVar 8 | { 9 | /** */ 10 | public enum TYPE 11 | { 12 | // these are here mostly to allow the holding container to perform 13 | // in-place updates, which the example container "GameObject" does 14 | // not. 15 | NONE, 16 | INTEGER, 17 | FLOAT, 18 | STRING, 19 | ENTITY 20 | ; 21 | } 22 | 23 | /** */ 24 | abstract int getInt(); 25 | 26 | /** */ 27 | abstract float getFloat(); 28 | 29 | /** */ 30 | abstract String getString(); 31 | 32 | /** */ 33 | abstract Entity getEntity(); 34 | 35 | /** */ 36 | abstract TYPE getType(); 37 | 38 | // Sentinel for non-existent variables 39 | public static final UserVar NILL = new UserVar() 40 | { 41 | @Override final int getInt() { return 0; } 42 | @Override final float getFloat() { return 0; } 43 | @Override final String getString() { return ""; } 44 | @Override final Entity getEntity() { return Entity.NILL; } 45 | @Override final TYPE getType() { return TYPE.NONE; } 46 | }; 47 | 48 | // NOTE: Could easily be a double instead. Given small object size padding 49 | // it's likely wouldn't even increase memory footprint. 50 | static final class FLOAT extends UserVar 51 | { 52 | float value; 53 | 54 | FLOAT(float v) { value = v; } 55 | 56 | @Override final int getInt() { return (int)value; } 57 | @Override final float getFloat() { return value; } 58 | @Override final String getString() { return String.valueOf(value); } 59 | @Override final Entity getEntity() { return Entity.NILL; } 60 | @Override final TYPE getType() { return TYPE.FLOAT; } 61 | } 62 | 63 | // NOTE: Could easily be a long instead. Given small object size padding 64 | // it's likely wouldn't even increase memory footprint. 65 | static final class INT extends UserVar 66 | { 67 | int value; 68 | 69 | INT(int v) { value = v; } 70 | 71 | @Override final int getInt() { return value; } 72 | @Override final float getFloat() { return value; } 73 | @Override final String getString() { return String.valueOf(value); } 74 | @Override final Entity getEntity() { return Entity.NILL; } // could lookup UID if used 75 | @Override final TYPE getType() { return TYPE.INTEGER; } 76 | } 77 | 78 | static final class STRING extends UserVar 79 | { 80 | String value; 81 | 82 | STRING(String v) { value = v; } 83 | 84 | @Override final int getInt() { return 0; } // parsing would be better 85 | @Override final float getFloat() { return 0; } // paring would be better 86 | @Override final String getString() { return value; } 87 | @Override final Entity getEntity() { return Entity.NILL; } // could look up tag 88 | @Override final TYPE getType() { return TYPE.STRING; } 89 | } 90 | 91 | static final class ENTITY extends UserVar 92 | { 93 | Entity value; 94 | 95 | ENTITY(Entity v) { value = v; } 96 | 97 | @Override final int getInt() { return 0; } // or UID if used 98 | @Override final float getFloat() { return 0; } // ditto as int 99 | @Override final String getString() { return ""; } // or something else 100 | @Override final Entity getEntity() { return value; } 101 | @Override final TYPE getType() { return TYPE.ENTITY; } 102 | } 103 | } -------------------------------------------------------------------------------- /src/roquen/math/lds/Sobol3D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.lds; 2 | 3 | /** 4 | * 5 | */ 6 | public final class Sobol3D extends LDS 7 | { 8 | // state data for the sequence 9 | private int i,d0,d1,d2; 10 | 11 | // direction table 12 | private static final int[] D; 13 | 14 | // build the direction tables 15 | static { 16 | // TODO: 'i' = -1 is not handled 17 | 18 | D = new int[65]; 19 | 20 | // second dimension 21 | int c = 1 << 31; 22 | 23 | D[0] = c; 24 | 25 | for(int i=2; i<64; i+=2) { 26 | c = c ^ (c >>> 1); 27 | D[i] = c; 28 | } 29 | 30 | // third dimension 31 | int s0,s1,t; 32 | 33 | s0 = D[1] = D[0]; 34 | s1 = D[3] = D[2]; 35 | 36 | for (int i=4; i<64; i+=2) { 37 | t = s1; 38 | s1 ^= s0 ^ (s0 >>> 2); 39 | s0 = t; 40 | 41 | D[i+1] = s1; 42 | } 43 | } 44 | 45 | /** */ 46 | public Sobol3D() { 47 | long t = System.nanoTime(); 48 | int m = mix.getAndDecrement(); 49 | int x = (int)t; 50 | int y = (int)(t >> 32); 51 | int z = (int)(t * 2685821657736338717L); 52 | 53 | // TODO: y&z values sucks...hash 54 | seed(m^x, m^y, m^z); 55 | } 56 | 57 | /** Sets seed values for the three dimensions and resets the stream. */ 58 | public final void seed(int s0, int s1, int s2) 59 | { 60 | d0 = s0; 61 | d1 = s1; 62 | d2 = s2; 63 | i = 0; 64 | } 65 | 66 | /** Return current index into the stream. */ 67 | public final int getPos() { return i; } 68 | 69 | /** */ 70 | private final void updateState() 71 | { 72 | int c = Integer.numberOfTrailingZeros(~i); 73 | int o = c+c; 74 | 75 | d0 ^= 0x80000000 >>> c; 76 | d1 ^= D[o]; 77 | d2 ^= D[o+1]; 78 | i += 1; 79 | } 80 | 81 | /** Move 'num' positions forward or backward in the stream. */ 82 | public final void seek(int num) 83 | { 84 | int n = i + num; 85 | int a = i ^ (i >>> 1); 86 | int b = n ^ (n >>> 1); 87 | int d = a ^ b; 88 | 89 | int c = 0; 90 | 91 | while(d != 0) { 92 | if ((d & 1) != 0) { 93 | d0 ^= 0x80000000 >>> c; 94 | d1 ^= D[c+c]; 95 | d2 ^= D[c+c+1]; 96 | } 97 | 98 | d >>>= 1; 99 | c += 1; 100 | } 101 | 102 | i = n; 103 | } 104 | 105 | public final void next(roquen.fake.Vect3f v) 106 | { 107 | v.x = (d0 >>> 8) * 0x1p-24f; 108 | v.y = (d1 >>> 8) * 0x1p-24f; 109 | v.z = (d2 >>> 8) * 0x1p-24f; 110 | } 111 | 112 | /** Sets the three elements of 'v' starting of 'off' to the next value. */ 113 | public final void next(float[] v, int off) 114 | { 115 | v[off++] = (d0 >>> 8) * 0x1p-24f; 116 | v[off++] = (d1 >>> 8) * 0x1p-24f; 117 | v[off++] = (d2 >>> 8) * 0x1p-24f; 118 | 119 | updateState(); 120 | } 121 | 122 | /** Sets the first three elements of 'v' to the next value. */ 123 | public final void next(float[] v) { next(v,0); } 124 | 125 | /** Puts the next value (three elements) into 'fb' */ 126 | public final void next(java.nio.FloatBuffer fb) 127 | { 128 | fb.put((d0 >>> 8) * 0x1p-24f); 129 | fb.put((d1 >>> 8) * 0x1p-24f); 130 | fb.put((d2 >>> 8) * 0x1p-24f); 131 | updateState(); 132 | } 133 | 134 | /** Puts the next value (three elements) into 'fb' at the specified offset. */ 135 | public final void next(java.nio.FloatBuffer fb, int off) 136 | { 137 | fb.put(off++, (d0 >>> 8) * 0x1p-24f); 138 | fb.put(off++, (d1 >>> 8) * 0x1p-24f); 139 | fb.put(off, (d2 >>> 8) * 0x1p-24f); 140 | updateState(); 141 | } 142 | } -------------------------------------------------------------------------------- /src/roquen/util/Generics.java: -------------------------------------------------------------------------------- 1 | package roquen.util; 2 | 3 | //import java.lang.reflect.*; 4 | import java.util.function.Function; 5 | 6 | public enum Generics 7 | { 8 | ; 9 | 10 | /** Helper class for creating arrays and instances of type T. */ 11 | public static class Factory 12 | { 13 | private final Class clazz; 14 | private final Function,T> alloc; 15 | 16 | /** */ 17 | public Factory(Class type) 18 | { 19 | clazz = type; 20 | alloc = Factory::defAlloc; 21 | } 22 | 23 | /** Specify the method of instance allocation */ 24 | public Factory(Class type, Function,T> gen) 25 | { 26 | clazz = type; 27 | alloc = gen != null ? gen : Factory::defAlloc; 28 | } 29 | 30 | @SuppressWarnings("unchecked") 31 | public static Factory get(T obj) 32 | { 33 | return (Factory)new Factory<>(obj.getClass()); 34 | } 35 | 36 | /** */ 37 | public final Class getType() { return clazz; } 38 | 39 | /** */ 40 | public final T[] newArray(int len) 41 | { 42 | return Generics.newArray(clazz, len); 43 | } 44 | 45 | /** Returns an array of length 'n' filled with instances created by {@link #newInstance()}*/ 46 | public T[] newFilledArray(int n) 47 | { 48 | T[] a = newArray(n); 49 | 50 | for(int i=0; i T defAlloc(Class clazz) 57 | { 58 | try { 59 | return clazz.newInstance(); 60 | } catch (InstantiationException|IllegalAccessException e) { 61 | return null; 62 | } 63 | } 64 | 65 | /** 66 | * Instantiate an object of type 'T'. 67 | */ 68 | public T newInstance() 69 | { 70 | return alloc.apply(clazz); 71 | } 72 | } 73 | 74 | 75 | public static T[] newArray(T obj, int len) 76 | { 77 | Class clazz = obj.getClass(); 78 | 79 | @SuppressWarnings("unchecked") 80 | T[] r = (T[])java.lang.reflect.Array.newInstance(clazz, len); 81 | 82 | return r; 83 | } 84 | 85 | public static T[] newArray(Class clazz, int len) 86 | { 87 | @SuppressWarnings("unchecked") 88 | T[] r = (T[])java.lang.reflect.Array.newInstance(clazz, len); 89 | 90 | return r; 91 | } 92 | 93 | /** 94 | * Only for weak type requirements. Actual type of the 95 | * array is Object[]. 96 | */ 97 | public static T[] newArray(int len) 98 | { 99 | @SuppressWarnings("unchecked") 100 | T[] r = (T[])new Object[len]; 101 | 102 | return r; 103 | } 104 | 105 | /* 106 | // Don't look at me: thinking about evil things here 107 | @SuppressWarnings("unchecked") 108 | public static T fooBar(Object obj) throws Exception 109 | { 110 | ParameterizedType superclass = (ParameterizedType)obj.getClass().getGenericSuperclass(); 111 | Class object = (Class)superclass.getActualTypeArguments()[0]; 112 | Class[] params = {}; 113 | Constructor cons = object.getDeclaredConstructor(params); 114 | Object[] args = {}; 115 | 116 | return cons.newInstance(args); 117 | } 118 | */ 119 | 120 | 121 | 122 | public static void main(String[] args) 123 | { 124 | Factory intFactory = new Factory<>(int.class); 125 | 126 | Object bar = intFactory.newArray(10); 127 | int[] bari = (int[])bar; 128 | 129 | System.out.println(bari.getClass()); 130 | 131 | //Factory sobelGen = new Factory<>(roquen.math.lds.Sobol1D.class); 132 | //roquen.math.lds.Sobol1D lds = sobelGen.newInstance(); 133 | 134 | //System.out.println(lds.next()); 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/roquen/vm/FatOaf.java: -------------------------------------------------------------------------------- 1 | package roquen.vm; 2 | 3 | import static sun.misc.Unsafe.*; 4 | import static roquen.vm.UnsafeUtils.*; 5 | 6 | /** 7 | * Fat off-heap Overlaid Array Format 8 | */ 9 | 10 | // Experimental evil hack for comparison vs. put/get and direct buffers 11 | @SuppressWarnings("restriction") 12 | public class FatOaf 13 | { 14 | /** */ 15 | public final byte[] b; 16 | 17 | /** */ 18 | public final int[] i; 19 | 20 | /** */ 21 | public final float[] f; 22 | 23 | private final long baseAddress; 24 | 25 | // just to shorten things a bit 26 | private static final int F = ARRAY_FLOAT_BASE_OFFSET; 27 | private static final int I = ARRAY_INT_BASE_OFFSET; 28 | private static final int B = ARRAY_BYTE_BASE_OFFSET; 29 | 30 | private static final int HEADER_LEN = F+I+B; 31 | 32 | /** */ 33 | private static final long template; 34 | 35 | // TODO: correctly build these 36 | private static final int F_LEN_OFF = instanceHeaderSize; 37 | private static final int I_LEN_OFF = F+instanceHeaderSize; 38 | private static final int B_LEN_OFF = F+I+instanceHeaderSize; 39 | 40 | /** initial index of the data for the integer array */ 41 | public static final int I_OFF = B >> 2; 42 | 43 | /** initial index of the data for the float array */ 44 | public static final int F_OFF = I_OFF + (I >> 2); 45 | 46 | /** initial index of the data for the byte array */ 47 | public static final int B_OFF = 0; 48 | 49 | static { 50 | long a = template = unsafe.allocateMemory(HEADER_LEN); 51 | float[] f = new float[3]; 52 | int[] i = new int[4]; 53 | byte[] b = new byte[5]; 54 | 55 | // TODO: verify length offset 56 | unsafe.copyMemory(f, 0, null, a, F); a += F; 57 | unsafe.copyMemory(i, 0, null, a, I); a += I; 58 | unsafe.copyMemory(b, 0, null, a, B); 59 | 60 | int lf = unsafe.getInt(template + F_LEN_OFF); 61 | int li = unsafe.getInt(template + I_LEN_OFF); 62 | int lb = unsafe.getInt(template + B_LEN_OFF); 63 | 64 | if (lf == 3 && li == 4 && lb == 5) { 65 | unsafe.putInt(template + F_LEN_OFF, Integer.MAX_VALUE); 66 | unsafe.putInt(template + I_LEN_OFF, Integer.MAX_VALUE); 67 | unsafe.putInt(template + B_LEN_OFF, Integer.MAX_VALUE); 68 | } 69 | else throw new RuntimeException("oops"); 70 | } 71 | 72 | // TODO: make temp arrays if not expected headers found 73 | 74 | public FatOaf(int len, boolean lie) 75 | { 76 | len = (len + 3) & ~3; 77 | 78 | long size = len + HEADER_LEN; 79 | 80 | baseAddress = unsafe.allocateMemory(size); 81 | 82 | unsafe.copyMemory(null, template, null, baseAddress, HEADER_LEN); 83 | 84 | // TODO: temp hack 85 | f = (float[])getReference(baseAddress); 86 | i = (int[]) getReference(baseAddress + F); 87 | b = (byte[]) getReference(baseAddress + F+I); 88 | 89 | if (!lie) { 90 | unsafe.putInt(baseAddress + F_LEN_OFF, (len >> 2) + I_OFF); 91 | unsafe.putInt(baseAddress + I_LEN_OFF, (len >> 2) + F_OFF); 92 | unsafe.putInt(baseAddress + B_LEN_OFF, len + B_OFF); 93 | } 94 | 95 | } 96 | 97 | public static void main(String[] args) 98 | { 99 | FatOaf oaf = new FatOaf(44, true); 100 | int[] i = oaf.i; 101 | byte[] b = oaf.b; 102 | float[] f = oaf.f; 103 | 104 | System.out.println(F + " " + I + " " + B); 105 | 106 | System.out.println(f.getClass() + " " + f.length); 107 | System.out.println(i.getClass() + " " + i.length); 108 | System.out.println(b.getClass() + " " + b.length); 109 | 110 | System.out.println(HEADER_LEN); 111 | System.out.println(I_OFF + " " + F_OFF); 112 | 113 | b[3] = 0x12; 114 | b[2] = 0x34; 115 | b[1] = 0x56; 116 | b[0] = 0x78; 117 | 118 | System.out.println(i[I_OFF] == 0x12345678); 119 | 120 | f[F_OFF] = 1.f; 121 | 122 | System.out.println(Integer.toHexString(i[I_OFF])); 123 | 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/roquen/vm/UnsafeUtils.java: -------------------------------------------------------------------------------- 1 | package roquen.vm; 2 | 3 | import sun.misc.Unsafe; 4 | 5 | /** temp hack - hotspot only (more or less) */ 6 | public enum UnsafeUtils 7 | { 8 | ; 9 | 10 | // temp testing hack -- of no use as is 11 | public enum ArrayType 12 | { 13 | BOOLEAN(boolean[].class), 14 | BYTE (byte[].class), 15 | SHORT (short[].class), 16 | CHAR (char[].class), 17 | INT (int[].class), 18 | FLOAT (float[].class), 19 | LONG (long[].class), 20 | DOUBLE (double[].class), 21 | OBJECT (Object[].class) 22 | ; 23 | 24 | public final Class clazz; 25 | private final int headerSize; 26 | private final int elementSize; 27 | 28 | ArrayType(Class c) 29 | { 30 | clazz = c; 31 | headerSize = unsafe.arrayBaseOffset(c); 32 | elementSize = unsafe.arrayIndexScale(c); 33 | } 34 | 35 | /** */ 36 | public int getHeaderSize() 37 | { 38 | return headerSize; 39 | //return unsafe.arrayBaseOffset(clazz); 40 | } 41 | 42 | /** */ 43 | public int getElementSize() 44 | { 45 | return elementSize; 46 | //return unsafe.arrayIndexScale(clazz); 47 | } 48 | 49 | /** */ 50 | public long sizeof(int len) 51 | { 52 | return getHeaderSize() + ((long)getElementSize())*len; 53 | } 54 | 55 | } 56 | 57 | 58 | public static final sun.misc.Unsafe unsafe; 59 | 60 | // fill-in unsafe 61 | static { 62 | java.lang.reflect.Field f; 63 | Unsafe u = null; 64 | try { 65 | f = Unsafe.class.getDeclaredField("theUnsafe"); 66 | f.setAccessible(true); 67 | u = (Unsafe) f.get(null); 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } 71 | unsafe = u; 72 | } 73 | 74 | /** 75 | * true if references are stored in 64-bits. 64-bit VM and no compressed oops. 76 | */ 77 | public static final boolean longPointer = Unsafe.ARRAY_OBJECT_INDEX_SCALE == 8; 78 | 79 | /** 80 | * true if VM is 64-bit. 81 | */ 82 | public static final boolean is64Bit = Unsafe.ADDRESS_SIZE == 8; 83 | 84 | /** 85 | * true if hardware stores data in little endian format 86 | */ 87 | public static final boolean isLittleEndian; 88 | 89 | static { 90 | long a = unsafe.allocateMemory(4); 91 | unsafe.putAddress(a, 0x12345678); 92 | byte b = unsafe.getByte(a); 93 | unsafe.freeMemory(a); 94 | isLittleEndian = b == (byte)0x78; 95 | } 96 | 97 | public static final int instanceHeaderSize; 98 | 99 | static { 100 | // TODO: this assumes hotspot...add some checking 101 | instanceHeaderSize = Unsafe.ADDRESS_SIZE + Unsafe.ARRAY_OBJECT_INDEX_SCALE; 102 | } 103 | 104 | 105 | //public static java.lang.reflect.Constructor c; 106 | //public static final java.lang.invoke.MethodHandle mh; 107 | 108 | static { 109 | java.lang.reflect.Constructor m; 110 | 111 | try { 112 | Class dbb = ClassLoader.getSystemClassLoader().loadClass("java.nio.DirectByteBuffer"); 113 | m = dbb.getDeclaredConstructor(long.class, int.class, Object.class); 114 | m.setAccessible(true); 115 | //mh = java.lang.invoke.MethodHandles.lookup().unreflectConstructor(m).asType(java.lang.invoke.MethodType.methodType(java.nio.ByteBuffer.class, long.class, int.class, Object.class)); 116 | } 117 | catch(Throwable t) {/**/} 118 | } 119 | 120 | //riven 121 | /** 122 | * Convert a raw address into a reference. The GC could have moved 123 | * the actual object between if the value is 'on-heap'. 124 | */ 125 | public static Object getReference(long a) 126 | { 127 | Object[] t = new Object[1]; 128 | 129 | if (longPointer) 130 | unsafe.putLong(t, (long)Unsafe.ARRAY_OBJECT_BASE_OFFSET, a); 131 | else 132 | unsafe.putInt(t, (long)Unsafe.ARRAY_OBJECT_BASE_OFFSET, (int)a); 133 | 134 | return t[0]; 135 | } 136 | 137 | // riven 138 | /** Convert a reference into a raw address. */ 139 | public static long getAddress(Object o) 140 | { 141 | Object[] t = new Object[] {o}; 142 | long a; 143 | 144 | if (longPointer) 145 | a = unsafe.getLong(t, (long)Unsafe.ARRAY_OBJECT_BASE_OFFSET); 146 | else 147 | a = unsafe.getInt(t, (long)Unsafe.ARRAY_OBJECT_BASE_OFFSET) & 0xFFFF_FFFFL; 148 | 149 | return a; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/roquen/math/Int32.java: -------------------------------------------------------------------------------- 1 | package roquen.math; 2 | 3 | 4 | // NOTES: Includes some uber basics for those not familiar with their bit-twiddling. 5 | // These will all be small and are highly likely to be inlined 6 | 7 | // The final on methods is implicitly, explicitly marked 8 | // because it can't hurt. 9 | public enum Int32 { 10 | 11 | ; 12 | 13 | // HotSpot has popcount as an intrinsic, but we need a way 14 | // to test for hardware support...sigh. 15 | static final boolean hasPopCount = false; 16 | 17 | /** 18 | * Returns true if 'a' and 'b' have the same sign. 19 | * Zero is considered to be positive. 20 | */ 21 | public static final boolean sameSign(int a, int b) 22 | { 23 | return (a^b) >= 0; 24 | } 25 | 26 | /** 27 | * Returns true if 'x' is zero or a power-of-two. 28 | */ 29 | public static final boolean isZeroOrPOT(int x) 30 | { 31 | return (x & (x-1)) == 0; 32 | } 33 | 34 | /** Returns 'x' with the lowest set bit zeroed */ 35 | public static final int zeroLowBit(int x) 36 | { 37 | return x & (x-1); 38 | } 39 | 40 | /** */ 41 | public static final int isolateLowBit(int x) 42 | { 43 | return x & -x; 44 | } 45 | 46 | /** */ 47 | public static final int isolateLowZero(int x) 48 | { 49 | return ~x & (x+1); 50 | } 51 | 52 | /** Set all low order bits until a set bit is found. */ 53 | public static final int fillLow(int x) 54 | { 55 | return x | (x-1); 56 | } 57 | 58 | /** Set the lowest zero to one. No effect in none. */ 59 | public static final int setLowZero(int x) 60 | { 61 | return x | (x+1); 62 | } 63 | 64 | 65 | 66 | /** (a >= 0) ? a : 0 */ 67 | public static final int clampPositive(int a) 68 | { 69 | return a & ~(a >> 31); // dep-chain=3 70 | } 71 | 72 | public static final int abs(int a) 73 | { 74 | // dep-chain=3 75 | int s = a >> 31; 76 | a ^= s; 77 | a -= s; 78 | return a; 79 | } 80 | 81 | public static final int min(int a, int b) 82 | { 83 | // dep-chain=4 84 | a -= b; 85 | a &= (a >> 31); 86 | a += b; 87 | 88 | return a; 89 | } 90 | 91 | /** */ 92 | public static final int max(int a, int b) 93 | { 94 | // dep-chain=4 95 | a -= b; 96 | a &= ~(a >> 31); 97 | a += b; 98 | 99 | return a; 100 | } 101 | 102 | /** (a>31) & (c^d))^d; 107 | } 108 | 109 | public static final int parity(int x) 110 | { 111 | if (hasPopCount) 112 | return Integer.bitCount(x) & 1; 113 | 114 | int p; 115 | x = (x ^ (x >>> 1)); 116 | x = (x ^ (x >>> 2)) & 0x11111111; 117 | x = x*0x11111111; 118 | p = (x >> 28) & 1; 119 | 120 | return p; 121 | } 122 | 123 | /** 124 | * Returns 1 for positive, 0 for zero and -1 125 | * for negative inputs. 126 | */ 127 | public static final int sign(int a) 128 | { 129 | return (-a >>> 31) | (a >> 31); 130 | } 131 | 132 | /** 133 | * Returns 1 for input greater than zero, otherwise 0. 134 | */ 135 | public static final int sgn(int a) 136 | { 137 | return (-a >>> 31); 138 | } 139 | 140 | /** 141 | * Returns -1 for input greater than zero, otherwise 0. 142 | */ 143 | public static final int sgnMask(int a) 144 | { 145 | return (-a >> 31); 146 | } 147 | 148 | /** 149 | * Returns 1 for input greater or equal to zero, otherwise 0. 150 | */ 151 | public static final int sgnz(int a) 152 | { 153 | return (~a >>> 31); 154 | } 155 | 156 | /** 157 | * Returns -1 for input greater or equal to zero, otherwise 0. 158 | */ 159 | public static final int sgnzMask(int a) 160 | { 161 | return (~a >> 31); 162 | } 163 | 164 | /** ceiling(log2(x)) */ 165 | public static final int ceilingLog2(int x) 166 | { 167 | return 32-Integer.numberOfLeadingZeros(x-1); 168 | } 169 | 170 | /** floor(log2(x)) */ 171 | public static final int floorLog2(int x) 172 | { 173 | return 31-Integer.numberOfLeadingZeros(x); 174 | } 175 | 176 | /** Returns next integer with the same population count as 'x'. */ 177 | public static final int nextPop(int x) 178 | { 179 | int a = x & -x; 180 | int b = x + a; 181 | int c = x ^ b; 182 | int d = (2 + Integer.numberOfTrailingZeros(x)); 183 | return b | (c >>> d); 184 | } 185 | 186 | /** Computes 'a' such that a*x = 1 for odd integers 'x' */ 187 | public static final int modInverse(int x) 188 | { 189 | // newton's 190 | int r = (x*x)+x - 1; 191 | int t = x*r; 192 | r *= 2-t; t = x*r; 193 | r *= 2-t; t = x*r; 194 | r *= 2-t; 195 | return r; 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/roquen/wiki/RngDiscreteDist.java: -------------------------------------------------------------------------------- 1 | package roquen.wiki; 2 | 3 | /** 4 | * Example of discrete distribution generation by directly 5 | * using the PDF (linear search) and CDF (binary search). 6 | * These are not practical implementations. 7 | *

    8 | * 9 | */ 10 | public enum RngDiscreteDist 11 | { 12 | ; 13 | 14 | static java.util.Random rng = java.util.concurrent.ThreadLocalRandom.current(); 15 | static float weightSum; 16 | static int[] weights; 17 | static float[] pdf; // 18 | static float[] cdf; // 19 | static float[] lhisto; // 20 | static float[] bhisto; // 21 | 22 | // 23 | @SuppressWarnings("boxing") 24 | public static void generationTime() 25 | { 26 | int e = weights.length; 27 | float s = 0; 28 | float t; 29 | 30 | // 1) Walk through the list create both a 31 | // pdf and cdf. pdf is used for a 32 | // linear search and cdf for binary. 33 | for(int i=0; i 0); 67 | 68 | return i-1; 69 | } 70 | 71 | // Generate by a binary search using 72 | // the CDF. 73 | public static int binary() 74 | { 75 | float u = rng.nextFloat(); 76 | int len = cdf.length - 1; 77 | int i = 0; 78 | 79 | if (u > cdf[0]) { 80 | int j = len; 81 | 82 | while (i < j) { 83 | int m = (i + j) >>> 1; 84 | if (u > cdf[m]) 85 | i = m + 1; 86 | else 87 | j = m; 88 | } 89 | } 90 | 91 | return i; 92 | } 93 | 94 | @SuppressWarnings("boxing") 95 | public static void main(String[] args) 96 | { 97 | int argc = args.length; 98 | int len; 99 | 100 | // 1) based on input method either create or 101 | // load in a list of weights. At the same 102 | // time we'll also sum them up. 103 | 104 | if (argc >= 3) { 105 | // three or more: use input as explicit list of weights 106 | len = argc; 107 | weights = new int[len]; 108 | 109 | for(int i=0; i>>1); 17 | } 18 | 19 | /** 20 | * Returns 'a' multiplied by the sign of 'b'. 21 | *

    22 | * equivalent to: {@linkplain java.lang.Math#copySign(double,double) copySign}(1,b)*a 23 | */ 24 | public static final double mulSign(double a, double b) 25 | { 26 | long sb = (Double.doubleToRawLongBits(b) >>> 63) << 63; 27 | long ia = (Double.doubleToRawLongBits(a) ^ sb); 28 | return Double.longBitsToDouble(ia); 29 | } 30 | 31 | /** 32 | * Returns the smallest of the two inputs without special casing for NaNs and -0 33 | *

     34 |    * min(-0, 0)  = -0
     35 |    * min( 0,-0)  =  0
     36 |    * min(NaN, x) =  x
     37 |    * min(x, NaN) =  NaN
     38 |    * 
    39 | */ 40 | public static final double min(double a, double b) 41 | { 42 | return (a <= b) ? a : b; 43 | } 44 | 45 | /** 46 | * Returns the smaller of 'a' and 'b'. 47 | *

    48 | * No special casing -0, only returns NaN if both 49 | * inputs are NaN. 50 | *

     51 |    * minNum(-0, 0)  = -0
     52 |    * minNum( 0,-0)  =  0
     53 |    * minNum(NaN, x) =  x
     54 |    * minNum(x, NaN) =  x
     55 |    * 
    56 | */ 57 | public static final double minNum(double a, double b) 58 | { 59 | if (b >= a) return a; // a <= b and neither are NaN 60 | if (b == b) return b; // b isn't NaN 61 | return a; // both are NaN 62 | } 63 | 64 | /** 65 | * Returns the largest of the two inputs without special casing for NaNs and -0 66 | *
     67 |    * max(-0, 0)  = -0
     68 |    * max( 0,-0)  =  0
     69 |    * max(NaN, x) =  x
     70 |    * max(x, NaN) =  NaN
     71 |    * 
    72 | */ 73 | public static final double max(double a, double b) 74 | { 75 | return (a >= b) ? a : b; 76 | } 77 | 78 | /** 79 | * Returns the larger of 'a' and 'b'. 80 | *

    81 | * No special casing -0, only returns NaN if both 82 | * inputs are NaN. 83 | *

     84 |    * maxNum(-0, 0)  =  0
     85 |    * maxNum( 0,-0)  = -0
     86 |    * maxNum(NaN, x) =  x
     87 |    * maxNum(x, NaN) =  x
     88 |    * 
    89 | */ 90 | public static final double maxNum(double a, double b) 91 | { 92 | if (a <= b) return b; // b >= a and neither are NaN 93 | if (a == a) return a; // a isn't NaN 94 | return b; 95 | } 96 | 97 | /** 98 | *

    99 | * NEVER CALL ME 100 | */ 101 | /* 102 | public static final double asin(double a) 103 | { 104 | // range reduction 105 | long ia = Double.doubleToRawLongBits(a); 106 | long aa = (ia<<1)>>>1; 107 | long sa = B_ONE | (ia^aa); 108 | double d = Double.longBitsToDouble(aa); 109 | double m = Double.longBitsToDouble(sa); 110 | 111 | // atan(+,+); 112 | d = Math.atan2(d, Math.sqrt((1.0+d)*(1.0-d))); 113 | 114 | return m*d; 115 | } 116 | */ 117 | 118 | // HotSpot doesn't give access to various SIMD opcode sets 119 | // rsqrt approximations. 120 | 121 | /** Make an initial guess for 1/sqrt(x) using Matthew Robertson's "magic" number */ 122 | public static final double rsqrtGuess(double x) 123 | { 124 | long i = 0x5fe6eb50c7b537a9L - (Double.doubleToRawLongBits(x) >>> 1); 125 | double g = Double.longBitsToDouble(i); 126 | return g; 127 | } 128 | 129 | /** 130 | * Approximate 1/sqrt(x) from initial guess g using 131 | * 1 step of Newton's method. 132 | */ 133 | public static final double rsqrt_1(double x, double g) 134 | { 135 | double hx = x * 0.5; 136 | g = g*(1.5-hx*g*g); 137 | return g; 138 | } 139 | 140 | /** 141 | * Approximate 1/sqrt(x) from initial guess g using 142 | * 2 steps of Newton's method. 143 | */ 144 | public static final double rsqrt_2(double x, double g) 145 | { 146 | double hx = x * 0.5; 147 | g = g*(1.5-hx*g*g); 148 | g = g*(1.5-hx*g*g); 149 | return g; 150 | } 151 | 152 | /** 153 | * Approximate 1/sqrt(x) from initial guess g using 154 | * 3 step of Newton's method. 155 | */ 156 | public static final double rsqrt_3(double x, double g) 157 | { 158 | double hx = x * 0.5; 159 | g = g*(1.5-hx*g*g); 160 | g = g*(1.5-hx*g*g); 161 | g = g*(1.5-hx*g*g); 162 | return g; 163 | } 164 | 165 | /** 166 | * Returns the IEEE complaint bit format, converting any negative zero to zero. 167 | * Does not normalized NaNs. Intended for hashing. 168 | */ 169 | public static final long toBits(double x) 170 | { 171 | return Double.doubleToRawLongBits(0.0+x); 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /src/roquen/math/rng/discrete/AliasMethodFlat.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng.discrete; 2 | 3 | import roquen.math.rng.PRNG; 4 | 5 | /** 6 | * Example specialized version of {@link AliasMethod}. Flattens 7 | * the two internal arrays into a one. This will reduce the 8 | * number of memory-load stalls for expected access patterns. 9 | */ 10 | 11 | public class AliasMethodFlat extends DiscreteMethod 12 | { 13 | private final float[] data; 14 | private final int size; 15 | 16 | /** The range of the distribution. */ 17 | public int getSize() { 18 | return size; 19 | } 20 | 21 | private AliasMethodFlat(float[] d) 22 | { 23 | data = d; 24 | size = data.length >>> 1; 25 | } 26 | 27 | private static AliasMethodFlat make_(double[] w, double sum) 28 | { 29 | int len = w.length; 30 | double scale = len / sum; 31 | int[] ss = new int[len]; 32 | int[] ls = new int[len]; 33 | 34 | int si = 0; 35 | int li = 0; 36 | 37 | for (int i = 0; i != len; i++) { 38 | 39 | double p = w[i] = w[i] * scale; 40 | 41 | if (p > 1) 42 | ls[li++] = i; 43 | else 44 | ss[si++] = i; 45 | } 46 | 47 | float[] data = new float[len*2]; 48 | 49 | while (si != 0 && li != 0) { 50 | int ws = ss[--si]; 51 | int wl = ls[--li]; 52 | int id = ws<<1; 53 | 54 | data[id] = (float)w[ws]; 55 | data[id+1] = wl; 56 | w[wl] = (w[wl] + w[ws]) - 1; 57 | 58 | if (w[wl] > 1) 59 | ls[li++] = wl; 60 | else 61 | ss[si++] = wl; 62 | } 63 | 64 | while (si != 0) data[ss[--si]<<1] = 1; 65 | while (li != 0) data[ls[--li]<<1] = 1; 66 | 67 | return new AliasMethodFlat(data); 68 | } 69 | 70 | public static AliasMethodFlat make(double[] w) 71 | { 72 | int len = w.length; 73 | double sum = 0; 74 | double[] sa = new double[len]; 75 | 76 | // Compute the total weight of the input set and 77 | // copy the original array. 78 | for (int i = 0; i != len; i++) { 79 | double wi = w[i]; 80 | 81 | if (wi < 0) 82 | throw new IllegalArgumentException("AliasMethod: negative weight"); 83 | 84 | sa[i] = wi; 85 | sum += wi; 86 | } 87 | 88 | return make_(sa, sum); 89 | } 90 | 91 | /** */ 92 | public static AliasMethodFlat make(float[] w) 93 | { 94 | int len = w.length; 95 | double sum = 0; 96 | double[] sa = new double[len]; 97 | 98 | // Compute the total weight of the input set and 99 | // copy the original array. 100 | for (int i = 0; i != len; i++) { 101 | double wi = w[i]; 102 | 103 | if (wi < 0) 104 | throw new IllegalArgumentException("AliasMethod: negative weight"); 105 | 106 | sa[i] = wi; 107 | sum += wi; 108 | } 109 | 110 | return make_(sa, sum); 111 | } 112 | 113 | /** */ 114 | public static AliasMethodFlat make(int[] w) 115 | { 116 | int len = w.length; 117 | double sum = 0; 118 | double[] sa = new double[len]; 119 | 120 | // Compute the total weight of the input set and 121 | // copy the original array. 122 | for (int i = 0; i != len; i++) { 123 | double wi = w[i]; 124 | 125 | if (wi < 0) 126 | throw new IllegalArgumentException("AliasMethod: negative weight"); 127 | 128 | sa[i] = wi; 129 | sum += wi; 130 | } 131 | 132 | return make_(sa, sum); 133 | } 134 | 135 | 136 | /** Returns the next value in the distribution. */ 137 | @Override 138 | public int nextInt(PRNG rng) 139 | { 140 | int v = rng.nextIntFast(size); 141 | int i = v+v; 142 | float p = rng.nextFloat(); 143 | return p <= data[i] ? v : (int)data[i+1]; 144 | } 145 | 146 | /* 147 | @SuppressWarnings("boxing") 148 | public static void main(String[] args) 149 | { 150 | roquen.math.rng.XorStar64 rng = new roquen.math.rng.XorStar64(1); 151 | 152 | for(int t=0; t<13; t++) { 153 | int len = rng.nextInt(5)+2; 154 | double[] w = new double[len]; 155 | int[] h = new int[len]; 156 | 157 | double sum = 0; 158 | for(int i=0;i 9 | * This hash has a flaw (link) 10 | * which is very unlikely to be a concern. 11 | *

    12 | * Wikipedia 13 | */ 14 | 15 | // TODO: nothing has been testing...just quickly banged out 16 | public enum MurmurHash2 17 | { 18 | ; 19 | 20 | private static final int M = 0x5bd1e995; 21 | 22 | /** A starting value for hash. */ 23 | public static final int hashInit() 24 | { 25 | return 0x9747b28c; 26 | } 27 | 28 | /** */ 29 | public static final int hashMakeSeed(int h) 30 | { 31 | return hashComplete(hashAdd(hashInit(),h)); 32 | } 33 | 34 | /** */ 35 | public static final int hashMakeSeed(long h) 36 | { 37 | return hashComplete(hashAdd(hashInit(),h)); 38 | } 39 | 40 | /** Final mixing of the hash */ 41 | public static final int hashComplete(int h) 42 | { 43 | h ^= h >>> 13; h *= M; h ^= h >>> 15; 44 | 45 | return h; 46 | } 47 | 48 | /** */ 49 | public static final int hashAdd(int h, int x) 50 | { 51 | x *= M; x ^= x >>> 24; x *= M; 52 | 53 | h ^= x; h *= M; 54 | 55 | return h; 56 | } 57 | 58 | /** */ 59 | public static final int hashAdd(int h, int x, int y) 60 | { 61 | x *= M; x ^= x >>> 24; x *= M; 62 | y *= M; y ^= y >>> 24; y *= M; 63 | 64 | h ^= x; h *= M; h ^= y; 65 | 66 | return h; 67 | } 68 | 69 | /** */ 70 | public static final int hashAdd(int h, int x, int y, int z) 71 | { 72 | x *= M; x ^= x >>> 24; x *= M; 73 | y *= M; y ^= y >>> 24; y *= M; 74 | z *= M; z ^= z >>> 24; z *= M; 75 | 76 | h ^= x; h *= M; 77 | h ^= y; h *= M; 78 | h ^= z; h *= M; 79 | 80 | return h; 81 | } 82 | 83 | /** */ 84 | public static final int hashAdd(int h, int x, int y, int z, int w) 85 | { 86 | x *= M; x ^= x >>> 24; x *= M; 87 | y *= M; y ^= y >>> 24; y *= M; 88 | z *= M; z ^= z >>> 24; z *= M; 89 | w *= M; w ^= w >>> 24; w *= M; 90 | 91 | h ^= x; h *= M; 92 | h ^= y; h *= M; 93 | h ^= z; h *= M; 94 | 95 | return h; 96 | } 97 | 98 | /** */ 99 | public static final int hashAdd(int h, long x) 100 | { 101 | return hashAdd(h, (int)x, (int)(x>>>32)); 102 | } 103 | 104 | /** */ 105 | public static final int hashAdd(int h, long x, long y) 106 | { 107 | return hashAdd(h, (int)x, (int)(x>>>32), 108 | (int)y, (int)(y>>>32)); 109 | } 110 | 111 | /** */ 112 | public static final int hashAdd(int h, float x) 113 | { 114 | return hashAdd(h, toBits(x)); 115 | } 116 | 117 | /** */ 118 | public static final int hashAdd(int h, float x, float y) 119 | { 120 | return hashAdd(h, toBits(x), toBits(y)); 121 | } 122 | 123 | /** */ 124 | public static final int hashAdd(int h, float x, float y, float z) 125 | { 126 | return hashAdd(h, toBits(x), toBits(y), toBits(z)); 127 | } 128 | 129 | /** */ 130 | public static final int hashAdd(int h, float x, float y, float z, float w) 131 | { 132 | return hashAdd(h, toBits(x), toBits(y), toBits(z), toBits(w)); 133 | } 134 | 135 | /** */ 136 | public static final int hashAdd(int h, double x) 137 | { 138 | return hashAdd(h, toBits(x)); 139 | } 140 | 141 | /** */ 142 | public static final int hashAdd(int h, double x, double y) 143 | { 144 | return hashAdd(h, toBits(x), toBits(y)); 145 | } 146 | 147 | /** */ 148 | public static final int hashAdd(int h, int[] a) 149 | { 150 | int c = a.length; 151 | int i = 0; 152 | 153 | while(c >= 4) { 154 | h = hashAdd(h, a[i], a[i+1], a[i+2], a[i+3]); 155 | i += 4; 156 | c -= 4; 157 | } 158 | 159 | while(i < c) 160 | h = hashAdd(h, a[i++]); 161 | 162 | return h; 163 | } 164 | 165 | /** */ 166 | public static final int hashAdd(int h, float[] a) 167 | { 168 | int c = a.length; 169 | int i = 0; 170 | 171 | while(c >= 4) { 172 | h = hashAdd(h, a[i], a[i+1], a[i+2], a[i+3]); 173 | i += 4; 174 | c -= 4; 175 | } 176 | 177 | while(i < c) 178 | h = hashAdd(h, a[i++]); 179 | 180 | return h; 181 | } 182 | 183 | /** */ 184 | public static final int hashAdd(int h, long[] a) 185 | { 186 | int c = a.length; 187 | int i = 0; 188 | 189 | while(c >= 2) { 190 | h = hashAdd(h, a[i], a[i+1]); 191 | i += 2; 192 | c -= 2; 193 | } 194 | 195 | if (i != c) 196 | h = hashAdd(h, a[i]); 197 | 198 | return h; 199 | } 200 | 201 | /** */ 202 | public static final int hashAdd(int h, double[] a) 203 | { 204 | int c = a.length; 205 | int i = 0; 206 | 207 | while(c >= 2) { 208 | h = hashAdd(h, a[i], a[i+1]); 209 | i += 2; 210 | c -= 2; 211 | } 212 | 213 | if (i != c) 214 | h = hashAdd(h, a[i]); 215 | 216 | return h; 217 | } 218 | } 219 | 220 | -------------------------------------------------------------------------------- /src/roquen/math/rng/discrete/AliasMethodFixedPoint.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng.discrete; 2 | 3 | import roquen.math.rng.PRNG; 4 | 5 | /** 6 | * Example specialized version of {@link AliasMethod}. Flattens 7 | * the two internal arrays into a one like {@link AliasMethodFlat} 8 | * and stores probabilities in fixed point. Drops a conversion 9 | * to floating point and a multiple in each {@link #nextInt(PRNG)} 10 | */ 11 | public class AliasMethodFixedPoint extends DiscreteMethod 12 | { 13 | // 'nextInt' could loose the shift on the computation of 'p' 14 | // by either using unsigned comparisons of JDK8 or by biasing 15 | // the probability table entries (equivalent to unsigned comparisons). 16 | // this additionally improves the fixed-point representation by 17 | // giving it one more bit to work with. 18 | 19 | private final int[] data; 20 | private final int size; 21 | 22 | /** The range of the distribution. */ 23 | public int getSize() { 24 | return size; 25 | } 26 | 27 | private AliasMethodFixedPoint(int[] d) 28 | { 29 | data = d; 30 | size = data.length >>> 1; 31 | } 32 | 33 | private static AliasMethodFixedPoint make_(double[] w, double sum) 34 | { 35 | int len = w.length; 36 | double scale = len / sum; 37 | int[] ss = new int[len]; 38 | int[] ls = new int[len]; 39 | 40 | int si = 0; 41 | int li = 0; 42 | 43 | for (int i = 0; i != len; i++) { 44 | 45 | double p = w[i] = w[i] * scale; 46 | 47 | if (p > 1) 48 | ls[li++] = i; 49 | else 50 | ss[si++] = i; 51 | } 52 | 53 | int[] data = new int[len*2]; 54 | 55 | while (si != 0 && li != 0) { 56 | int ws = ss[--si]; 57 | int wl = ls[--li]; 58 | int id = ws<<1; 59 | 60 | data[id] = (int)(w[ws]*Integer.MAX_VALUE); // see 'bias' above 61 | data[id+1] = wl; 62 | w[wl] = (w[wl] + w[ws]) - 1; 63 | 64 | if (w[wl] > 1) 65 | ls[li++] = wl; 66 | else 67 | ss[si++] = wl; 68 | } 69 | 70 | while (si != 0) data[ss[--si]<<1] = Integer.MAX_VALUE; // see 'bias' above 71 | while (li != 0) data[ls[--li]<<1] = Integer.MAX_VALUE; // see 'bias' above 72 | 73 | return new AliasMethodFixedPoint(data); 74 | } 75 | 76 | public static AliasMethodFixedPoint make(double[] w) 77 | { 78 | int len = w.length; 79 | double sum = 0; 80 | double[] sa = new double[len]; 81 | 82 | // Compute the total weight of the input set and 83 | // copy the original array. 84 | for (int i = 0; i != len; i++) { 85 | double wi = w[i]; 86 | 87 | if (wi < 0) 88 | throw new IllegalArgumentException("AliasMethod: negative weight"); 89 | 90 | sa[i] = wi; 91 | sum += wi; 92 | } 93 | 94 | return make_(sa, sum); 95 | } 96 | 97 | /** */ 98 | public static AliasMethodFixedPoint make(float[] w) 99 | { 100 | int len = w.length; 101 | double sum = 0; 102 | double[] sa = new double[len]; 103 | 104 | // Compute the total weight of the input set and 105 | // copy the original array. 106 | for (int i = 0; i != len; i++) { 107 | double wi = w[i]; 108 | 109 | if (wi < 0) 110 | throw new IllegalArgumentException("AliasMethod: negative weight"); 111 | 112 | sa[i] = wi; 113 | sum += wi; 114 | } 115 | 116 | return make_(sa, sum); 117 | } 118 | 119 | /** */ 120 | public static AliasMethodFixedPoint make(int[] w) 121 | { 122 | int len = w.length; 123 | double sum = 0; 124 | double[] sa = new double[len]; 125 | 126 | // Compute the total weight of the input set and 127 | // copy the original array. 128 | for (int i = 0; i != len; i++) { 129 | double wi = w[i]; 130 | 131 | if (wi < 0) 132 | throw new IllegalArgumentException("AliasMethod: negative weight"); 133 | 134 | sa[i] = wi; 135 | sum += wi; 136 | } 137 | 138 | return make_(sa, sum); 139 | } 140 | 141 | 142 | /** Returns the next value in the distribution. */ 143 | @Override 144 | public int nextInt(PRNG rng) 145 | { 146 | int v = rng.nextIntFast(size); 147 | int i = v+v; 148 | int p = rng.nextInt()>>>1; // see 'bias' above 149 | return p <= data[i] ? v : data[i+1]; // see 'bias' above 150 | } 151 | 152 | /* 153 | @SuppressWarnings("boxing") 154 | public static void main(String[] args) 155 | { 156 | roquen.math.rng.XorStar64 rng = new roquen.math.rng.XorStar64(1); 157 | 158 | for(int t=0; t<13; t++) { 159 | int len = rng.nextInt(5)+2; 160 | double[] w = new double[len]; 161 | int[] h = new int[len]; 162 | 163 | double sum = 0; 164 | for(int i=0;iUser Variables 8 | *

    9 | * User variables allow designers to assign additional data to the various 10 | * exposed {@link GameObject}. This allows designing scripts which are 11 | * data-driven and building of functionality of which the code base is not 12 | * specifically aware. 13 | *

    14 | * These user variables are logically typeless, that is to 15 | * say that no specific type associated with a given variable. At any point 16 | * in time the active type will be that of the most recent assignment. Any 17 | * unassigned variable query will return a default value of that type and 18 | * any existing variable which is assigned this default value will automatically 19 | * be deleted. 20 | *

    21 | * 22 | */ 23 | 24 | // NOTES: 25 | // 1) This example shows an implementation which stores dvars with their 26 | // associated object. Without change to "user" code this can be flipped 27 | // to having a single storage for all containers. 28 | 29 | abstract class GameObject> 30 | { 31 | //*** 32 | static final String EMPTY_STRING = ""; 33 | 34 | /** Transform any nulls into EMPTY_STRING */ 35 | static final String stringFilter(String s) 36 | { 37 | if (s != null) return s; 38 | return EMPTY_STRING; 39 | } 40 | 41 | 42 | //*** dynamic variable support stuff 43 | HashMap dvars = null; 44 | 45 | /** Returns the variable of the specified name and NILL if it doesn't exist. */ 46 | public final UserVar getVar(String name) 47 | { 48 | if (dvars != null) { 49 | UserVar v = dvars.get(name); 50 | 51 | if (v != null) 52 | return v; 53 | } 54 | 55 | return UserVar.NILL; 56 | } 57 | 58 | /** 59 | * Returns true if there is a dynamic variable of the 60 | * specified name defined. 61 | */ 62 | public final boolean isVarDefined(String name) 63 | { 64 | return getVar(name) != UserVar.NILL; 65 | } 66 | 67 | /** 68 | * Returns the value of the variable as an integer. 69 | *

    70 | * If the name is currently assigned to a float then 71 | * the result is the same as: (int)getFloat(name). In 72 | * all other cases, including undefined, the result is zero. 73 | */ 74 | public final int getInt(String name) 75 | { 76 | return getVar(name).getInt(); 77 | } 78 | 79 | /** 80 | * Returns the value of the variable as a float. 81 | *

    82 | * If the name is currently assigned to a int then 83 | * the result is the same as: getInt(name). In 84 | * all other cases, including undefined, the result is zero. 85 | */ 86 | public final float getFloat(String name) 87 | { 88 | return getVar(name).getFloat(); 89 | } 90 | 91 | /** 92 | * Return the value of the variable as a {@link Entity}. 93 | *

    94 | * If the variable is question is not entity or is 95 | * undefined, then the result is {@link Entity.NILL}. 96 | */ 97 | public final Entity getEntity(String name) 98 | { 99 | return getVar(name).getEntity(); 100 | } 101 | 102 | /** 103 | * Returns the value of the variable as a {@link String}. 104 | *

    105 | * If the variable is currently assigned an integer or a float, then 106 | * the result is that value converted into a string. In all other 107 | * cases, including undefined, the result is an empty string. 108 | */ 109 | public final String getString(String name) 110 | { 111 | return getVar(name).getString(); 112 | } 113 | 114 | /** 115 | * Unconditionally removes any variable of the specified name. In 116 | * the container is made empty, the storage is automatically removed. 117 | */ 118 | private final void deleteVar(String name) 119 | { 120 | if (dvars != null) { 121 | dvars.remove(name); 122 | 123 | if (dvars.size() != 0) 124 | return; 125 | 126 | dvars = null; 127 | } 128 | } 129 | 130 | private final void setVar(String name, UserVar value) 131 | { 132 | if (dvars == null) dvars = new HashMap<>(); 133 | dvars.put(name, value); 134 | } 135 | 136 | // NOTE: All the sets could be optimized. Such as not creating 137 | // a new UserVar.TYPE object if one already exists and is of 138 | // the same type. Additionally if the new value if a different 139 | // type in int vs. float from current but is perfectly 140 | // representable in current, then current type could be used. 141 | 142 | /** 143 | * Sets or creates a dynamic variable with the specified name and value. 144 | *

    145 | * setInt(0) automatically deletes. 146 | */ 147 | public final void setInt(String name, int value) 148 | { 149 | if (value != 0) 150 | setVar(name, new UserVar.INT(value)); 151 | else 152 | deleteVar(name); 153 | } 154 | 155 | /** 156 | * Sets or creates a dynamic variable with the specified name and value. 157 | *

    158 | * setFloat(0) automatically deletes. 159 | */ 160 | public final void setFloat(String name, float value) 161 | { 162 | if (value != 0) 163 | setVar(name, new UserVar.FLOAT(value)); 164 | else 165 | deleteVar(name); 166 | } 167 | 168 | /** 169 | * Sets or creates a dynamic variable with the specified name and value. 170 | *

    171 | * setEntity(null) automatically deletes. 172 | */ 173 | public final void setEntity(String name, Entity value) 174 | { 175 | if (value != null && value != Entity.NILL) 176 | setVar(name, new UserVar.ENTITY(value)); 177 | else 178 | deleteVar(name); 179 | } 180 | 181 | /** 182 | * Sets or creates a dynamic variable with the specified name and value. 183 | *

    184 | * setString(null) automatically deletes. 185 | */ 186 | public final void setString(String name, String value) 187 | { 188 | if (value != null && value.length() != 0) 189 | setVar(name, new UserVar.STRING(value)); 190 | else 191 | deleteVar(name); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/roquen/math/seq/TestIntSequence.java: -------------------------------------------------------------------------------- 1 | package roquen.math.seq; 2 | 3 | /** 4 | * Integer array filling and modifying routines for testing. It uses a 5 | * static instance of a PRNG and therefore shouldn't be used concurrently 6 | * by multiple threads. 7 | */ 8 | public enum TestIntSequence 9 | { 10 | ; 11 | private static roquen.math.rng.XorStar64 rng = new roquen.math.rng.XorStar64(); 12 | 13 | public static long getSeed() { return rng.getSeed(); } 14 | public static void setSeed(long seed) { rng.setSeed(seed); } 15 | 16 | // 17 | 18 | /** 19 | * Modify data using a uniform distribution. 20 | *

    21 | * if update is false then logically: 22 | * data[i] = i initialization is performed. 23 | *

    24 | * data[i] += rng(min,max) 25 | *

    26 | * where rng(min,max) is uniform value on [min,max) 27 | */ 28 | public static void uniform(int[] data, boolean update, int min, int max) 29 | { 30 | int d = max-min; 31 | int e = data.length; 32 | 33 | if (update) { 34 | for(int i=0; idata using a geometric distribution. 45 | *

    46 | * if update is false then logically: 47 | * data[i]=i initialization is performed. 48 | *

    49 | * The modification is we start a counter at zero, then 50 | * repeated flip a coin. If we get "tails" we increment 51 | * the counter and repeat until we get "heads". Once 52 | * we have a count we again flip a coin to decided if 53 | * we want to negate the value which is then applied 54 | * to the array's value. 55 | * @see {@link roquen.math.rng.PRNG#nextToss()} 56 | */ 57 | public static void geometric(int[] data, boolean update) 58 | { 59 | int e = data.length; 60 | 61 | if (update) { 62 | for(int i=0; i> 31; 65 | d ^= s; 66 | d -= s; 67 | 68 | data[i] += d; 69 | } 70 | } 71 | else { 72 | for(int i=0; i> 31; 75 | d ^= s; 76 | d -= s; 77 | 78 | data[i] = i + d; 79 | } 80 | } 81 | } 82 | 83 | /** 84 | * Modify data using a poisson distribution. 85 | *

    86 | * if update is false then logically: 87 | * data[i]=i initialization is performed. 88 | *

    89 | * At each element a Poisson distribution is computed 90 | * followed by a coin flip to determine if the value 91 | * is to be negated the is added to the element. 92 | * @see {@link roquen.math.rng.PRNG#nextPoisson(float)} 93 | */ 94 | public static void poisson(int[] data, float mean, boolean update) 95 | { 96 | int e = data.length; 97 | float emean = (float)Math.exp(-mean); 98 | 99 | if (update) { 100 | for(int i=0; i> 31; 103 | d ^= s; 104 | d -= s; 105 | 106 | data[i] += d; 107 | } 108 | } 109 | else { 110 | for(int i=0; i> 31; 113 | d ^= s; 114 | d -= s; 115 | 116 | data[i] = i + d; 117 | } 118 | } 119 | } 120 | 121 | private static void swapL(int[] data, int a, int b) 122 | { 123 | int t = data[a]; 124 | data[a] = data[b]; 125 | data[b] = t; 126 | } 127 | 128 | /** 129 | * Walks 'data' in order. With a probability of 'prob' swaps the 130 | * current element with the one up to 'dist' forward (uniformly 131 | * chosen). 132 | */ 133 | public static void hammingSwapUniform(int[] data, int dist, float prob) 134 | { 135 | int e = data.length; 136 | 137 | for(int i=0; i 0) { 160 | b += i; 161 | if (b < e) 162 | swapL(data, i, b); 163 | } 164 | } 165 | } 166 | 167 | 168 | /** 169 | * Swaps 'n' entry pairs in data chosen uniformly 170 | * from its size. 171 | */ 172 | public static void swapN(int[] data, int n) 173 | { 174 | int e = data.length; 175 | 176 | for(int i=0; i>> c; 194 | data[i] = d; 195 | } 196 | } 197 | 198 | /* 199 | public static void main(String[] args) { 200 | int len = 22; 201 | int run = 10; 202 | int[] data = new int[len]; 203 | 204 | for(int i=0; i 16 | * Implementation is classic building a CDF (partitioning the 17 | * range [0,1] into intervals), generate a random number on 18 | * [0,1) and find the interval containing the number by 19 | * binary search and the associated value is the result. 20 | * There's a twist (again classic) is that the range is split 21 | * into two (see code) for better representation. 22 | *

    23 | * 24 | */ 25 | public class RandomSelect 26 | { 27 | /** cumulative probabilities of the entries */ 28 | private final float[] cdf; 29 | 30 | /** table of entries */ 31 | private final E[] data; 32 | 33 | /** cdf[median-1] < 1/2 <= cdf[median] */ 34 | private final int median; 35 | 36 | /** 37 | *

    38 | * This class is not thread-safe. 39 | */ 40 | 41 | public static class Builder 42 | { 43 | /** list of weighted entries */ 44 | ArrayList> w = new ArrayList<>(); 45 | 46 | // temp storage for init -- not thread safe anyway 47 | private int median; 48 | 49 | 50 | /** Adds an entry. */ 51 | public void add(E data, float weight) 52 | { 53 | if (weight > 0) { 54 | w.add(new FloatPair<>(data, weight)); 55 | return; 56 | } 57 | 58 | // TODO: warning/error for invalid weight 59 | } 60 | 61 | // all temp hack 62 | private float[] init(float[] pr, float s) { 63 | // temp hacks 64 | int len = pr.length; 65 | float[] cdf = new float[len]; 66 | float curr; 67 | int max = len - 1; 68 | curr = cdf[0] = s*pr[0]; 69 | 70 | int i = 0; 71 | 72 | // For numeric precision the cumulative probabilities are broken 73 | // into two regions. The lower part of the array stores forward 74 | // up to 1/2. The variable 'median' notes this position in the 75 | // array. The upper part stores backward. 76 | 77 | while (i < max && curr < 0.5) { 78 | i++; 79 | cdf[i] = curr = (s*pr[i] + curr); 80 | } 81 | 82 | median = i; 83 | 84 | cdf[max] = curr = s*pr[max]; 85 | 86 | i = max-1; 87 | 88 | while (i > median) { 89 | cdf[i] = curr = (s*pr[i] + curr); 90 | i--; 91 | } 92 | 93 | return cdf; 94 | } 95 | 96 | /** */ 97 | public RandomSelect build() 98 | { 99 | // NOTE: The building process makes no nods to performance 100 | // this could be greatly improved. 101 | int len = w.size(); 102 | int i = 0; 103 | float totalW = 0.f; 104 | float[] cdf; 105 | E[] entries = Generics.newArray(len); 106 | 107 | FloatPair.sort(w); 108 | 109 | float[] p = new float[len]; 110 | 111 | for(FloatPair e : w) { 112 | p[i] = e.value; 113 | entries[i++] = e.data; 114 | totalW += e.value; 115 | } 116 | 117 | totalW = 1.f/totalW; 118 | 119 | cdf = init(p, totalW); 120 | 121 | return new RandomSelect<>(cdf, entries, median); 122 | } 123 | 124 | /** Reset the builder to empty */ 125 | public void clear() 126 | { 127 | w.clear(); 128 | } 129 | 130 | } 131 | 132 | protected RandomSelect(float[] p, E[] v, int m) 133 | { 134 | cdf = p; 135 | data = v; 136 | median = m; 137 | } 138 | 139 | public static Builder getBuilder() 140 | { 141 | return new Builder<>(); 142 | } 143 | 144 | public int size() 145 | { 146 | return cdf.length; 147 | } 148 | 149 | /** 150 | * Transform uniform value 'u' into the represented distribution. 151 | *

    152 | * Computational time is O(ln n). 153 | */ 154 | public E eval(float u) 155 | { 156 | int i, j, k; 157 | int max = cdf.length - 1; 158 | 159 | // cumulative probabilities are broken into two ranges. 160 | if (u <= cdf[median]) { 161 | 162 | // TODO: flip 163 | if (u <= cdf[0]) 164 | return data[0]; 165 | 166 | i = 0; 167 | j = median - 0; 168 | 169 | while (i < j) { 170 | k = (i + j) >>> 1; 171 | if (u > cdf[k]) 172 | i = k + 1; 173 | else 174 | j = k; 175 | } 176 | } 177 | else { 178 | u = 1 - u; 179 | 180 | // TODO: flip 181 | if (u < cdf[max]) 182 | return data[max]; 183 | 184 | i = median + 1; 185 | j = max; 186 | 187 | while (i < j) { 188 | k = (i + j) >>> 1; 189 | if (u < cdf[k]) 190 | i = k + 1; 191 | else 192 | j = k; 193 | } 194 | i--; 195 | } 196 | 197 | return data[i]; 198 | } 199 | 200 | // debugging aid 201 | @Override 202 | public String toString() 203 | { 204 | StringBuffer sb = new StringBuffer(); 205 | int len = cdf.length; 206 | 207 | sb.append(getClass().getSimpleName()); 208 | sb.append('['); 209 | 210 | for(int i=0; i builder = RandomSelect.getBuilder(); 228 | 229 | builder.add("A", 1); 230 | builder.add("B", 1); 231 | builder.add("C", 1); 232 | builder.add("D", 1); 233 | builder.add("E", 1); 234 | builder.add("F", 1); 235 | builder.add("G", 2); 236 | 237 | RandomSelect select = builder.build(); 238 | System.out.println(select); 239 | 240 | java.util.concurrent.ThreadLocalRandom rng = java.util.concurrent.ThreadLocalRandom.current(); 241 | 242 | // no time based hashing for the default constructor ATM.. 243 | // equal to passing zero (as here). The first value is 244 | // then insured to be zero so even a tiny probability entry 245 | // will always appear first. 246 | roquen.math.lds.Sobol1D lds = new roquen.math.lds.Sobol1D(0); 247 | 248 | for(int i=0; i<10; i++) { 249 | float p0 = rng.nextFloat(); 250 | float p1 = lds.next(); 251 | String s0 = select.eval(p0); 252 | String s1 = select.eval(p1); 253 | System.out.println(s0 + ", " + s1); 254 | } 255 | } 256 | */ 257 | } 258 | -------------------------------------------------------------------------------- /src/roquen/pr0n/Dissembler.java: -------------------------------------------------------------------------------- 1 | package roquen.pr0n; 2 | 3 | import java.nio.file.*; 4 | 5 | import sun.misc.Unsafe; 6 | import static roquen.vm.UnsafeUtils.*; 7 | //import sun.misc.Unsafe; 8 | 9 | @SuppressWarnings("restriction") 10 | public enum Dissembler 11 | { 12 | ; 13 | 14 | /** 15 | * true if VM oop headers appear to be in the expected layout. 16 | *

    17 | */ 18 | public static final boolean hasExpectedOopHeaders = checkHeaders(); 19 | 20 | private static final boolean checkHeaders() 21 | { 22 | // expecting: 23 | // mark (native) = ADDRESS_SIZE 24 | // class (4 for 32/64+coop, 8 for 64) = ARRAY_OBJECT_INDEX_SCALE 25 | // length (if array = 4) 26 | // pad (if needed to align to 64-bits for 64-bit elements) 27 | 28 | int AS = Unsafe.ADDRESS_SIZE; // mark work (native pointer) 29 | int PS = Unsafe.ARRAY_OBJECT_INDEX_SCALE; // class pointer (perhaps compressed) 30 | 31 | // The 'length' entry for an array should match 32 | // 'value' of the single 32-bit field object 33 | Integer iw = null; 34 | 35 | for (int i=1; i<16; i++) { 36 | iw = Integer.valueOf(i); 37 | if (unsafe.getInt(iw, (long)(PS+AS)) != i) 38 | return false; 39 | } 40 | 41 | int c0 = unsafe.getInt(iw, 0L); 42 | long c1 = getAddress(Integer.class); 43 | System.out.println(c0 + " " + c1); 44 | System.identityHashCode(iw); 45 | c0 = unsafe.getInt(iw, 0L); 46 | c1 = getAddress(Integer.class); 47 | System.out.println(c0 + " " + c1); 48 | 49 | 50 | // T {0=32 bit, 1=64+coop, 2=64} 51 | @SuppressWarnings("unused") 52 | int t = ((Unsafe.ARRAY_OBJECT_INDEX_SCALE+Unsafe.ADDRESS_SIZE) >> 2)-2; 53 | 54 | // on 64-bit we expect all array headers to be 24/16 (for coop) 55 | // on 32-bit: 12 for 32-bit elements and smaller, otherwise 16 56 | 57 | /* 58 | for (int i=0; i<3; i++) { 59 | Integer t0 = Integer.valueOf(i); 60 | int ex = unsafe.getInt(t0, (long)(PS+AS)); 61 | System.out.println(ex); 62 | } 63 | */ 64 | 65 | // TODO: complete the check 66 | return true; 67 | } 68 | 69 | /** No protection ATM. Only call once, not thread-safe */ 70 | public static void loadDeceiver(String base) throws Exception 71 | { 72 | Path path = FileSystems.getDefault().getPath(base, "roquen", "pr0n", "Deceiver.class"); 73 | byte[] b = java.nio.file.Files.readAllBytes(path); 74 | 75 | // TODO: Not reliable. Just a quick hack 76 | for(int i=0; i> 4) & 0xf; 148 | char c = (t <= 9) ? (char)('0'+t) : (char)('A'+t-10); 149 | 150 | b.append(c); 151 | t = a[i] & 0xf; 152 | c = (t <= 9) ? (char)('0'+t) : (char)('A'+t-10); 153 | b.append(c); 154 | 155 | if (i == len) 156 | return b.append(']').toString(); 157 | 158 | b.append(", "); 159 | } 160 | } 161 | 162 | public static void main(String[] args) throws Exception 163 | { 164 | loadDeceiver("bin"); 165 | System.out.println(hasExpectedOopHeaders); 166 | 167 | Integer wi = Integer.valueOf(666); 168 | int[] zz = asI(wi); 169 | System.out.println(zz.length); 170 | 171 | java.util.ArrayList foo = new java.util.ArrayList<>(); 172 | java.util.ArrayList bar; 173 | 174 | //System.out.println("address size: " + Unsafe.ADDRESS_SIZE); 175 | //System.out.println(Unsafe.ARRAY_OBJECT_BASE_OFFSET); 176 | //System.out.println(Unsafe.ARRAY_OBJECT_INDEX_SCALE); 177 | 178 | // allocate some space to remove 179 | for(int i=0; i<50000; i++) { 180 | foo.add(new byte[1024]); 181 | } 182 | 183 | // now the arrays we're going to lie about. 184 | byte[] ba = new byte[16]; 185 | int[] ia = asI(ba);//Deceiver.asI(ba); 186 | float[] fa = asF(ba);//Deceiver.asF(ba); 187 | //long x = getAddress(ba); 188 | 189 | //System.out.println(Long.toHexString(x)); 190 | 191 | ia[0] = 0xa; 192 | fa[3] = 1.f; 193 | 194 | System.out.println(hexString(ba)); 195 | 196 | do { 197 | foo.remove(foo.size()-1); // free up some space 198 | 199 | System.out.println(hexString(ba)); 200 | System.gc(); // try to request a full GC. 201 | 202 | // just in case that didn't work let's fill up the heap 203 | bar = new java.util.ArrayList<>(); 204 | try { 205 | while(true) { 206 | bar.add(new byte[0xFFFFFF]); 207 | } 208 | } 209 | catch(Error e) { 210 | // 211 | } 212 | bar.clear(); 213 | 214 | if ((Object)ia != (Object)ba) { System.out.println("x"); } 215 | 216 | ia[0]++; 217 | ia[1]++; 218 | ia[2]++; 219 | fa[3] += .5f; 220 | System.out.println(hexString(ba) 221 | + " " + Long.toHexString(getAddress(ba)) 222 | + " " + Long.toHexString(getAddress(ba)) 223 | ); 224 | } while(!foo.isEmpty()); 225 | 226 | //System.out.println(x); 227 | } 228 | 229 | 230 | 231 | 232 | 233 | } 234 | -------------------------------------------------------------------------------- /src/roquen/math/rng/discrete/AliasMethod.java: -------------------------------------------------------------------------------- 1 | package roquen.math.rng.discrete; 2 | 3 | import roquen.math.rng.PRNG; 4 | 5 | /** 6 | * An instance of this class represents a fixed arbitrary discrete 7 | * probability distribution function via Vose's alias method. 8 | *

    9 | * Specifically a set of 'n' weights are provided at generation 10 | * time. These values are converted into probabilities and an 11 | * efficient representation is created to return a random integer 12 | * on the range [0,n) with these probabilities. Generating the 13 | * data tables requires linear time and once constructed performing 14 | * a query is constant time. Storage cost is 2n. 15 | *

    16 | *

    17 | * "A Linear Algorithm For Generating Random Numbers With a Given Distribution", 18 | * Michael D. Vose, 1991. 19 | *

    20 | * @see http://www.keithschwarz.com/darts-dice-coins/ 21 | */ 22 | public class AliasMethod extends DiscreteMethod 23 | { 24 | // NOTES: If you've found this class by a web-search then 25 | // you're probably doing scientific computation and you 26 | // need to modify it. Notably change 'prob' to a more 27 | // appropriate type and matching PRNG generation in 28 | // 'nextInt'. 29 | 30 | /** Probability that the original column should be chosen. */ 31 | private final float[] prob; 32 | 33 | /** The second rectangle */ 34 | private final int[] alias; 35 | 36 | /** The range of the distribution. */ 37 | public int getSize() { 38 | return alias.length; 39 | } 40 | 41 | private AliasMethod(float[] prob, int[] alias) 42 | { 43 | this.prob = prob; 44 | this.alias = alias; 45 | } 46 | 47 | /** Core routine for building the tables. This could be optimized. */ 48 | private static AliasMethod make_(double[] w, double sum) 49 | { 50 | int len = w.length; 51 | double scale = len / sum; 52 | int[] ss = new int[len]; 53 | int[] ls = new int[len]; 54 | 55 | int si = 0; 56 | int li = 0; 57 | 58 | // convert weights into scaled probabilities and partition 59 | // the input into a big and small set. The temp arrays 60 | // can be eliminated. 61 | for (int i = 0; i != len; i++) { 62 | 63 | double p = w[i] = w[i] * scale; 64 | 65 | if (p > 1) 66 | ls[li++] = i; 67 | else 68 | ss[si++] = i; 69 | } 70 | 71 | float[] prob = new float[len]; 72 | int[] alias = new int[len]; 73 | 74 | // construct the probability & alias tables. SEE: paper 75 | // or above provided linked. 76 | while (si != 0 && li != 0) { 77 | int ws = ss[--si]; 78 | int wl = ls[--li]; 79 | prob[ws] = (float)w[ws]; 80 | alias[ws] = wl; 81 | w[wl] = (w[wl] + w[ws]) - 1; 82 | 83 | if (w[wl] > 1) 84 | ls[li++] = wl; 85 | else 86 | ss[si++] = wl; 87 | } 88 | 89 | // if either/both of list are not empty then 90 | // fill the associated prob with insured selection 91 | // (no alias for that slot). 92 | while (si != 0) prob[ss[--si]] = 1; 93 | while (li != 0) prob[ls[--li]] = 1; 94 | 95 | return new AliasMethod(prob, alias); 96 | } 97 | 98 | /** 99 | * Returns an AliasMethod instance which represents 100 | * the specified weights. 101 | *

    102 | */ 103 | public static AliasMethod make(double[] w) 104 | { 105 | int len = w.length; 106 | double sum = 0; 107 | double[] sa = new double[len]; 108 | 109 | // Compute the total weight of the input set and 110 | // copy the original array. 111 | for (int i = 0; i != len; i++) { 112 | double wi = w[i]; 113 | 114 | if (wi < 0) 115 | throw new IllegalArgumentException("AliasMethod: negative weight"); 116 | 117 | sa[i] = wi; 118 | sum += wi; 119 | } 120 | 121 | return make_(sa, sum); 122 | } 123 | 124 | /** @see #make(double[]) */ 125 | public static AliasMethod make(float[] w) 126 | { 127 | int len = w.length; 128 | double sum = 0; 129 | double[] sa = new double[len]; 130 | 131 | // Compute the total weight of the input set and 132 | // copy the original array. 133 | for (int i = 0; i != len; i++) { 134 | double wi = w[i]; 135 | 136 | if (wi < 0) 137 | throw new IllegalArgumentException("AliasMethod: negative weight"); 138 | 139 | sa[i] = wi; 140 | sum += wi; 141 | } 142 | 143 | return make_(sa, sum); 144 | } 145 | 146 | /** @see #make(double[]) */ 147 | public static AliasMethod make(int[] w) 148 | { 149 | int len = w.length; 150 | double sum = 0; 151 | double[] sa = new double[len]; 152 | 153 | // Compute the total weight of the input set and 154 | // copy the original array. 155 | for (int i = 0; i != len; i++) { 156 | double wi = w[i]; 157 | 158 | if (wi < 0) 159 | throw new IllegalArgumentException("AliasMethod: negative weight"); 160 | 161 | sa[i] = wi; 162 | sum += wi; 163 | } 164 | 165 | return make_(sa, sum); 166 | } 167 | 168 | 169 | /** 170 | * Returns the next value in the distribution. 171 | *

    172 | * The result is on [0, {@link #getSize()}) 173 | *

    174 | * Requires generating two uniform samples from 175 | * 'rng' and one or two table lookups and 176 | * completes in constant time. 177 | */ 178 | @Override 179 | public int nextInt(PRNG rng) 180 | { 181 | // Vose's version 182 | // double p = alias.length*rng.nextDouble(); 183 | // int i = (int)p; 184 | // return p-i <= prob[i] ? i : alias[i]; 185 | 186 | // Deviation from Vose here. Generate two 187 | // uniforms instead of one. 188 | int i = rng.nextIntFast(alias.length); 189 | float p = rng.nextFloat(); 190 | return p <= prob[i] ? i : alias[i]; 191 | } 192 | 193 | /* 194 | @SuppressWarnings("boxing") 195 | public static void main(String[] args) 196 | { 197 | roquen.math.rng.XorStar64 rng = new roquen.math.rng.XorStar64(1); 198 | 199 | for(int t=0; t<13; t++) { 200 | int len = rng.nextInt(5)+2; 201 | double[] w = new double[len]; 202 | int[] h = new int[len]; 203 | 204 | double sum = 0; 205 | for(int i=0;iMemory->x87. 38 | private static void spSinCos(float[] d, float[] s) 39 | { 40 | int len = d.length>>1; 41 | int di = 0; 42 | 43 | for(int i=0; i>2; 106 | int i = 0; 107 | 108 | while(i>2; 120 | int i = 0; 121 | 122 | while(i 8 | * All ranges are shown in American notation: square bracket 9 | * is inclusive and parentheses is exclusive. 10 | */ 11 | public abstract class PRNG implements roquen.math.seq.IntegerSequence, roquen.math.seq.FloatSequence 12 | { 13 | /** Sets the current state data of the generator. */ 14 | public abstract void setSeed(long seed); 15 | 16 | /** Returns the current state data of the generator. */ 17 | public abstract long getSeed(); 18 | 19 | /** Returns a uniform 32-bit integer. */ 20 | @Override 21 | public abstract int nextInt(); 22 | 23 | /** Returns a uniform 64-bit integer. */ 24 | public abstract long nextLong(); 25 | 26 | // just in case we happen to have two threads on different 27 | // processors make two non-seeded generators within the 28 | // same nanosecond (currently CPU tick) and that somehow 29 | // really matters. Or we're in the future of this writing 30 | // and computers are really fast and we succeed in creating 31 | // two non-seeded generators in a row within the same 32 | // nanosecond and it matters. You never know. (Seriously, 33 | // why not...doesn't cost you anything) 34 | protected static AtomicLong mix = new AtomicLong(-1); 35 | 36 | //*************************************** 37 | //** Derived stuff all below this point 38 | //** some assumptions based on 32-bit 39 | //** base generator. 40 | //*************************************** 41 | 42 | /** Maps a 32-bit integer to [0,1) single. */ 43 | public static final float mapToZO(int n) 44 | { 45 | // max value is 1-ulp(1) 46 | return (n >>> 8) * 0x1p-24f; 47 | } 48 | 49 | /** Maps a 32-bit integer to (0,1] single. */ 50 | public static final float mapToZOi(int n) 51 | { 52 | return ((n >>> 8)+1) * 0x1p-24f; 53 | } 54 | 55 | /** Maps a 64-bit integer to [0,1) double. */ 56 | public static final double mapToZO(long n) 57 | { 58 | // max value is 1-ulp(1) 59 | return (n >>> 12) * 0x1p-52; 60 | } 61 | 62 | /** Maps a 32-bit integer to [-1,1] single. */ 63 | public static final float mapToPMO(int n) 64 | { 65 | // TODO: What about not shifting and allowing 66 | // the rounding to handle? Bias issues? Think 67 | return ((n >> 8)+0.5f) * 0x1.000002p-23f; 68 | } 69 | 70 | /** Maps a 64-bit integer to [-1,1] double. */ 71 | public static final double mapToPMO(long n) 72 | { 73 | // TODO: see mapToPMO(float) 74 | return ((n >> 12)+0.5)*0x1.0000000000001p-51; 75 | } 76 | 77 | /** Maps a 32-bit integer to (-1,1) single. */ 78 | public static final float mapToPMOx(int n) 79 | { 80 | return ((n >> 8)+0.5f) * 0x1p-23f; 81 | } 82 | 83 | /** Maps a 64-bit integer to (-1,1) double. */ 84 | public static final double mapToPMOx(long n) 85 | { 86 | return ((n >> 12)+0.5)*0x1p-51; 87 | } 88 | 89 | 90 | /** Returns a uniform boolean */ 91 | public final boolean nextBoolean() 92 | { 93 | return nextInt() < 0; 94 | } 95 | 96 | /** 97 | * Returns a uniform integer on [0, n). 98 | *

    99 | * Range 'n' legal on [0, 0x8000]. 100 | */ 101 | public final int nextIntFast(int n) 102 | { 103 | // not quite uniform..you shouldn't care. 104 | // If you're really paranoid change to a 105 | // rejection method. 106 | return ((nextInt()>>>15) * n) >>> 17; 107 | } 108 | 109 | /** 110 | * Returns a uniform integer on [0, n). 111 | * @see #nextIntFast(int) 112 | */ 113 | public final int nextInt(int n) 114 | { 115 | // See notes in nextInt. This is 116 | // (on average) a better choice for 117 | // 64-bit VMs. 118 | long r = nextInt() >>> 1; 119 | 120 | // sign doesn't matter here 121 | r = (r * n) >> 31; 122 | 123 | return (int)r; 124 | } 125 | 126 | /** 127 | * Returns a uniform float on [0, 1) = [0, 1-ulp(1)] 128 | *

    129 | * @see #mapToZO(int) 130 | */ 131 | @Override 132 | public final float nextFloat() 133 | { 134 | return mapToZO(nextInt()); 135 | } 136 | 137 | /** 138 | * Returns a uniform single on [min,max) 139 | */ 140 | public final float nextFloat(float min, float max) 141 | { 142 | // NOTE: Not the soundest method..you shouldn't care. 143 | return min+nextFloat()*(max-min); 144 | } 145 | 146 | /** 147 | * Returns a uniform double on [0, 1) = [0, 1-ulp(1)] 148 | *

    149 | * @see #mapToZO(long) 150 | */ 151 | public final double nextDouble() 152 | { 153 | return mapToZO(nextLong()); 154 | } 155 | 156 | /** 157 | * Returns a uniform double on [min,max) 158 | */ 159 | public final double nextDouble(double min, double max) 160 | { 161 | // NOTE: Not the soundest method..you shouldn't care. 162 | return min+nextDouble()*(max-min); 163 | } 164 | 165 | 166 | /** 167 | * Returns a 'n' bit random number, [0, 2n), with 168 | * n on [1,32] 169 | */ 170 | public final int nextBits(int n) 171 | { 172 | return nextInt() >>> (32-n); 173 | } 174 | 175 | 176 | /** 177 | * Returns a 'n' bit random number, [0, 2n), with 178 | * n on [1,64] 179 | */ 180 | public final long nextLongBits(int n) 181 | { 182 | return nextLong() >>> (64-n); 183 | } 184 | 185 | /** 186 | * Returns a 'n' bit random number, [2n/2, 2n/2), 187 | * with n on [1,32]. 188 | */ 189 | public final int nextSignedBits(int n) 190 | { 191 | return nextInt() >> (32-n); 192 | } 193 | 194 | /** 195 | * Returns a random number on [0, 0xFFFF] with a 196 | * triangular distribution. 197 | */ 198 | public final int nextIntTriangle() 199 | { 200 | int r0,r1; 201 | 202 | r1 = nextInt(); 203 | r0 = r1 >>> 16; 204 | r1 = r1 & 0xFFFF; 205 | 206 | return (r0+r1+1)>>1; 207 | } 208 | 209 | /** 210 | * Returns a random number on [0, 1) with a 211 | * triangular distribution. 212 | */ 213 | public final float nextFloatTriangle() 214 | { 215 | long r0,r1; 216 | 217 | r1 = nextLong(); 218 | r0 = r1 >>> 40; // 24-bit 219 | r1 = r1 & 0xFFFFFF; // 24-bit 220 | 221 | return (r0+r1) * 0x1p-25f; 222 | } 223 | 224 | /** 225 | * Returns a random integer with a Poisson distribution. The 226 | * input 'eMean' is exp(-mean). 227 | *

    228 | * Implementation is suitable for small means. 229 | */ 230 | public final int nextPoisson(float eMean) 231 | { 232 | int r = 1; 233 | float t = nextFloat(); 234 | 235 | while (t > eMean) { 236 | r++; 237 | t *= nextFloat(); 238 | } 239 | return r-1; 240 | } 241 | 242 | /** 243 | * Geometric distribution with p = 1/2. 244 | *

    245 | * Returns a random integer on [0,32] with probability of (1/2)n+1. 246 | *

    247 | * Number of times I toss a coin until I see a "heads" (minus one). So we get 248 | * 0,1,2...(50%, 25%, 12.5%...) 249 | */ 250 | public final int nextToss() 251 | { 252 | return Integer.numberOfLeadingZeros(nextInt()); 253 | } 254 | 255 | 256 | /** 257 | * Geometric distribution with p = 1/2. Result on [0,64] 258 | *

    259 | * Very limited usefulness. A result of 33 has a probability 260 | * of 2-34 ~= 1x10-10. 261 | * @see #nextToss() 262 | */ 263 | public final int nextLongToss() 264 | { 265 | return Long.numberOfLeadingZeros(nextLong()); 266 | } 267 | 268 | } 269 | -------------------------------------------------------------------------------- /src/roquen/pg/noise/SimplexNoise3D.java: -------------------------------------------------------------------------------- 1 | package roquen.pg.noise; 2 | 3 | public class SimplexNoise3D extends Noise 4 | { 5 | /** 6 | * If true the valid input set to noise is restricted 7 | * to positive numbers. This will produce serious defects 8 | * if any of the input coordinates are negative. 9 | */ 10 | private static final boolean restrictToPositive = false; 11 | 12 | 13 | /** 14 | * Compile time selection between Perlin's simplex vectors and 15 | * the older vector set from Improved (gradient) noise. 16 | */ 17 | private static final boolean perlinVectors = false; 18 | 19 | /** 20 | * Compile time selection: If true vectors are expanded 21 | * to a switch table instead of conditional moves. 22 | */ 23 | private static final boolean expandVectors = true; 24 | 25 | 26 | /** 27 | * Final scaling factor. Depends on vector set. 28 | */ 29 | private static final float finalScale; 30 | 31 | static { 32 | if (perlinVectors) 33 | finalScale = 8; 34 | else 35 | finalScale = 32; 36 | } 37 | 38 | 39 | /** 40 | * Completes coordinate hashing and performs the dot product with the selected vector. 41 | */ 42 | private static float dotRandVector(int h, float x, float y, float z) 43 | { 44 | // complete hash generation (see eval) 45 | h = posthash(h) >>> 24; 46 | 47 | if (perlinVectors) { 48 | float S; 49 | 50 | if (false) { 51 | int b5 = h >> 5 & 1; 52 | int b4 = h >> 4 & 1; 53 | int b3 = h >> 3 & 1; 54 | int b2 = h >> 2 & 1; 55 | int b = h & 3; 56 | 57 | float P,Q,R; 58 | 59 | switch (b) { 60 | case 1: P=x; Q=y; R=z; break; 61 | case 2: P=y; Q=z; R=x; break; 62 | default: P=z; Q=x; R=y; break; 63 | } 64 | if (true) { 65 | if (b5 == b3) P = -P; 66 | if (b5 == b4) Q = -Q; 67 | if (b5 != (b4^b3)) R = -R; 68 | } else { 69 | P = b5 == b3 ? -P : P; 70 | Q = b5 == b4 ? -Q: Q; 71 | R = b5 != (b4^b3) ? -R : R; 72 | } 73 | 74 | S = (b == 0 ? Q + R : b2 == 0 ? Q : R); 75 | 76 | 77 | return (P + S); 78 | } 79 | else { 80 | S = 0;//tempHack(h,x,y,z); 81 | 82 | return S; 83 | } 84 | } 85 | else { 86 | // Use the "older" vector set from Improved Gradient Noise. 87 | 88 | if (expandVectors) { 89 | switch(h & 0xF) { 90 | case 0x0: return x+y; 91 | case 0x1: return -x+y; 92 | case 0x2: return x-y; 93 | case 0x3: return -x-y; 94 | case 0x4: return x+z; 95 | case 0x5: return -x+z; 96 | case 0x6: return x-z; 97 | case 0x7: return -x-z; 98 | case 0x8: return y+z; 99 | case 0x9: return -y+z; 100 | case 0xA: return y-z; 101 | case 0xB: return -y-z; 102 | case 0xC: return y+x; 103 | case 0xD: return -y+z; 104 | case 0xE: return y-x; 105 | case 0xF: return -y-z; 106 | default: return 0; // never happens 107 | } 108 | } 109 | else { 110 | h &= 0xF; 111 | 112 | float u = (h < 8) ? x : y; 113 | float v = (h < 4) ? y : ((h == 12 || h == 14) ? x : z); 114 | 115 | return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); 116 | } 117 | } 118 | } 119 | 120 | /** Properly rounded: 1/3 */ 121 | private static final float K0 = 0x1.555556p-2f; 122 | 123 | /** Properly rounded: 1/6 */ 124 | private static final float K1 = 0x1.555556p-3f; 125 | 126 | private static final boolean simpleHash = true; 127 | private static final int M = 0x5bd1e995; 128 | 129 | private static final int prehash(int i, int j, int k) 130 | { 131 | if (simpleHash) 132 | return (i<<16)^(j<<8)^(k); 133 | else { 134 | int h; 135 | 136 | i *= M; i ^= i >>> 24; i *= M; 137 | j *= M; j ^= j >>> 24; j *= M; 138 | k *= M; k ^= k >>> 24; k *= M; 139 | 140 | h = i; h *= M; 141 | h ^= j; h *= M; 142 | h ^= k; 143 | 144 | return h; 145 | } 146 | } 147 | 148 | private static final int posthash(int h) 149 | { 150 | if (simpleHash) 151 | h *= 0xB5262C85; 152 | else { 153 | h ^= h >>> 13; h *= M; h ^= h >>> 15; 154 | } 155 | return h; 156 | } 157 | 158 | 159 | 160 | /** 161 | * 162 | */ 163 | public static float eval(float x, float y, float z) 164 | { 165 | // project the input coordinate (via skew) 166 | float s = (x + y + z) * K0; 167 | int i, j, k; 168 | 169 | if (restrictToPositive) { 170 | // This is possible if input is restricted to positive values. 171 | // The center of the image in the example is (0,0,0), so will 172 | // show the (serious) defects if used and the inputs are negative. 173 | // 174 | // The major upside is that the code will run significantly 175 | // faster if this input limitation is required. 176 | i = (int)(x+s); 177 | j = (int)(y+s); 178 | k = (int)(z+s); 179 | } 180 | else { 181 | i = pseudoFloor(x+s); 182 | j = pseudoFloor(y+s); 183 | k = pseudoFloor(z+s); 184 | } 185 | 186 | // unproject the coordinate back to Euclidean space. 187 | float t = (i + j + k) * K1; 188 | float x0 = x - (i-t); 189 | float y0 = y - (j-t); 190 | float z0 = z - (k-t); 191 | 192 | // locate the simplex of the input coordinate. 193 | int i1, j1, k1; 194 | int i2, j2, k2; 195 | 196 | if (x0 >= y0) { 197 | i2 = 1; 198 | j1 = 0; 199 | 200 | if (y0 >= z0) { 201 | i1 = j2 = 1; 202 | k1 = k2 = 0; 203 | } 204 | else { 205 | j2 = 0; 206 | k2 = 1; 207 | 208 | if (x0 >= z0) 209 | i1 = 1; 210 | else 211 | i1 = 0; 212 | 213 | k1 = i1 ^ 1; 214 | } 215 | } 216 | else { 217 | i1 = 0; 218 | j2 = 1; 219 | 220 | if (y0 < z0) { 221 | j1 = i2 = 0; 222 | k1 = k2 = 1; 223 | } 224 | else { 225 | j1 = 1; 226 | k1 = 0; 227 | 228 | if (x0 < z0) { 229 | i2 = 0; 230 | k2 = 1; 231 | } 232 | else { 233 | i2 = 1; 234 | k2 = 0; 235 | } 236 | } 237 | } 238 | 239 | // calculate the four coordinates 240 | float x1 = x0 - i1 + K1; 241 | float y1 = y0 - j1 + K1; 242 | float z1 = z0 - k1 + K1; 243 | 244 | float x2 = x0 - i2 + 2*K1; 245 | float y2 = y0 - j2 + 2*K1; 246 | float z2 = z0 - k2 + 2*K1; 247 | 248 | float x3 = x0 - 1 + 3*K1; 249 | float y3 = y0 - 1 + 3*K1; 250 | float z3 = z0 - 1 + 3*K1; 251 | 252 | // Step 1 of hash generation, if needed the hashing 253 | // is completed in 'doRandVector'. 254 | // This could be improved 255 | int h0 = prehash(i, j, k ); 256 | int h1 = prehash(i+i1, j+j1, k+k1); 257 | int h2 = prehash(i+i2, j+j2, k+k2); 258 | int h3 = prehash(i+ 1, j+ 1, k+ 1); 259 | 260 | float n = 0; 261 | 262 | // Calculate and sum the results of the four coordinates. 263 | 264 | t = 0.6f - x0*x0 - y0*y0 - z0*z0; 265 | 266 | if (t > 0){ 267 | t *= t; 268 | n += t*t * dotRandVector(h0, x0, y0, z0); 269 | } 270 | 271 | t = 0.6f - x1*x1 - y1*y1 - z1*z1; 272 | 273 | if (t > 0) { 274 | t *= t; 275 | n += t*t * dotRandVector(h1, x1, y1, z1); 276 | } 277 | 278 | t = 0.6f - x2*x2 - y2*y2 - z2*z2; 279 | 280 | if (t > 0) { 281 | t *= t; 282 | n += t*t * dotRandVector(h2, x2, y2, z2); 283 | } 284 | 285 | t = 0.6f - x3*x3 - y3*y3 - z3*z3; 286 | 287 | if (t > 0) { 288 | t *= t; 289 | n += t*t * dotRandVector(h3, x3, y3, z3); 290 | } 291 | 292 | return finalScale * n; 293 | } 294 | } -------------------------------------------------------------------------------- /src/roquen/math/sfc/Morton2D.java: -------------------------------------------------------------------------------- 1 | package roquen.math.sfc; 2 | 3 | import roquen.fake.Vect2i; 4 | 5 | /** 6 | * Static utilities for 2-to-1 mappings based on Morton/Z-Order/Lebesgue curve. 7 | */ 8 | public enum Morton2D { 9 | ; 10 | 11 | 12 | 13 | /** bit positions of scattered X */ 14 | protected static final int MASK_X = 0x55555555; 15 | 16 | /** bit positions of scattered Y */ 17 | protected static final int MASK_Y = MASK_X<<1; 18 | 19 | /** Increase the represented Y coordinate by one. */ 20 | public static int incY(int code) 21 | { 22 | //int r = (code | MASK_X) + 2; 23 | //return (r & MASK_Y) | (code & MASK_X); 24 | 25 | int mx = MASK_X; 26 | int x = code & mx; 27 | int my = mx+mx; 28 | int y = code & my; 29 | 30 | y |= mx; y += 2; y &= my; 31 | 32 | return x|y; 33 | } 34 | 35 | /** Decrease the represented Y coordinate by one. */ 36 | public static int decY(int code) 37 | { 38 | //int r = (code & MASK_Y) - 2; 39 | //return (r & MASK_Y) | (code & MASK_X); 40 | 41 | int mx = MASK_X; 42 | int x = code & mx; 43 | int my = mx+mx; 44 | int y = code & my; 45 | 46 | y -= 2; y &= my; 47 | 48 | return x|y; 49 | } 50 | 51 | /** Increase the represented X coordinate by one. */ 52 | public static int incX(int code) 53 | { 54 | //int r = (code | MASK_Y) + 1; 55 | //return (r & MASK_X) | (code & MASK_Y); 56 | 57 | int my = MASK_Y; 58 | int mx = my >>> 1; // MASK_X 59 | int x = code | my; // set bits for carry 60 | int y = code & my; // isolate Y 61 | 62 | x += 1; x &= mx; // add and isolate 63 | 64 | return x|y; // rebuild code 65 | } 66 | 67 | /** Decrease the represented X coordinate by one. */ 68 | public static int decX(int code) 69 | { 70 | //int r = (code & MASK_X) - 1; 71 | //return (r & MASK_X) | (code & MASK_Y); 72 | 73 | int mx = MASK_X; 74 | int x = code & mx; // isolate X 75 | int my = mx+mx; // MASK_Y 76 | int y = code & my; // isolate Y 77 | 78 | x -= 1; x &= mx; // sub and isolate 79 | 80 | return x|y; // rebuild code 81 | } 82 | 83 | /** 84 | * (ax,ay)+(bx,by) 85 | */ 86 | public static int add(int a, int b) 87 | { 88 | int x = (a | MASK_Y) + (b & MASK_X); 89 | int y = (a | MASK_X) + (b & MASK_Y); 90 | return (x & MASK_X) | (y & MASK_Y); 91 | } 92 | 93 | /** 94 | * (ax,ay)-(bx,by) 95 | */ 96 | public static int sub(int a, int b) 97 | { 98 | int x = (a & MASK_X) - (b & MASK_X); 99 | int y = (a & MASK_Y) - (b & MASK_Y); 100 | return (x & MASK_X) | (y & MASK_Y); 101 | } 102 | 103 | /** 104 | * (min(ax,bx), min(ay,by)) 105 | */ 106 | public static int min(int a, int b) 107 | { 108 | int xdiff = (a & MASK_X) - (b & MASK_X); 109 | int ydiff = (a >> 1 & MASK_X) - (b >> 1 & MASK_X); 110 | 111 | int maskx = xdiff >> 31; 112 | int masky = ydiff >> 31; 113 | 114 | int xmin = (maskx & a) | (~maskx & b); 115 | int ymin = (masky & a) | (~masky & b); 116 | 117 | return (xmin & MASK_X) | (ymin & MASK_Y); 118 | } 119 | 120 | /** 121 | * (max(ax,bx), max(ay,by)) 122 | */ 123 | public static int max(int a, int b) 124 | { 125 | int xdiff = (a & MASK_X) - (b & MASK_X); 126 | int ydiff = (a >> 1 & MASK_X) - (b >> 1 & MASK_X); 127 | int maskx = (xdiff >> 31); 128 | int masky = (ydiff >> 31); 129 | int xmin = (~maskx & a) | (maskx & b); 130 | int ymin = (~masky & a) | (masky & b); 131 | return ((xmin & MASK_X) | (ymin & MASK_Y)); 132 | } 133 | 134 | /** 135 | * Scatter the lower 16-bits into even bit positions. 136 | * x on [0,0xffff]. 137 | */ 138 | public static int scatter1(int x) 139 | { 140 | //x = x & 0xFFFF; 141 | x = (x ^ (x << 8)) & 0x00FF00FF; //16 142 | x = (x ^ (x << 4)) & 0x0F0F0F0F; // 8 143 | x = (x ^ (x << 2)) & 0x33333333; // 4 144 | x = (x ^ (x << 1)) & MASK_X; 145 | 146 | return x; 147 | } 148 | 149 | /** 150 | * Gather all the even bits into the lower 16. Odd 151 | * bits must be already zero. 152 | */ 153 | public static int gather1_(int x) 154 | { 155 | x = (x ^ (x >>> 1)) & 0x33333333; 156 | x = (x ^ (x >>> 2)) & 0x0F0F0F0F; 157 | x = (x ^ (x >>> 4)) & 0x00FF00FF; 158 | x = (x ^ (x >>> 8)) & 0x0000FFFF; 159 | return x; 160 | } 161 | 162 | /** 163 | * Gather all the even bits into the lower 16. 164 | */ 165 | public static int gather1(int x) 166 | { 167 | x &= MASK_X; 168 | x = (x ^ (x >>> 1)) & 0x33333333; 169 | x = (x ^ (x >>> 2)) & 0x0F0F0F0F; 170 | x = (x ^ (x >>> 4)) & 0x00FF00FF; 171 | x = (x ^ (x >>> 8)) & 0x0000FFFF; 172 | return x; 173 | } 174 | 175 | /** 176 | * 177 | */ 178 | public static int encode4(Vect2i v) 179 | { 180 | return encode4(v.x,v.y); 181 | } 182 | 183 | /** 184 | * x,y on [0,0xF] 185 | */ 186 | public static int encode4(int x, int y) 187 | { 188 | // dependency chain = 5 in 9 ops 189 | x = x * 0x10101010 & 0x80402010; 190 | y = y * 0x10101010 & 0x80402010; 191 | x = x * 0x204081; 192 | y = y * 0x204081; 193 | x = x >>> 25; 194 | y = y >>> 24; 195 | return x|y; 196 | } 197 | 198 | /** 199 | * 200 | */ 201 | public static void decode4(Vect2i p, int code) 202 | { 203 | int i = code+code; 204 | p.x = ((0xee44ee44 >> i) & 3); 205 | p.y = ((0xfafa5050 >> i) & 3); 206 | } 207 | 208 | /** 209 | * 210 | */ 211 | public static int encode5(Vect2i v) 212 | { 213 | return encode5(v.x, v.y); 214 | } 215 | 216 | /** 217 | * x,y on [0,0x1F] 218 | */ 219 | public static int encode5(int x, int y) 220 | { 221 | // dependency chain = 6 in 11 ops 222 | //x &= 0x0000001f; y &= 0x0000001f; 223 | x *= 0x01041041; y *= 0x01041041; 224 | x &= 0x10204081; y &= 0x10204081; 225 | x *= 0x00108421; y *= 0x00108421; 226 | x &= 0x15500000; y &= 0x15500000; 227 | return((x >>> 20) | (y >>> 19)); 228 | } 229 | 230 | /** 231 | */ 232 | public static void decode5(Vect2i v, int code) 233 | { 234 | int x = code; 235 | int y = code >>> 1; 236 | x &= 0x00000155; y &= 0x00000155; 237 | x |= (x >>> 1); y |= (y >>> 1); 238 | x &= 0x00000133; y &= 0x00000133; 239 | x |= (x >>> 2); y |= (y >>> 2); 240 | x &= 0x0000010f; y &= 0x0000010f; 241 | x |= (x >>> 4); y |= (y >>> 4); 242 | x &= 0x0000001f; y &= 0x0000001f; 243 | v.x = x; 244 | v.y = y; 245 | } 246 | 247 | /** 248 | * x,y on [0,0xFF] 249 | */ 250 | public static final int encode8(int x, int y) 251 | { 252 | x = (int)((x * 0x0101010101010101L & 0x8040201008040201L) * 0x0102040810204081L >>> 49) & 0x5555; 253 | y = (int)((y * 0x0101010101010101L & 0x8040201008040201L) * 0x0102040810204081L >>> 48) & 0xAAAA; 254 | 255 | return x|y; 256 | } 257 | 258 | /** 259 | * x,y on [0,0xFFFF] 260 | */ 261 | public static int encode16(int x, int y) 262 | { 263 | //x &= 0x0000ffff; y &= 0x0000ffff; 264 | x |= (x << 8); y |= (y << 8); 265 | x &= 0x00ff00ff; y &= 0x00ff00ff; 266 | x |= (x << 4); y |= (y << 4); 267 | x &= 0x0f0f0f0f; y &= 0x0f0f0f0f; 268 | x |= (x << 2); y |= (y << 2); 269 | x &= 0x33333333; y &= 0x33333333; 270 | x |= (x << 1); y |= (y << 1); 271 | x &= MASK_X; y &= MASK_X; 272 | return(x|(y<<1)); 273 | } 274 | 275 | /** 276 | * 277 | */ 278 | public final static void decode16(Vect2i v, int code) 279 | { 280 | int x = code; 281 | int y = code >>> 1; 282 | x &= MASK_X; y &= MASK_X; 283 | x |= (x >>> 1); y |= (y >>> 1); 284 | x &= 0x33333333; y &= 0x33333333; 285 | x |= (x >>> 2); y |= (y >>> 2); 286 | x &= 0x0f0f0f0f; y &= 0x0f0f0f0f; 287 | x |= (x >>> 4); y |= (y >>> 4); 288 | x &= 0x00ff00ff; y &= 0x00ff00ff; 289 | x |= (x >>> 8); y |= (y >>> 8); 290 | x &= 0x0000ffff; y &= 0x0000ffff; 291 | v.x = x; 292 | v.y = y; 293 | } 294 | 295 | @SuppressWarnings("boxing") 296 | public static void main(String[] args) 297 | { 298 | Vect2i p = new Vect2i(); 299 | 300 | int px = 0; 301 | int py = 0; 302 | 303 | for(int i=0; i<16; i++) { 304 | int e = encode4(i&3,(i>>2)&3); 305 | px |= (i&3) << (e+e); 306 | py |= ((i>>2)&3) << (e+e); 307 | //System.out.printf("{%d,%d},",p.x,p.y); 308 | } 309 | 310 | System.out.printf("%s,%s\n",Integer.toBinaryString(px),Integer.toBinaryString(py)); 311 | 312 | for(int i=0; i<16; i++) { 313 | decode4(p,i); 314 | System.out.printf("{%d,%d},",p.x,p.y); 315 | } 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/roquen/pg/noise/Noise.java: -------------------------------------------------------------------------------- 1 | package roquen.pg.noise; 2 | 3 | 4 | public abstract class Noise 5 | { 6 | public static final int pseudoFloor(float x) 7 | { 8 | //return (int)x; 9 | //int ix = (int)x-1.f; return ix - (ix>>31); 10 | return x >= 0 ? (int)x : (int)x-1; 11 | } 12 | 13 | /** 3t2 - 2t3 */ 14 | public static final float ease(float t) 15 | { 16 | return (t*t*(3.f-(t+t))); 17 | } 18 | 19 | /** 6t - 6t2 */ 20 | public static final float easeDt(float t) 21 | { 22 | return 6.f*t*(1-t); 23 | } 24 | 25 | /** 26 | * 10t3 - 15t4 + 6t5 27 | */ 28 | public static final float iease(float t) 29 | { 30 | return t*t*t*(t*(t*6.f-15.f)+10.f); 31 | } 32 | 33 | /** 30t2 - 60t3 + 30t4 */ 34 | public static final float ieaseDt(float t) 35 | { 36 | return 30.f*t*t*(t*(t-2.f)+1.f); 37 | } 38 | 39 | public static final float lerp(float t, float a, float b) 40 | { 41 | return a+t*(b-a); 42 | } 43 | 44 | 45 | /** map 32-bit integer to a single on [-1,1] */ 46 | public static final float normalizeI(int h) 47 | { 48 | return (h>>>7)*0x1.0p-24f - 1; 49 | } 50 | 51 | //*************** HASHING FUNCTIONS 52 | 53 | private static final int M = 0x5bd1e995; 54 | 55 | 56 | public static final int postHashM2(int h) 57 | { 58 | h ^= h >>> 13; h *= M; h ^= h >>> 15; 59 | 60 | return h; 61 | } 62 | 63 | 64 | public static final int preHashM2(int x) 65 | { 66 | int h = 0x9747b28c; 67 | 68 | x *= M; x ^= x >>> 24; x *= M; 69 | 70 | h ^= x; h *= M; 71 | 72 | return h; 73 | } 74 | 75 | public static final int hashM2(int x) 76 | { 77 | return postHashM2(preHashM2(x)); 78 | } 79 | 80 | 81 | public static final int preHashM2(int x, int y) 82 | { 83 | int h = 0x9747b28c; 84 | 85 | x *= M; x ^= x >>> 24; x *= M; 86 | y *= M; y ^= y >>> 24; y *= M; 87 | 88 | h ^= x; h *= M; h ^= y; 89 | 90 | return h; 91 | } 92 | 93 | public static final int hashM2(int x, int y) 94 | { 95 | return postHashM2(preHashM2(x,y)); 96 | } 97 | 98 | public static final int preHashM2(int x, int y, int z) 99 | { 100 | int h = 0x9747b28c; 101 | 102 | x *= M; x ^= x >>> 24; x *= M; 103 | y *= M; y ^= y >>> 24; y *= M; 104 | z *= M; z ^= z >>> 24; z *= M; 105 | 106 | h ^= x; h *= M; 107 | h ^= y; h *= M; 108 | h ^= z; 109 | 110 | return h; 111 | } 112 | 113 | public static final int hashM2(int x, int y, int z) 114 | { 115 | return postHashM2(preHashM2(x,y,z)); 116 | } 117 | 118 | 119 | public static final int preHashJ(int x) 120 | { 121 | int h = 0x9747b28c; 122 | 123 | h += x; h += h << 10; h ^= h >>> 6; 124 | 125 | return h; 126 | } 127 | 128 | public static final int preHashJ(int x, int y) 129 | { 130 | int h = 0x9747b28c; 131 | 132 | h += x; h += h << 10; h ^= h >>> 6; 133 | h += y; h += h << 10; h ^= h >>> 6; 134 | 135 | return h; 136 | } 137 | 138 | public static final int hashJ(int x, int y) 139 | { 140 | return postHashJ(preHashJ(x,y)); 141 | } 142 | 143 | public static final int preHashJ(int x, int y, int z) 144 | { 145 | int h = 0x9747b28c; 146 | 147 | h += x; h += h << 10; h ^= h >>> 6; 148 | h += y; h += h << 10; h ^= h >>> 6; 149 | h += z; h += h << 10; h ^= h >>> 6; 150 | 151 | return h; 152 | } 153 | 154 | public static final int hashJ(int x, int y, int z) 155 | { 156 | return postHashJ(preHashJ(x,y,z)); 157 | } 158 | 159 | 160 | public static final int postHashJ(int h) 161 | { 162 | h += h << 3; 163 | h ^= h >>> 11; 164 | h += h << 15; 165 | 166 | return h; 167 | } 168 | 169 | public static final int hashTEA4(int x, int y) 170 | { 171 | int v0 = x; 172 | int v1 = y; 173 | 174 | v0 += ((v1<<4)+0xA341316C)^(v1+0x9e3779b9)^((v1>>>4)+0xC8013EA4); 175 | v1 += ((v0<<4)+0xAD90777D)^(v0+0x9e3779b9)^((v0>>>4)+0x7E95761E); 176 | v0 += ((v1<<4)+0xA341316C)^(v1+0x3c6ef372)^((v1>>>4)+0xC8013EA4); 177 | v1 += ((v0<<4)+0xAD90777D)^(v0+0x3c6ef372)^((v0>>>4)+0x7E95761E); 178 | v0 += ((v1<<4)+0xA341316C)^(v1+0xdaa66d2b)^((v1>>>4)+0xC8013EA4); 179 | v1 += ((v0<<4)+0xAD90777D)^(v0+0xdaa66d2b)^((v0>>>4)+0x7E95761E); 180 | v0 += ((v1<<4)+0xA341316C)^(v1+0x78dde6e4)^((v1>>>4)+0xC8013EA4); 181 | v1 += ((v0<<4)+0xAD90777D)^(v0+0x78dde6e4)^((v0>>>4)+0x7E95761E); 182 | 183 | return v0^v1; 184 | } 185 | 186 | public static final int hashZ(int x, int y) 187 | { 188 | // 8-bit input only 189 | int sx = (int)((x * 0x0101010101010101L & 0x8040201008040201L) * 190 | 0x0102040810204081L >>> 49) & 0x5555; 191 | 192 | int sy = (int)((y * 0x0101010101010101L & 0x8040201008040201L) * 193 | 0x0102040810204081L >>> 48) & 0xAAAA; 194 | 195 | return sx|sy; 196 | } 197 | 198 | public static final int hashWang(int seed) 199 | { 200 | seed = (seed ^ 61) ^ (seed >>> 16); 201 | seed *= 9; 202 | seed = seed ^ (seed >>> 4); 203 | seed *= 0x27d4eb2d; 204 | seed = seed ^ (seed >>> 15); 205 | return seed; 206 | } 207 | 208 | public static long hashWang(long key) { 209 | key = (~key) + (key << 21); // key = (key << 21) - key - 1; 210 | key = key ^ (key >>> 24); 211 | key = (key + (key << 3)) + (key << 8); // key * 265 212 | key = key ^ (key >>> 14); 213 | key = (key + (key << 2)) + (key << 4); // key * 21 214 | key = key ^ (key >>> 28); 215 | key = key + (key << 31); 216 | return key; 217 | } 218 | 219 | /* 220 | // inverse of the 64-bit wang hash function (still in C) 221 | uint64_t inverse_hash(uint64_t key) { 222 | uint64_t tmp; 223 | 224 | // Invert key = key + (key << 31) 225 | tmp = key-(key<<31); 226 | key = key-(tmp<<31); 227 | 228 | // Invert key = key ^ (key >> 28) 229 | tmp = key^key>>28; 230 | key = key^tmp>>28; 231 | 232 | // Invert key *= 21 233 | key *= 14933078535860113213u; 234 | 235 | // Invert key = key ^ (key >> 14) 236 | tmp = key^key>>14; 237 | tmp = key^tmp>>14; 238 | tmp = key^tmp>>14; 239 | key = key^tmp>>14; 240 | 241 | // Invert key *= 265 242 | key *= 15244667743933553977u; 243 | 244 | // Invert key = key ^ (key >> 24) 245 | tmp = key^key>>24; 246 | key = key^tmp>>24; 247 | 248 | // Invert key = (~key) + (key << 21) 249 | tmp = ~key; 250 | tmp = ~(key-(tmp<<21)); 251 | tmp = ~(key-(tmp<<21)); 252 | key = ~(key-(tmp<<21)); 253 | 254 | return key; 255 | } 256 | */ 257 | 258 | 259 | //*************** DOT WITH RANDOM VECTOR FUNCTIONS 260 | 261 | 262 | 263 | public static final float grad7(int h, float x, float y) 264 | { 265 | switch (h >>> (32-3)) { 266 | case 0x0: return x+y; 267 | case 0x1: return -x+y; 268 | case 0x2: return x-y; 269 | case 0x3: return -x-y; 270 | case 0x4: return x; 271 | case 0x5: return -x; 272 | case 0x6: return y; 273 | case 0x7: return -y; 274 | default: return 0; // never happens 275 | } 276 | } 277 | 278 | // perlin's simplex reference 279 | public static final float gradPSR(int h, float x, float y, float z) 280 | { 281 | int b5 = h >> 5 & 1; 282 | int b4 = h >> 4 & 1; 283 | int b3 = h >> 3 & 1; 284 | int b2 = h >> 2 & 1; 285 | int b = h & 3; 286 | 287 | float p = b == 1 ? x : b == 2 ? y : z; 288 | float q = b == 1 ? y : b == 2 ? z : x; 289 | float r = b == 1 ? z : b == 2 ? x : y; 290 | 291 | p = b5 == b3 ? -p : p; 292 | q = b5 == b4 ? -q: q; 293 | r = b5 != (b4^b3) ? -r : r; 294 | 295 | return (p + (b == 0 ? q + r : b2 == 0 ? q : r)); 296 | } 297 | 298 | public static final float gradF(int h, float x, float y, float z) 299 | { 300 | // TODO: change to shift instead? 301 | switch(h & 0xF) { 302 | case 0x0: return x+y; 303 | case 0x1: return -x+y; 304 | case 0x2: return x-y; 305 | case 0x3: return -x-y; 306 | case 0x4: return x+z; 307 | case 0x5: return -x+z; 308 | case 0x6: return x-z; 309 | case 0x7: return -x-z; 310 | case 0x8: return y+z; 311 | case 0x9: return -y+z; 312 | case 0xA: return y-z; 313 | case 0xB: return -y-z; 314 | case 0xC: return x+y; 315 | case 0xD: return -x+y; 316 | case 0xE: return -y+z; 317 | case 0xF: return -y-z; 318 | default: return 0; 319 | } 320 | } 321 | 322 | 323 | //public abstract float eval(float x); 324 | } 325 | 326 | -------------------------------------------------------------------------------- /src/roquen/math/Float32.java: -------------------------------------------------------------------------------- 1 | package roquen.math; 2 | 3 | /** 4 | * Some basic math routines for 32-bit floating point. 5 | *

    6 | * 7 | *

  • http://www.java-gaming.org/topics/atan2/28986/msg/264901/view.html
  • 8 | *
  • http://www.java-gaming.org/topics/exp-log-amp-pow/24240/msg/203361/view.html
  • 9 | * 10 | */ 11 | 12 | public enum Float32 { 13 | 14 | ; 15 | 16 | static final int B_ONE = Float.floatToRawIntBits(1.f); 17 | 18 | /** 19 | * Returns abs(a) 20 | *

    21 | * This is a branch-free alternate of {@link java.lang.Math#abs(float)} 22 | */ 23 | public static final float abs(float a) 24 | { 25 | return Float.intBitsToFloat((Float.floatToRawIntBits(a) & (-1>>>1))); 26 | } 27 | 28 | /** 29 | * Returns 'a' multiplied by the sign of 'b'. 30 | *

    31 | * equivalent to: {@linkplain java.lang.Math#copySign(float,float) copySign}(1,b)*a 32 | */ 33 | public static final float mulSign(float a, float b) 34 | { 35 | int sb = Float.floatToRawIntBits(b) & 0x80000000; 36 | int ia = Float.floatToRawIntBits(a) ^ sb; 37 | return Float.intBitsToFloat(ia); 38 | } 39 | 40 | public static int roundToInt(float x) 41 | { 42 | // TODO: 43 | return (int)(x + Math.copySign(0.5f,x)); 44 | } 45 | 46 | /** 47 | * Returns the smallest of the two inputs without special casing for NaNs and -0 48 | *

     49 |    * min(-0, 0)  = -0
     50 |    * min( 0,-0)  =  0
     51 |    * min(NaN, x) =  x
     52 |    * min(x, NaN) =  NaN
     53 |    * 
    54 | */ 55 | public static final float min(float a, float b) 56 | { 57 | return (a <= b) ? a : b; 58 | } 59 | 60 | /** 61 | * Returns the smaller of 'a' and 'b'. 62 | *

    63 | * No special casing -0, only returns NaN if both 64 | * inputs are NaN. 65 | *

     66 |    * minNum(-0, 0)  = -0
     67 |    * minNum( 0,-0)  =  0
     68 |    * minNum(NaN, x) =  x
     69 |    * minNum(x, NaN) =  x
     70 |    * 
    71 | */ 72 | public static final float minNum(float a, float b) 73 | { 74 | if (b >= a) return a; // a <= b and neither are NaN 75 | if (b == b) return b; // b isn't NaN 76 | return a; 77 | } 78 | 79 | /** 80 | * Returns the largest of the two inputs without special casing for NaNs and -0 81 | *
     82 |    * max(-0, 0)  = -0
     83 |    * max( 0,-0)  =  0
     84 |    * max(NaN, x) =  x
     85 |    * max(x, NaN) =  NaN
     86 |    * 
    87 | */ 88 | public static final float max(float a, float b) 89 | { 90 | return (a >= b) ? a : b; 91 | } 92 | 93 | /** 94 | * Returns the larger of 'a' and 'b'. 95 | *

    96 | * No special casing -0, only returns NaN if both 97 | * inputs are NaN. 98 | *

     99 |    * maxNum(-0, 0)  =  0
    100 |    * maxNum( 0,-0)  = -0
    101 |    * maxNum(NaN, x) =  x
    102 |    * maxNum(x, NaN) =  x
    103 |    * 
    104 | */ 105 | public static final float maxNum(float a, float b) 106 | { 107 | if (a <= b) return b; // b >= a and neither are NaN 108 | if (a == a) return a; // a isn't NaN 109 | return b; 110 | } 111 | 112 | /** returns true if |d| <= epsilon. If d is NaN will return false. */ 113 | public final static boolean epsilonEquals(float d, float epsilon) 114 | { 115 | // if 'd' is NaN, returns false 116 | return abs(d) <= epsilon; 117 | } 118 | 119 | // TODO: these should be change to pre-computed correctly 120 | // rounded hex constants. 121 | 122 | public static final float PI = 0x3.243f6cp0f; // (float)(Math.PI); 123 | public static final float PI_OVER_2 = 0x1.921fb6p0f; // (float)(Math.PI/2); 124 | public static final float PI_OVER_4 = 0xc.90fdbp-4f; // (float)(Math.PI/4); 125 | 126 | public static final float ONE_OVER_LOG_2 = 0x1.715476p0f; // (float)(1.0/Math.log(2)); 127 | public static final float LOG_2 = 0xb.17218p-4f; // (float)Math.log(2); 128 | 129 | /** log(2)/log(10) */ 130 | public static final float LOG_2_OVER_LOG_10 = 0x1.344136p-2f; 131 | 132 | public static final float SQRT_2 = 0x1.6a09e6p0f; //(float)Math.sqrt(2); 133 | 134 | /** 135 | * arc tangent of x on [-1,1] 136 | *

    137 | * 5th order minimax approximation (minimizing abs error). Banged out quickly, 138 | * a better version could be produced. Error bound of ~0.0006 @ 139 | * x = +/-{0.205219, 0.59347, 0.888196, 1.0} 140 | */ 141 | public static final float atan_5(float x) 142 | { 143 | // quality (of either abs or rel error) can be improved at same cost. 144 | // Additionally (by using Estrin's) one could probably produce a higher 145 | // order approximation at same cost (by reducing dependency chains). YMMV. 146 | float x2 = x*x; 147 | return x*(0.995354f+x2*(-0.288769f+0.079331f*x2)); 148 | } 149 | 150 | /** */ 151 | public static final float atan(float y, float x) 152 | { 153 | // TODO: reduce 154 | float ay = Math.abs(y); 155 | float xy = x*y; // this is xor of sign of x & y...probably removable. 156 | float r = 0; 157 | 158 | // perform argument reduction. probably can be reduced 159 | if (x < 0) { x = -x; r = -PI; } 160 | if (ay > x) { float t = x; x = ay; ay = -t; r += PI_OVER_2; } 161 | 162 | // perform the approximation..increasing speed or accuracy by 163 | // trading the base approximation possible 164 | r += atan_5(ay/x); 165 | 166 | // xor the sign of reduced range with the input for final result.. 167 | // again all of this could probably be cleaned up with some thought. 168 | return mulSign(r, xy); 169 | } 170 | 171 | /** 172 | * atan(y,x), where y >=0 and x >=0. 173 | *

    174 | * */ 175 | // blah 176 | public static final float atanpp(float y, float x) 177 | { 178 | if (x <= y) return atan_5(y/x); 179 | 180 | return PI_OVER_2 - atan_5(x/y); 181 | } 182 | 183 | /** 184 | * atan of x on [0,Inf] 185 | */ 186 | public static final float atanp(float x) 187 | { 188 | // ignoring numeric issues around '1' due to the subtract, 189 | // same error bound as core routine, stretched out over 190 | // the interval. 191 | return PI_OVER_4 + atan_5((x-1)/(x+1)); 192 | } 193 | 194 | /** atan of x on [-Inf, Inf] */ 195 | public static final float atan(float x) 196 | { 197 | //int ix = Float.floatToRawIntBits(x); 198 | //int ax = 0x7fffffff & ix; 199 | //int sz = B_ONE | (ix^ax); // 64-bit maybe - mask ix instead 200 | //x = Float.intBitsToFloat(ax); 201 | //x = atap(x); 202 | //x *= sx; 203 | 204 | // TODO: change to local and unfold 205 | float r = atanp(Math.abs(x)); 206 | 207 | return Math.copySign(r, x); // TODO: 208 | } 209 | 210 | /** 211 | *

    212 | * NEVER CALL ME 213 | */ 214 | /* 215 | public static final float asin(float a) 216 | { 217 | // range reduction 218 | int ia = Float.floatToRawIntBits(a); 219 | int aa = (0x7fffffff & ia); // |a| 220 | int sa = (0x80000000 & ia) | B_ONE; // a < 0 ? -1 : 1 221 | float d = Float.intBitsToFloat(aa); // |a| 222 | float m = Float.intBitsToFloat(sa); // {-1,1} 223 | 224 | // atan(+,+); 225 | d = (float)Math.atan2(d, Math.sqrt((1.f+d)*(1.f-d))); 226 | 227 | return m*d; 228 | } 229 | */ 230 | 231 | // NOTE: simply comment out higher order terms 232 | // in exp2 to use a lower quality/faster approximation 233 | 234 | // 3rd order: 14 good bits 235 | /** 236 | private static final float EXP2_0 = 0xf.ff8fcp-4f; 237 | private static final float EXP2_1 = 0xb.24b09p-4f; 238 | private static final float EXP2_2 = 0x3.96e3dp-4f; 239 | private static final float EXP2_3 = 0x1.446bap-4f; 240 | */ 241 | 242 | // 4th order: 17 good bits 243 | /** 244 | private static final float EXP2_0 = 0x1.00002cp0f; 245 | private static final float EXP2_1 = 0x1.62d166p-1f; 246 | private static final float EXP2_2 = 0x1.ee798ap-3f; 247 | private static final float EXP2_3 = 0x1.aa13fp-5f; 248 | private static final float EXP2_4 = 0x1.bb7cd4p-7f; 249 | */ 250 | 251 | 252 | // 5th order: 21 good bits 253 | private static final float EXP2_0 = 0xf.ffffep-4f; 254 | private static final float EXP2_1 = 0xb.1729ap-4f; 255 | private static final float EXP2_2 = 0x3.d79c1p-4f; 256 | private static final float EXP2_3 = 0xe.4d4cp-8f; 257 | private static final float EXP2_4 = 0x2.4a14p-8f; 258 | private static final float EXP2_5 = 0x7.c45p-12f; 259 | 260 | 261 | /** 262 | * Calculates: 2x 263 | */ 264 | 265 | public static final float exp2(float x) 266 | { 267 | int a = (int)x; 268 | float b = x-a; 269 | float r = 0; 270 | 271 | //r = b*(r + EXP2_6); 272 | r = b*(r + EXP2_5); 273 | r = b*(r + EXP2_4); 274 | r = b*(r + EXP2_3); 275 | r = b*(r + EXP2_2); 276 | r = b*(r + EXP2_1); 277 | r = (r + EXP2_0); 278 | 279 | return exp2(a)*r; 280 | } 281 | 282 | 283 | // Result accurate to 22 bits (on primary range). 284 | private static final float LOG2_1 = 0x1.71547ap1f; 285 | private static final float LOG2_2 = 0x1.ec554ep-1f; 286 | private static final float LOG2_3 = 0x1.310a2cp-1f; 287 | 288 | 289 | /** 290 | * Calculates: Log2 x 291 | *

    292 | * Accuracy: 22 bits (in normal range) 293 | */ 294 | 295 | public static final float log2(float x) 296 | { 297 | int i = Float.floatToRawIntBits(x); 298 | int e = ((i >>> 23) & 0xff)-127; 299 | float y = Float.intBitsToFloat(i - (e<<23)); 300 | float r = (y-SQRT_2)/(y+SQRT_2); 301 | float b = r * r; 302 | float a; 303 | 304 | // Approximate via ArcTanh: 305 | a = r*(LOG2_1 + b*(LOG2_2 + b*LOG2_3)); 306 | 307 | return 0.5f + e + a; 308 | } 309 | 310 | /** 311 | * Calculates: ex 312 | *

    313 | */ 314 | public static final float exp(float x) 315 | { 316 | return exp2(x * ONE_OVER_LOG_2); 317 | } 318 | 319 | /** 320 | * Calculates: xy 321 | */ 322 | public static final float powf(float x, float y) 323 | { 324 | return exp2(y * log2(x)); 325 | } 326 | 327 | /** 328 | * Calculates: xn 329 | */ 330 | public static final float pow(float x, int n) 331 | { 332 | float r = 1.f; 333 | int e = n; 334 | 335 | if (n < 0) 336 | e = -n; 337 | 338 | do { 339 | if ((e & 1) != 0) r *= x; 340 | 341 | e >>>= 1; 342 | 343 | if (e != 0) { 344 | x *= x; 345 | continue; 346 | } 347 | 348 | if (n >= 0) 349 | return r; 350 | 351 | return 1/r; 352 | 353 | } while(true); 354 | } 355 | 356 | /** 357 | * Calculates: Log x 358 | */ 359 | public static final float log(float x) 360 | { 361 | return log2(x) * LOG_2; 362 | } 363 | 364 | /** 365 | * Calculates: Log10 x 366 | */ 367 | public static final float log10(float x) 368 | { 369 | return log2(x) * LOG_2_OVER_LOG_10; 370 | } 371 | 372 | /** 373 | * Calculates: 2x for inputs on [-127, 128]. 374 | *

    375 | * The result is exact for valid input values, 376 | * otherwise the result is undefined. 377 | */ 378 | public static final float exp2(int x) 379 | { 380 | return Float.intBitsToFloat((x+127)<<23); 381 | } 382 | 383 | /** 384 | * Calculates: 2x for inputs on [0, 30]. 385 | *

    386 | * The result is exact for valid input values, 387 | * otherwise the result is undefined. 388 | */ 389 | public static final float exp2ps(int x) 390 | { 391 | return 1<x for inputs on [-30, 0]. 396 | *

    397 | * The result is exact for valid input values, 398 | * otherwise the result is undefined. 399 | */ 400 | public static final float exp2ns(int x) 401 | { 402 | return 0x1.p-30f * (1<<(30+x)); 403 | } 404 | 405 | 406 | /** 407 | * Returns the IEEE complaint bit format, converting any negative zero to zero. 408 | * Does not normalized NaNs. Intended for hashing. 409 | */ 410 | public static final int toBits(float x) 411 | { 412 | return Float.floatToRawIntBits(0.f+x); 413 | } 414 | 415 | // Everything below here is very questionable in usefulness 416 | 417 | // HotSpot doesn't give access to various SIMD opcode sets 418 | // rsqrt approximations. 419 | 420 | /** 421 | * Make an initial guess for 1/sqrt(x) using Chris Lomont's "magic" number 422 | */ 423 | public static final float rsqrtGuess(float x) 424 | { 425 | int i = 0x5f375a86 - (Float.floatToRawIntBits(x) >>> 1); 426 | float g = Float.intBitsToFloat(i); 427 | return g; 428 | } 429 | 430 | /** 431 | * Approximate 1/sqrt(x) from initial guess g using 432 | * 1 step of Newton's method. 433 | *

    434 | */ 435 | public static final float rsqrt_1(float x, float g) 436 | { 437 | float hx = x * 0.5f; 438 | g = g*(1.5f-hx*g*g); 439 | return g; 440 | } 441 | 442 | /** 443 | * Performs two Newton's steps. 444 | *

    445 | * @see #rsqrt_1(float, float) 446 | */ 447 | public static final float rsqrt_2(float x, float g) 448 | { 449 | float hx = x * 0.5f; 450 | g = g*(1.5f-hx*g*g); 451 | g = g*(1.5f-hx*g*g); 452 | return g; 453 | } 454 | } 455 | --------------------------------------------------------------------------------