mod-double-power-of-two.js (4955B)
1 const isLittleEndian = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1; 2 3 function fromRawBits(s) { 4 let bits = s.split(" ").map(n => parseInt(n, 16)); 5 assertEq(bits.length, 8); 6 if (isLittleEndian) { 7 bits.reverse(); 8 } 9 return new Float64Array(new Uint8Array(bits).buffer)[0]; 10 } 11 12 function toRawBits(d) { 13 let bits = [...new Uint8Array(new Float64Array([d]).buffer)]; 14 if (isLittleEndian) { 15 bits.reverse(); 16 } 17 return bits.map(n => n.toString(16).padStart(2, "0")).join(" "); 18 } 19 20 assertEq(fromRawBits("7f ef ff ff ff ff ff ff"), Number.MAX_VALUE); 21 assertEq(toRawBits(Number.MAX_VALUE), "7f ef ff ff ff ff ff ff"); 22 23 assertEq(fromRawBits("00 00 00 00 00 00 00 01"), Number.MIN_VALUE); 24 assertEq(toRawBits(Number.MIN_VALUE), "00 00 00 00 00 00 00 01"); 25 26 let values = [ 27 0, 0.000001, 0.1, 0.125, 1/6, 0.25, 0.3, 1/3, 0.5, 2/3, 0.8, 0.9, 28 1, 2, 3, 4, 5, 10, 14, 15, 16, 29 100.1, 100.2, 30 31 Number.MAX_SAFE_INTEGER + 4, 32 Number.MAX_SAFE_INTEGER + 3, 33 Number.MAX_SAFE_INTEGER + 2, 34 Number.MAX_SAFE_INTEGER + 1, 35 Number.MAX_SAFE_INTEGER, 36 Number.MAX_SAFE_INTEGER - 1, 37 Number.MAX_SAFE_INTEGER - 2, 38 Number.MAX_SAFE_INTEGER - 3, 39 Number.MAX_SAFE_INTEGER - 4, 40 41 // Largest normal (Number.MAX_VALUE) 42 fromRawBits("7f ef ff ff ff ff ff ff"), 43 fromRawBits("7f ef ff ff ff ff ff fe"), 44 fromRawBits("7f ef ff ff ff ff ff fd"), 45 fromRawBits("7f ef ff ff ff ff ff fc"), 46 fromRawBits("7f ef ff ff ff ff ff fb"), 47 fromRawBits("7f ef ff ff ff ff ff fa"), 48 fromRawBits("7f ef ff ff ff ff ff f9"), 49 fromRawBits("7f ef ff ff ff ff ff f8"), 50 fromRawBits("7f ef ff ff ff ff ff f7"), 51 fromRawBits("7f ef ff ff ff ff ff f6"), 52 fromRawBits("7f ef ff ff ff ff ff f5"), 53 fromRawBits("7f ef ff ff ff ff ff f4"), 54 fromRawBits("7f ef ff ff ff ff ff f3"), 55 fromRawBits("7f ef ff ff ff ff ff f2"), 56 fromRawBits("7f ef ff ff ff ff ff f1"), 57 fromRawBits("7f ef ff ff ff ff ff f0"), 58 59 // Smallest subnormal (Number.MIN_VALUE) 60 fromRawBits("00 00 00 00 00 00 00 01"), 61 fromRawBits("00 00 00 00 00 00 00 02"), 62 fromRawBits("00 00 00 00 00 00 00 03"), 63 fromRawBits("00 00 00 00 00 00 00 04"), 64 fromRawBits("00 00 00 00 00 00 00 05"), 65 fromRawBits("00 00 00 00 00 00 00 06"), 66 fromRawBits("00 00 00 00 00 00 00 07"), 67 fromRawBits("00 00 00 00 00 00 00 08"), 68 fromRawBits("00 00 00 00 00 00 00 09"), 69 fromRawBits("00 00 00 00 00 00 00 0a"), 70 fromRawBits("00 00 00 00 00 00 00 0b"), 71 fromRawBits("00 00 00 00 00 00 00 0c"), 72 fromRawBits("00 00 00 00 00 00 00 0d"), 73 fromRawBits("00 00 00 00 00 00 00 0e"), 74 fromRawBits("00 00 00 00 00 00 00 0f"), 75 76 // Largest subnormal 77 fromRawBits("00 0f ff ff ff ff ff ff"), 78 fromRawBits("00 0f ff ff ff ff ff fe"), 79 fromRawBits("00 0f ff ff ff ff ff fd"), 80 fromRawBits("00 0f ff ff ff ff ff fc"), 81 fromRawBits("00 0f ff ff ff ff ff fb"), 82 fromRawBits("00 0f ff ff ff ff ff fa"), 83 fromRawBits("00 0f ff ff ff ff ff f9"), 84 fromRawBits("00 0f ff ff ff ff ff f8"), 85 fromRawBits("00 0f ff ff ff ff ff f7"), 86 fromRawBits("00 0f ff ff ff ff ff f6"), 87 fromRawBits("00 0f ff ff ff ff ff f5"), 88 fromRawBits("00 0f ff ff ff ff ff f4"), 89 fromRawBits("00 0f ff ff ff ff ff f3"), 90 fromRawBits("00 0f ff ff ff ff ff f2"), 91 fromRawBits("00 0f ff ff ff ff ff f1"), 92 fromRawBits("00 0f ff ff ff ff ff f0"), 93 94 // Least positive normal 95 fromRawBits("00 10 00 00 00 00 00 00"), 96 fromRawBits("00 10 00 00 00 00 00 01"), 97 fromRawBits("00 10 00 00 00 00 00 02"), 98 fromRawBits("00 10 00 00 00 00 00 03"), 99 fromRawBits("00 10 00 00 00 00 00 04"), 100 fromRawBits("00 10 00 00 00 00 00 05"), 101 fromRawBits("00 10 00 00 00 00 00 06"), 102 fromRawBits("00 10 00 00 00 00 00 07"), 103 fromRawBits("00 10 00 00 00 00 00 08"), 104 fromRawBits("00 10 00 00 00 00 00 09"), 105 fromRawBits("00 10 00 00 00 00 00 0a"), 106 fromRawBits("00 10 00 00 00 00 00 0b"), 107 fromRawBits("00 10 00 00 00 00 00 0c"), 108 fromRawBits("00 10 00 00 00 00 00 0d"), 109 fromRawBits("00 10 00 00 00 00 00 0e"), 110 fromRawBits("00 10 00 00 00 00 00 0f"), 111 112 Infinity, 113 NaN, 114 115 Math.E, Math.LN10, Math.LN2, Math.LOG10E, Math.LOG2E, 116 Math.PI, Math.SQRT1_2, Math.SQRT2, 117 ]; 118 119 // Also test with sign bit set. 120 values = values.concat(values.map(x => -x)); 121 122 function mod(n, d) { 123 with ({}); // disable Ion 124 return n % d; 125 } 126 127 function makeTest(divisor) { 128 function test() { 129 let expected = values.map(x => mod(x, divisor)); 130 131 for (let i = 0; i < 2000; ++i) { 132 let j = i % values.length; 133 assertEq(values[j] % divisor, expected[j]); 134 } 135 } 136 137 // Create a new function for each divisor to ensure we have proper compile-time constants. 138 return Function(`return ${test.toString().replaceAll("divisor", divisor)}`)(); 139 } 140 141 // The optimisation is used for power of two values up to 2^31. 142 for (let i = 0; i <= 31; ++i) { 143 let divisor = 2 ** i; 144 let f = makeTest(divisor); 145 f(); 146 } 147 148 // Also cover some cases which don't trigger the optimisation 149 for (let divisor of [-3, -2, -1, -0.5, 0, 0.5, 3, 5, 10]) { 150 let f = makeTest(divisor); 151 f(); 152 }