|
| 1 | +package io.github.honhimw.uuid; |
| 2 | + |
| 3 | +import java.math.BigDecimal; |
| 4 | +import java.math.BigInteger; |
| 5 | +import java.math.RoundingMode; |
| 6 | + |
| 7 | +/// Prevent from using division. Make it as fast as possible. |
| 8 | +/// |
| 9 | +/// @author honhimW |
| 10 | +/// @since 2025-12-30 |
| 11 | +public class Maths { |
| 12 | + |
| 13 | + public static final long ONE_THOUSAND = 1_000L; |
| 14 | + public static final long ONE_MILLION = 1_000_000L; |
| 15 | + /// 1 << 10 == 1024 greater than 1000, so we just take highest 10-bits in i64, 64 - 10 = 54 |
| 16 | + public static final int NANOS_TO_MILLIS_SHIFT = 54; |
| 17 | + public static final long NANOS_TO_MILLIS_MULTIPLIER = ((1L) << NANOS_TO_MILLIS_SHIFT) / ONE_MILLION; |
| 18 | + |
| 19 | + public static final long DIV_1000_MULTIPLIER = new BigDecimal(BigInteger.ONE.shiftLeft(64)).divide(BigDecimal.valueOf(125), RoundingMode.CEILING).longValueExact(); |
| 20 | + |
| 21 | + /// Optimize division by one million |
| 22 | + /// |
| 23 | + /// @param nanos range 1_000_000 - 1_000_000_000 |
| 24 | + /// @return millis seconds |
| 25 | + public static int ns2ms(int nanos) { |
| 26 | + return (int) (((nanos + 1) * NANOS_TO_MILLIS_MULTIPLIER) >>> NANOS_TO_MILLIS_SHIFT); |
| 27 | + } |
| 28 | + |
| 29 | + /// Optimize remainder of one million |
| 30 | + /// |
| 31 | + /// @param nanos range 1_000_000 - 1_000_000_000 |
| 32 | + /// @return lower nano seconds |
| 33 | + public static int nsMod(int nanos) { |
| 34 | + int ms = ns2ms(nanos); |
| 35 | + return nanos - (int) (ms * ONE_MILLION); |
| 36 | + } |
| 37 | + |
| 38 | + /// Optimize division by one thousand. |
| 39 | + /// |
| 40 | + /// 1000 == 8 * 125 |
| 41 | + /// 1. right shift 3(>>> 3) for division by 8 |
| 42 | + /// 2. divide by 125 using the "magic number" method. For odd divisors, we can compute [#DIV_1000_MULTIPLIER] |
| 43 | + /// as the multiplier constant. |
| 44 | + /// 3. use [#multiplyHigh(long, long)] to compute the high 64 bits of the 128-bit product. |
| 45 | + /// This effectively performs floor(x / 125) for all 64‑bit inputs. |
| 46 | + /// |
| 47 | + /// @param l long value |
| 48 | + /// @return result of division by 1000 |
| 49 | + public static long div1000(long l) { |
| 50 | + l = l >>> 3; // division by 8 |
| 51 | + return multiplyHigh(l, DIV_1000_MULTIPLIER); |
| 52 | + } |
| 53 | + |
| 54 | + /// Convert the lowest 3 decimal digits of milliseconds into nanoseconds. |
| 55 | + /// |
| 56 | + /// @param millis milli seconds |
| 57 | + /// @return nano seconds |
| 58 | + public static int ms2ns(long millis) { |
| 59 | + long l = div1000(millis); |
| 60 | + l = millis - (l * ONE_THOUSAND); |
| 61 | + return (int) (l * ONE_MILLION); |
| 62 | + } |
| 63 | + |
| 64 | + /// Returns as a `long` the most significant 64 bits of the 128-bit product of two 64-bit factors. |
| 65 | + /// |
| 66 | + /// Copied from JDK9+ |
| 67 | + /// |
| 68 | + /// @param x the first value |
| 69 | + /// @param y the second value |
| 70 | + /// @return the result |
| 71 | + public static long multiplyHigh(long x, long y) { |
| 72 | + // Use technique from section 8-2 of Henry S. Warren, Jr., |
| 73 | + // Hacker's Delight (2nd ed.) (Addison Wesley, 2013), 173-174. |
| 74 | + long x1 = x >> 32; |
| 75 | + long x2 = x & 0xFFFFFFFFL; |
| 76 | + long y1 = y >> 32; |
| 77 | + long y2 = y & 0xFFFFFFFFL; |
| 78 | + |
| 79 | + long z2 = x2 * y2; |
| 80 | + long t = x1 * y2 + (z2 >>> 32); |
| 81 | + long z1 = t & 0xFFFFFFFFL; |
| 82 | + long z0 = t >> 32; |
| 83 | + z1 += x2 * y1; |
| 84 | + |
| 85 | + return x1 * y1 + z0 + (z1 >> 32); |
| 86 | + } |
| 87 | + |
| 88 | +} |
0 commit comments