shell.js (3054B)
1 /*--- 2 defines: [assertNear] 3 allow_unused: True 4 ---*/ 5 6 // The nearest representable values to +1.0. 7 const ONE_PLUS_EPSILON = 1 + Math.pow(2, -52); // 0.9999999999999999 8 const ONE_MINUS_EPSILON = 1 - Math.pow(2, -53); // 1.0000000000000002 9 10 { 11 const fail = function (msg) { 12 var exc = new Error(msg); 13 try { 14 // Try to improve on exc.fileName and .lineNumber; leave exc.stack 15 // alone. We skip two frames: fail() and its caller, an assertX() 16 // function. 17 var frames = exc.stack.trim().split("\n"); 18 if (frames.length > 2) { 19 var m = /@([^@:]*):([0-9]+)$/.exec(frames[2]); 20 if (m) { 21 exc.fileName = m[1]; 22 exc.lineNumber = +m[2]; 23 } 24 } 25 } catch (ignore) { throw ignore;} 26 throw exc; 27 }; 28 29 let ENDIAN; // 0 for little-endian, 1 for big-endian. 30 31 // Return the difference between the IEEE 754 bit-patterns for a and b. 32 // 33 // This is meaningful when a and b are both finite and have the same 34 // sign. Then the following hold: 35 // 36 // * If a === b, then diff(a, b) === 0. 37 // 38 // * If a !== b, then diff(a, b) === 1 + the number of representable values 39 // between a and b. 40 // 41 const f = new Float64Array([0, 0]); 42 const u = new Uint32Array(f.buffer); 43 const diff = function (a, b) { 44 f[0] = a; 45 f[1] = b; 46 //print(u[1].toString(16) + u[0].toString(16) + " " + u[3].toString(16) + u[2].toString(16)); 47 return Math.abs((u[3-ENDIAN] - u[1-ENDIAN]) * 0x100000000 + u[2+ENDIAN] - u[0+ENDIAN]); 48 }; 49 50 // Set ENDIAN to the platform's endianness. 51 ENDIAN = 0; // try little-endian first 52 if (diff(2, 4) === 0x100000) // exact wrong answer we'll get on a big-endian platform 53 ENDIAN = 1; 54 assertEq(diff(2,4), 0x10000000000000); 55 assertEq(diff(0, Number.MIN_VALUE), 1); 56 assertEq(diff(1, ONE_PLUS_EPSILON), 1); 57 assertEq(diff(1, ONE_MINUS_EPSILON), 1); 58 59 var assertNear = function assertNear(a, b, tolerance=1) { 60 if (!Number.isFinite(b)) { 61 fail("second argument to assertNear (expected value) must be a finite number"); 62 } else if (Number.isNaN(a)) { 63 fail("got NaN, expected a number near " + b); 64 } else if (!Number.isFinite(a)) { 65 if (b * Math.sign(a) < Number.MAX_VALUE) 66 fail("got " + a + ", expected a number near " + b); 67 } else if (a !== b) { 68 // When the two arguments do not have the same sign bit, diff() 69 // returns some huge number. So if b is positive or negative 0, 70 // make target the zero that has the same sign bit as a. 71 var target = b === 0 ? a * 0 : b; 72 var err = diff(a, target); 73 if (err > tolerance) { 74 fail("got " + a + ", expected a number near " + b + 75 " (relative error: " + err + ")"); 76 } 77 } 78 }; 79 }