Last active
May 9, 2019 21:43
-
-
Save dfkaye/88102758495499f40bb547592281fea6 to your computer and use it in GitHub Desktop.
Get the decimal fraction of a value, if coercible to a number; exponent notation supported.
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
// 45678901234567890123456789012345678901234567890123456789012345678901234567890 | |
// 14 March 2019 - first cut. | |
// 18 March 2019 - support expontent notation. | |
// 19 March 2019 - better comment style, better return style. | |
// 9 May 2019 - fix 'a.b' ('.b' to '0'), trailing 0's ('.490' to '.49'). | |
// 9 May 2019 - fix Case 2 where e's value is less than the length of the | |
// remaining mantissa (i.e., use m.substring(e) ), and even | |
// better documentation. | |
/** | |
* @function fraction accepts param of any type and returns the decimal fraction | |
* of the value as a string, if the value is coercible to a number. | |
* | |
* If the coerced value results in null, undefined, or NaN, the function returns | |
* "0". | |
* | |
* Function accepts values in exponent notation, prepending 0's as necessary to | |
* shift decimals to the right where e is negative, or substringing decimals at | |
* index of e if e is positive but less than the number of decimals. | |
* | |
* Some examples: | |
* | |
* '9.123456789012345e-21' will return '.000000000000000000009123456789012345' | |
* '555.1111e-10' will return '.00000005551111' | |
* '2.222200000e2', will return '.22' | |
* '.123456789e8', will return '.9' | |
* | |
* @param {*} num - may be string, number, boolean, array, object... | |
* @returns {string} a fractional value coercible from the input. | |
*/ | |
function fraction(num) { | |
// First, convert input to a string and remove commas or spaces (i.e., convert | |
// '1 234.56' to 1234.567). | |
var s = String(num).replace(/[\,\s]/g, ''); | |
// Second, coerce the converted value to a number. | |
// If the value is NaN, assign as null. | |
// If it's not NaN, take the string to the right of the decimal point. | |
// If there isn't a decimal, split() returns null. | |
var m = +s === +s ? s.split('.')[1] : null; | |
// Third, check for exponent notation. | |
var e = m ? m.split('e')[1] : 0; | |
if (!e) { | |
/* | |
* Case 1: No exponent notation, so handle in normal course. | |
* If null, undefined, or NaN, return 0, else return mantissa. | |
*/ | |
return m == null || m !== m ? '0' : '.' + m.replace(/[0]+$/, ''); | |
} | |
if (+e >= 0) { | |
/* | |
* Case 2: An exponent notation has been found, its value is non-negative, | |
* so split the decimal at 'e', taking the digits to the left (before 'e'). | |
* If e is less than the length of the remaining digits, return the substring | |
* of those digits at index e; otherwise return '0'. | |
*/ | |
var t = m.split('e')[0]; | |
return e >= t.length ? '0' : '.' + t.substring(e).replace(/[0]+$/, ''); | |
} | |
/* | |
* Case 3: An exponent notation has been found, its value is negative, so | |
* insert 0's between the decimal and the value before 'e'. | |
*/ | |
// NOTE: The tilde operator converts, e.g., -8 to +7, to create a sized array. | |
var a = Array(~+e).fill(0).join(''); | |
var r = s.split('e')[0].match(/\d/g).join(''); | |
return '.' + a + r; | |
} | |
var tests = [ | |
1, 2, 3.4, 1234.5678, | |
'1,234,567.890', '1 234 567.8976', | |
0.0, -0.1, -2.2, 3.490000, | |
NaN, null, undefined, false, true, | |
'a', 'a.b', 'a.b.c', 'true', 'true.1', | |
Math, Math.round, | |
'12312231231231232112.2456789', | |
Number.POSITIVE_INFINITY, | |
Number.EPSILON, | |
".123456789e8", | |
".123456789e12", | |
2.222200000e2, | |
'2.222200000e2', | |
9.11111111015e20, | |
9.11111111015e21, | |
9.11111111015e31, | |
9.1234567890123456789e-21, | |
9.11111111015e-10, | |
0.00001111e-10, | |
555.1111e-10 | |
]; | |
var results = tests.map(function(test) { | |
return { input: String(test), result: fraction(test) }; | |
}); | |
console.log(JSON.stringify(results, '', 2)); | |
/* | |
[ | |
{ | |
"input": "1", | |
"result": "0" | |
}, | |
{ | |
"input": "2", | |
"result": "0" | |
}, | |
{ | |
"input": "3.4", | |
"result": ".4" | |
}, | |
{ | |
"input": "1234.5678", | |
"result": ".5678" | |
}, | |
{ | |
"input": "1,234,567.890", | |
"result": ".89" | |
}, | |
{ | |
"input": "1 234 567.8976", | |
"result": ".8976" | |
}, | |
{ | |
"input": "0", | |
"result": "0" | |
}, | |
{ | |
"input": "-0.1", | |
"result": ".1" | |
}, | |
{ | |
"input": "-2.2", | |
"result": ".2" | |
}, | |
{ | |
"input": "3.49", | |
"result": ".49" | |
}, | |
{ | |
"input": "NaN", | |
"result": "0" | |
}, | |
{ | |
"input": "null", | |
"result": "0" | |
}, | |
{ | |
"input": "undefined", | |
"result": "0" | |
}, | |
{ | |
"input": "false", | |
"result": "0" | |
}, | |
{ | |
"input": "true", | |
"result": "0" | |
}, | |
{ | |
"input": "a", | |
"result": "0" | |
}, | |
{ | |
"input": "a.b", | |
"result": "0" | |
}, | |
{ | |
"input": "a.b.c", | |
"result": "0" | |
}, | |
{ | |
"input": "true", | |
"result": "0" | |
}, | |
{ | |
"input": "true.1", | |
"result": "0" | |
}, | |
{ | |
"input": "[object Math]", | |
"result": "0" | |
}, | |
{ | |
"input": "function round() {\n [native code]\n}", | |
"result": "0" | |
}, | |
{ | |
"input": "12312231231231232112.2456789", | |
"result": ".2456789" | |
}, | |
{ | |
"input": "Infinity", | |
"result": "0" | |
}, | |
{ | |
"input": "2.220446049250313e-16", | |
"result": ".0000000000000002220446049250313" | |
}, | |
{ | |
"input": ".123456789e8", | |
"result": ".9" | |
}, | |
{ | |
"input": ".123456789e12", | |
"result": "0" | |
}, | |
{ | |
"input": "222.22", | |
"result": ".22" | |
}, | |
{ | |
"input": "2.222200000e2", | |
"result": ".22" | |
}, | |
{ | |
"input": "911111111015000000000", | |
"result": "0" | |
}, | |
{ | |
"input": "9.11111111015e+21", | |
"result": "0" | |
}, | |
{ | |
"input": "9.11111111015e+31", | |
"result": "0" | |
}, | |
{ | |
"input": "9.123456789012345e-21", | |
"result": ".000000000000000000009123456789012345" | |
}, | |
{ | |
"input": "9.11111111015e-10", | |
"result": ".000000000911111111015" | |
}, | |
{ | |
"input": "1.111e-15", | |
"result": ".000000000000001111" | |
}, | |
{ | |
"input": "5.551111e-8", | |
"result": ".00000005551111" | |
} | |
] | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment