-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Original code by NONPLAYT You can find the original code on https://github.com/DivineMC/DivineMC
- Loading branch information
Showing
1 changed file
with
121 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> | ||
Date: Sat, 25 May 2024 18:39:17 +0300 | ||
Subject: [PATCH] Divine: lithium: math.sine_lut | ||
|
||
Original code by NONPLAYT | ||
You can find the original code on https://github.com/DivineMC/DivineMC | ||
|
||
diff --git a/src/main/java/net/minecraft/util/Mth.java b/src/main/java/net/minecraft/util/Mth.java | ||
index c8da0247f76eb9c2c6247833d97ffc9de0538c52..6994aabad832118c4f8ff0f95a25286cf28a27f1 100644 | ||
--- a/src/main/java/net/minecraft/util/Mth.java | ||
+++ b/src/main/java/net/minecraft/util/Mth.java | ||
@@ -46,11 +46,11 @@ public class Mth { | ||
private static final double[] COS_TAB = new double[257]; | ||
|
||
public static float sin(float value) { | ||
- return SIN[(int)(value * 10430.378F) & 65535]; | ||
+ return space.bxteam.divinemc.util.lithium.CompactSineLUT.sin(value); // DivineMC - lithium: math.sine_lut | ||
} | ||
|
||
public static float cos(float value) { | ||
- return SIN[(int)(value * 10430.378F + 16384.0F) & 65535]; | ||
+ return space.bxteam.divinemc.util.lithium.CompactSineLUT.cos(value); // DivineMC - lithium: math.sine_lut | ||
} | ||
|
||
public static float sqrt(float value) { | ||
diff --git a/src/main/java/space/bxteam/divinemc/util/lithium/CompactSineLUT.java b/src/main/java/space/bxteam/divinemc/util/lithium/CompactSineLUT.java | ||
new file mode 100644 | ||
index 0000000000000000000000000000000000000000..5bc889cdbe02031d8aa90581ac557eaed3d5a6d0 | ||
--- /dev/null | ||
+++ b/src/main/java/space/bxteam/divinemc/util/lithium/CompactSineLUT.java | ||
@@ -0,0 +1,88 @@ | ||
+package space.bxteam.divinemc.util.lithium; | ||
+ | ||
+import net.minecraft.util.Mth; | ||
+ | ||
+/** | ||
+ * A replacement for the sine angle lookup table used in {@link Mth}, both reducing the size of LUT and improving | ||
+ * the access patterns for common paired sin/cos operations. | ||
+ * <p> | ||
+ * sin(-x) = -sin(x) | ||
+ * ... to eliminate negative angles from the LUT. | ||
+ * <p> | ||
+ * sin(x) = sin(pi/2 - x) | ||
+ * ... to eliminate supplementary angles from the LUT. | ||
+ * <p> | ||
+ * Using these identities allows us to reduce the LUT from 64K entries (256 KB) to just 16K entries (64 KB), enabling | ||
+ * it to better fit into the CPU's caches at the expense of some cycles on the fast path. The implementation has been | ||
+ * tightly optimized to avoid branching where possible and to use very quick integer operations. | ||
+ * <p> | ||
+ * Generally speaking, reducing the size of a lookup table is always a good optimization, but since we need to spend | ||
+ * extra CPU cycles trying to maintain parity with vanilla, there is the potential risk that this implementation ends | ||
+ * up being slower than vanilla when the lookup table is able to be kept in cache memory. | ||
+ * <p> | ||
+ * Unlike other "fast math" implementations, the values returned by this class are *bit-for-bit identical* with those | ||
+ * from {@link Mth}. Validation is performed during runtime to ensure that the table is correct. | ||
+ * | ||
+ * @author coderbot16 Author of the original (and very clever) <a href="https://gitlab.com/coderbot16/i73/-/tree/master/i73-trig/src">implementation</a> in Rust | ||
+ * @author jellysquid3 Additional optimizations, port to Java | ||
+ */ | ||
+public class CompactSineLUT { | ||
+ private static final int[] SIN_INT = new int[16384 + 1]; | ||
+ private static final float SIN_MIDPOINT; | ||
+ | ||
+ static { | ||
+ // Copy the sine table, covering to raw int bits | ||
+ for (int i = 0; i < SIN_INT.length; i++) { | ||
+ SIN_INT[i] = Float.floatToRawIntBits(Mth.SIN[i]); | ||
+ } | ||
+ | ||
+ SIN_MIDPOINT = Mth.SIN[Mth.SIN.length / 2]; | ||
+ | ||
+ // Test that the lookup table is correct during runtime | ||
+ for (int i = 0; i < Mth.SIN.length; i++) { | ||
+ float expected = Mth.SIN[i]; | ||
+ float value = lookup(i); | ||
+ | ||
+ if (expected != value) { | ||
+ throw new IllegalArgumentException(String.format("LUT error at index %d (expected: %s, found: %s)", i, expected, value)); | ||
+ } | ||
+ } | ||
+ } | ||
+ | ||
+ // [VanillaCopy] Mth#sin(float) | ||
+ public static float sin(float f) { | ||
+ return lookup((int) (f * 10430.378f) & 0xFFFF); | ||
+ } | ||
+ | ||
+ // [VanillaCopy] Mth#cos(float) | ||
+ public static float cos(float f) { | ||
+ return lookup((int) (f * 10430.378f + 16384.0f) & 0xFFFF); | ||
+ } | ||
+ | ||
+ private static float lookup(int index) { | ||
+ // A special case... Is there some way to eliminate this? | ||
+ if (index == 32768) { | ||
+ return SIN_MIDPOINT; | ||
+ } | ||
+ | ||
+ // Trigonometric identity: sin(-x) = -sin(x) | ||
+ // Given a domain of 0 <= x <= 2*pi, just negate the value if x > pi. | ||
+ // This allows the sin table size to be halved. | ||
+ int neg = (index & 0x8000) << 16; | ||
+ | ||
+ // All bits set if (pi/2 <= x), none set otherwise | ||
+ // Extracts the 15th bit from 'half' | ||
+ int mask = (index << 17) >> 31; | ||
+ | ||
+ // Trigonometric identity: sin(x) = sin(pi/2 - x) | ||
+ int pos = (0x8001 & mask) + (index ^ mask); | ||
+ | ||
+ // Wrap the position in the table. Moving this down to immediately before the array access | ||
+ // seems to help the Hotspot compiler optimize the bit math better. | ||
+ pos &= 0x7fff; | ||
+ | ||
+ // Fetch the corresponding value from the LUT and invert the sign bit as needed | ||
+ // This directly manipulate the sign bit on the float bits to simplify logic | ||
+ return Float.intBitsToFloat(SIN_INT[pos] ^ neg); | ||
+ } | ||
+} | ||
\ No newline at end of file |