From 3eed7d239f1c103a9ed324719068a9b4a8132444 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 17 Jan 2026 16:10:04 -0700 Subject: [PATCH 1/4] nit: remove frequency from white noise and implement sampler directly, as frequency here is just a second, slower salt. --- .../noise/random/WhiteNoiseBenchmark.java | 86 +++++++++++++++++++ .../sampler/noise/GaborSampler.java | 2 +- .../noise/random/GaussianNoiseSampler.java | 16 ++-- .../random/PositiveWhiteNoiseSampler.java | 14 +-- .../noise/random/WhiteNoiseSampler.java | 16 ++-- 5 files changed, 114 insertions(+), 20 deletions(-) create mode 100644 src/jmh/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseBenchmark.java diff --git a/src/jmh/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseBenchmark.java b/src/jmh/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseBenchmark.java new file mode 100644 index 0000000..dad6fd7 --- /dev/null +++ b/src/jmh/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseBenchmark.java @@ -0,0 +1,86 @@ +package com.dfsek.seismic.algorithms.sampler.noise.random; + +import com.dfsek.seismic.algorithms.sampler.noise.NoiseFunction; +import com.dfsek.seismic.type.sampler.Sampler; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.SECONDS) +public class WhiteNoiseBenchmark { + + private WhiteNoiseSampler f; + + private long seed; + private int startX; + private int startY; + private int startZ; + + @Setup + public void setup() { + f = new WhiteNoiseSampler(123123); + + Random r = new Random(); + startX = r.nextInt(10000); + startY = r.nextInt(10000); + startZ = r.nextInt(10000); + + seed = r.nextLong(); + } + + @Benchmark + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 5) + public double benchmarkWhiteNoise3D() { + double sum = 0.0; + + int sx = startX; + int sy = startY; + int sz = startZ; + long s = seed; + WhiteNoiseSampler ns = f; + + for(int x = 0; x < 16; x++) { + for(int z = 0; z < 16; z++) { + for(int y = 0; y < 384; y++) { + sum += ns.getSample(s, sx + x, sy + y, sz + z); + } + } + } + return sum; + } + + @Benchmark + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 5) + public double benchmarkWhiteNoise2D() { + double sum = 0.0; + + int sx = startX; + int sy = startY; + long s = seed; + WhiteNoiseSampler ns = f; + + for(int x = 0; x < 16; x++) { + for(int y = 0; y < 16; y++) { + sum += ns.getSample(s, sx + x, sy + y); + } + } + return sum; + } +} diff --git a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/GaborSampler.java b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/GaborSampler.java index 061dd77..b76b9d4 100644 --- a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/GaborSampler.java +++ b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/GaborSampler.java @@ -40,7 +40,7 @@ public GaborSampler(double frequency, long salt, double frequency0, double devia double impulsesPerCell = impulseDensity * kernelRadius * kernelRadius; g = Math.exp(-impulsesPerCell); - rand = new WhiteNoiseSampler(frequency, salt); + rand = new WhiteNoiseSampler(salt); } private double gaborNoise(long seed, double x, double y) { diff --git a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/GaussianNoiseSampler.java b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/GaussianNoiseSampler.java index 6426155..e29ecc8 100644 --- a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/GaussianNoiseSampler.java +++ b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/GaussianNoiseSampler.java @@ -9,21 +9,24 @@ import com.dfsek.seismic.algorithms.sampler.noise.NoiseFunction; +import com.dfsek.seismic.type.sampler.Sampler; /** * NoiseSampler implementation to provide random, normally distributed (Gaussian) noise. */ -public class GaussianNoiseSampler extends NoiseFunction { +public class GaussianNoiseSampler implements Sampler { private final WhiteNoiseSampler whiteNoiseSampler; // Back with a white noise sampler. + private final long salt; - public GaussianNoiseSampler(double frequency, long salt) { - super(frequency, salt); - whiteNoiseSampler = new WhiteNoiseSampler(frequency, salt); + public GaussianNoiseSampler(long salt) { + this.salt = salt; + whiteNoiseSampler = new WhiteNoiseSampler(0); } @Override - public double getNoiseRaw(long seed, double x, double y) { + public double getSample(long seed, double x, double y) { + seed += salt; // saves us a few adds double v1, v2, s; do { v1 = whiteNoiseSampler.getSample(seed++, x, y); @@ -35,7 +38,8 @@ public double getNoiseRaw(long seed, double x, double y) { } @Override - public double getNoiseRaw(long seed, double x, double y, double z) { + public double getSample(long seed, double x, double y, double z) { + seed += salt; // saves us a few adds double v1, v2, s; do { v1 = whiteNoiseSampler.getSample(seed++, x, y, z); diff --git a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/PositiveWhiteNoiseSampler.java b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/PositiveWhiteNoiseSampler.java index cedc6d6..a2a7b6c 100644 --- a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/PositiveWhiteNoiseSampler.java +++ b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/PositiveWhiteNoiseSampler.java @@ -16,9 +16,11 @@ */ public class PositiveWhiteNoiseSampler extends WhiteNoiseSampler { private static final long POSITIVE_POW1 = 0b01111111111L << 52; + private final long salt; - public PositiveWhiteNoiseSampler(double frequency, long salt) { - super(frequency, salt); + public PositiveWhiteNoiseSampler(long salt) { + super(salt); + this.salt = salt; } // Bits that when applied to the exponent/sign section of a double, produce a positive number with a power of 1. @@ -28,12 +30,12 @@ public double getNoiseRaw(long seed) { } @Override - public double getNoiseRaw(long seed, double x, double y) { - return (WhiteNoiseSampler.getNoiseUnmapped(seed, x, y) - 1); + public double getSample(long seed, double x, double y) { + return (WhiteNoiseSampler.getNoiseUnmapped(seed + salt, x, y) - 1); } @Override - public double getNoiseRaw(long seed, double x, double y, double z) { - return (WhiteNoiseSampler.getNoiseUnmapped(seed, x, y, z) - 1); + public double getSample(long seed, double x, double y, double z) { + return (WhiteNoiseSampler.getNoiseUnmapped(seed + salt, x, y, z) - 1); } } diff --git a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java index 2a4d212..bc6dbb6 100644 --- a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java +++ b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java @@ -9,17 +9,19 @@ import com.dfsek.seismic.algorithms.hashing.HashingFunctions; import com.dfsek.seismic.algorithms.sampler.noise.NoiseFunction; +import com.dfsek.seismic.type.sampler.Sampler; /** * NoiseSampler implementation to produce random, uniformly distributed (white) noise. */ -public class WhiteNoiseSampler extends NoiseFunction { +public class WhiteNoiseSampler implements Sampler { private static final long POSITIVE_POW1 = 0b01111111111L << 52; + private final long salt; // Bits that when applied to the exponent/sign section of a double, produce a positive number with a power of 1. - public WhiteNoiseSampler(double frequency, long salt) { - super(frequency, salt); + public WhiteNoiseSampler(long salt) { + this.salt = salt; } public static long randomBits(long seed, double x, double y, double z) { @@ -53,12 +55,12 @@ public double getNoiseRaw(long seed) { } @Override - public double getNoiseRaw(long seed, double x, double y) { - return (WhiteNoiseSampler.getNoiseUnmapped(seed, x, y) - 1.5) * 2; + public double getSample(long seed, double x, double y) { + return (WhiteNoiseSampler.getNoiseUnmapped(seed + salt, x, y) - 1.5) * 2; } @Override - public double getNoiseRaw(long seed, double x, double y, double z) { - return (WhiteNoiseSampler.getNoiseUnmapped(seed, x, y, z) - 1.5) * 2; + public double getSample(long seed, double x, double y, double z) { + return (WhiteNoiseSampler.getNoiseUnmapped(seed + salt, x, y, z) - 1.5) * 2; } } From d5da739cc6c7ac8fee5238fee84d0e6e4ba4cff7 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 17 Jan 2026 16:23:18 -0700 Subject: [PATCH 2/4] redo WhiteNoiseSampler bit hacks --- .../algorithms/sampler/noise/random/WhiteNoiseSampler.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java index bc6dbb6..aaf54ac 100644 --- a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java +++ b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java @@ -16,7 +16,7 @@ * NoiseSampler implementation to produce random, uniformly distributed (white) noise. */ public class WhiteNoiseSampler implements Sampler { - private static final long POSITIVE_POW1 = 0b01111111111L << 52; + private static final long POSITIVE_POW1 = 0b10000000000L << 52; private final long salt; // Bits that when applied to the exponent/sign section of a double, produce a positive number with a power of 1. @@ -50,13 +50,12 @@ public static double getNoiseUnmapped(long seed, double x, double y) { } public double getNoiseRaw(long seed) { - return (Double.longBitsToDouble((HashingFunctions.murmur64(seed) & 0x000fffffffffffffL) | WhiteNoiseSampler.POSITIVE_POW1) - 1.5) * - 2; + return Double.longBitsToDouble((HashingFunctions.murmur64(seed) & 0x000fffffffffffffL) | WhiteNoiseSampler.POSITIVE_POW1) - 3; } @Override public double getSample(long seed, double x, double y) { - return (WhiteNoiseSampler.getNoiseUnmapped(seed + salt, x, y) - 1.5) * 2; + return WhiteNoiseSampler.getNoiseUnmapped(seed + salt, x, y) - 3; } @Override From d78c4c00e7cfae0b4dc62646e07cc16628b63d89 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 17 Jan 2026 16:26:48 -0700 Subject: [PATCH 3/4] fix PositiveWhiteNoiseSampler --- .../random/PositiveWhiteNoiseSampler.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/PositiveWhiteNoiseSampler.java b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/PositiveWhiteNoiseSampler.java index a2a7b6c..69d8253 100644 --- a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/PositiveWhiteNoiseSampler.java +++ b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/PositiveWhiteNoiseSampler.java @@ -24,18 +24,30 @@ public PositiveWhiteNoiseSampler(long salt) { } // Bits that when applied to the exponent/sign section of a double, produce a positive number with a power of 1. + public static double getNoiseUnmapped(long seed, double x, double y, double z) { + long base = ((WhiteNoiseSampler.randomBits(seed, x, y, z)) & 0x000fffffffffffffL) | + POSITIVE_POW1; // Sign and exponent + return Double.longBitsToDouble(base); + } + + public static double getNoiseUnmapped(long seed, double x, double y) { + long base = (WhiteNoiseSampler.randomBits(seed, x, y) & 0x000fffffffffffffL) | POSITIVE_POW1; // Sign and exponent + return Double.longBitsToDouble(base); + } + + @Override public double getNoiseRaw(long seed) { - return (Double.longBitsToDouble((HashingFunctions.murmur64(seed) & 0x000fffffffffffffL) | PositiveWhiteNoiseSampler.POSITIVE_POW1) - - 1.5) * 2; + return (Double.longBitsToDouble((HashingFunctions.murmur64(seed) & 0x000fffffffffffffL) | POSITIVE_POW1) - + 1); } @Override public double getSample(long seed, double x, double y) { - return (WhiteNoiseSampler.getNoiseUnmapped(seed + salt, x, y) - 1); + return (getNoiseUnmapped(seed + salt, x, y) - 1); } @Override public double getSample(long seed, double x, double y, double z) { - return (WhiteNoiseSampler.getNoiseUnmapped(seed + salt, x, y, z) - 1); + return (getNoiseUnmapped(seed + salt, x, y, z) - 1); } } From b132b255dd45773f271cc3f7887ea1bb21ed4c50 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 17 Jan 2026 16:54:39 -0700 Subject: [PATCH 4/4] more white noise testing --- .../noise/random/WhiteNoiseBenchmark.java | 32 +++++++++++++++++-- .../noise/random/WhiteNoiseSampler.java | 6 ++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/jmh/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseBenchmark.java b/src/jmh/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseBenchmark.java index dad6fd7..7622a6b 100644 --- a/src/jmh/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseBenchmark.java +++ b/src/jmh/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseBenchmark.java @@ -1,7 +1,5 @@ package com.dfsek.seismic.algorithms.sampler.noise.random; -import com.dfsek.seismic.algorithms.sampler.noise.NoiseFunction; -import com.dfsek.seismic.type.sampler.Sampler; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -41,6 +39,36 @@ public void setup() { seed = r.nextLong(); } + @Benchmark + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 5) + public double mask() { + double sum = 0.0; + + for(int x = 0; x < 16; x++) { + for(int z = 0; z < 16; z++) { + sum += Double.longBitsToDouble(WhiteNoiseSampler.randomBits(seed, x, z) & 0x000fffffffffffffL); + } + } + return sum; + } + + @Benchmark + @Fork(1) + @Warmup(iterations = 5, time = 1) + @Measurement(iterations = 10, time = 5) + public double shift() { + double sum = 0.0; + + for(int x = 0; x < 16; x++) { + for(int z = 0; z < 16; z++) { + sum += Double.longBitsToDouble(WhiteNoiseSampler.randomBits(seed, x, z) >>> 12); + } + } + return sum; + } + @Benchmark @Fork(1) @Warmup(iterations = 5, time = 1) diff --git a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java index aaf54ac..29b65dd 100644 --- a/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java +++ b/src/main/java/com/dfsek/seismic/algorithms/sampler/noise/random/WhiteNoiseSampler.java @@ -40,17 +40,17 @@ public static long randomBits(long seed, double x, double y) { public static double getNoiseUnmapped(long seed, double x, double y, double z) { long base = ((WhiteNoiseSampler.randomBits(seed, x, y, z)) & 0x000fffffffffffffL) | - WhiteNoiseSampler.POSITIVE_POW1; // Sign and exponent + POSITIVE_POW1; // Sign and exponent return Double.longBitsToDouble(base); } public static double getNoiseUnmapped(long seed, double x, double y) { - long base = (WhiteNoiseSampler.randomBits(seed, x, y) & 0x000fffffffffffffL) | WhiteNoiseSampler.POSITIVE_POW1; // Sign and exponent + long base = (WhiteNoiseSampler.randomBits(seed, x, y) & 0x000fffffffffffffL) | POSITIVE_POW1; // Sign and exponent return Double.longBitsToDouble(base); } public double getNoiseRaw(long seed) { - return Double.longBitsToDouble((HashingFunctions.murmur64(seed) & 0x000fffffffffffffL) | WhiteNoiseSampler.POSITIVE_POW1) - 3; + return Double.longBitsToDouble((HashingFunctions.murmur64(seed) & 0x000fffffffffffffL) | POSITIVE_POW1) - 3; } @Override