|
| 1 | +module.exports.frexp = function frexp (arg) { // -> [number x, int11 exp] |
| 2 | + // original by: Oskar Larsson Högfeldt (http://oskar-lh.name/) |
| 3 | + // example 1: frexp(1) |
| 4 | + // returns 1: [0.5, 1] |
| 5 | + // example 2: frexp(1.5) |
| 6 | + // returns 2: [0.75, 1] |
| 7 | + // example 3: frexp(3 * Math.pow(2, 500)) |
| 8 | + // returns 3: [0.75, 502] |
| 9 | + // example 4: frexp(-4) |
| 10 | + // returns 4: [-0.5, 3] |
| 11 | + // example 5: frexp(Number.MAX_VALUE) |
| 12 | + // returns 5: [0.9999999999999999, 1024] |
| 13 | + // example 6: frexp(Number.MIN_VALUE) |
| 14 | + // returns 6: [0.5, -1073] |
| 15 | + // example 7: frexp(-Infinity) |
| 16 | + // returns 7: [-Infinity, 0] |
| 17 | + // example 8: frexp(-0) |
| 18 | + // returns 8: [-0, 0] |
| 19 | + // example 9: frexp(NaN) |
| 20 | + // returns 9: [NaN, 0] |
| 21 | + |
| 22 | + // Potential issue with this implementation: |
| 23 | + // the precision of Math.pow and the ** operator are undefined in the ECMAScript standard, |
| 24 | + // however, sane implementations should give the same results for Math.pow(2, <integer>) operations |
| 25 | + |
| 26 | + // Like frexp of C and std::frexp of C++, |
| 27 | + // but returns an array instead of using a pointer argument for passing the exponent result. |
| 28 | + // Object.is(n, frexp(n)[0] * 2 ** frexp(n)[1]) for all number values of n except when Math.isFinite(n) && Math.abs(n) > 2**1023 |
| 29 | + // Object.is(n, (2 * frexp(n)[0]) * 2 ** (frexp(n)[1] - 1)) for all number values of n |
| 30 | + // Object.is(n, frexp(n)[0]) for these values of n: 0, -0, NaN, Infinity, -Infinity |
| 31 | + // Math.abs(frexp(n)[0]) is >= 0.5 and < 1.0 for any other number-type value of n |
| 32 | + // See http://en.cppreference.com/w/cpp/numeric/math/frexp for a more detailed description |
| 33 | + |
| 34 | + arg = Number(arg) |
| 35 | + |
| 36 | + let result = [arg, 0] |
| 37 | + |
| 38 | + if (arg !== 0 && Number.isFinite(arg)) { |
| 39 | + const absArg = Math.abs(arg) |
| 40 | + let exp = Math.max(-1023, Math.floor(Math.log2(absArg)) + 1) |
| 41 | + let x = absArg * 2 ** -exp |
| 42 | + |
| 43 | + // These while loops compensate for rounding errors that sometimes occur because of ECMAScript's Math.log2's undefined precision |
| 44 | + // and also works around the issue of 2 ** exp === Infinity when exp >= 1024 |
| 45 | + while (x < 0.5) { |
| 46 | + x *= 2 |
| 47 | + exp-- |
| 48 | + } |
| 49 | + while (x >= 1) { |
| 50 | + x *= 0.5 |
| 51 | + exp++ |
| 52 | + } |
| 53 | + |
| 54 | + x *= Math.sign(arg) |
| 55 | + result[0] = x |
| 56 | + result[1] = exp |
| 57 | + } |
| 58 | + return result |
| 59 | +} |
0 commit comments