guest271314 (2019-03-07T20:42:30.000Z)
guest271314 at gmail.com (2019-03-11T14:51:06.550Z)
Original concept: Integer or decimal to array and array to decimal or integer https://codegolf.meta.stackexchange.com/a/17223 Proof of concept (with bugs) function numberToArray(n) { if (Math.abs(n) == 0 || Math.abs(n) == -0) { return [n] } const r = []; let [ a, int = Number.isInteger(a), d = g = [], e = i = 0 ] = [ n || this.valueOf()]; if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } for (; ~~a; r.unshift(~~(a % 10)), a /= 10); if (!int) { for (; ~~d; g.unshift(~~(d % 10)), d /= 10); g[0] = g[0] * (1 * (10 ** -i)) r.push(...g); } return r; } function arrayToNumber(a) { if ((Math.abs(a[0]) == 0 || Math.abs(a[0]) == -0) && a.length == 1) return a[0]; const [ g, r = x => x.length == 1 ? x[0] : x.length === 0 ? x : x.reduce((a, b) => a + b) , b = a.find(x => g(x)), p = a.findIndex(x => g(x)) ] = [x => !Number.isInteger(x)]; let [i, j] = [b ? p : a.length, -1]; return a.length === 1 ? a[0] : b && p ? r(a.slice(0, p).map(x => i ? x * (10 ** --i) : x)) + (a[p] + (a[p + 1] !== undefined ? r(a.slice(p + 1).map(x => x * (10 ** --j))) : 0)) : r(a.map(x => i ? x * (10 ** --i) : x)) } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123 , 2.718281828459, 321.7000000001, 809.56 , 1.61803398874989, 1.999, 100.01, 545454.45 , -7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); let numbers = arrays.map(n => arrayToNumber(n)); console.log({tests, arrays, numbers}); and working code (fixed bugs) by Stack Overflow user Shidersz https://stackoverflow.com/users/10366495/shidersz > Method numberToArray(): > I have been working some time on your implementation, and thinked to first analyze the numberToArray() method. To start, I have decided to create a method for analyze a decimal number and return statistics about it, basically, the information you where getting from this part of your code: >> if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } > The method I have made on is the next one (will be used inside numberToArray()) and basically gets the next information: > *1)* Integer section (iSection) of the decimal number (as integer). > *2)* Decimal section (dSection) of the decimal number (as integer). > *3)* Number of digits after the dot (dDigits). > *4)* Number of leading zeros after the dot (dZeros). >> function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; console.log(getDecimalStats(10.001)); console.log(getDecimalStats(-210.1)); console.log(getDecimalStats(-0.00001)); > Of course, if you dislike, you can put this same logic directly inside numberToArray() method. So, after making the previous function, I have done some reorganization on your code and added some commentaries to helps me understand what you where doing. Finally, and after adapted your code, I have found that the wrong mapping to the arrays was mostly because the arithmetic precision when operating with float number. After investigate some time about this problem, I found a solution that is based using a mathematical correction factor (it is commented on the code when it is applied). All in all, and until this time, I have come with the next solution to the numberToArray() method. >> function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function numberToArray(n){ let r = []; if (Math.abs(n) == 0) return [n]; let [a, int = Number.isInteger(a), g = []] = [n || this.valueOf()]; // Get the stats of the decimal number. let {dSection, dZeros} = getDecimalStats(a); // Push the integer part on the array. for (; ~~a; r.unshift(~~(a % 10)), a /= 10); // Push the decimal part on the array. if (!int) { // Push decimal digits on temporal array "g". for (; ~~dSection; g.unshift(~~(dSection % 10)), dSection /= 10); // Define the correction factor for the next operation. let cf = 10 ** (++dZeros); // Map g[0] to a decimal number and push elements on the array. g[0] = (g[0] * cf) * ((10 ** -dZeros) * cf) / (cf * cf); r.push(...g); } return r; } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123,2.718281828459, 321.7000000001, 809.56,1.61803398874989, 1.999, 100.01, 545454.45,-7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); console.log({tests, arrays}); > Method arrayToNumber(): > For this one I decided to go on my own (actually ignoring your current logic). The next approach will use the previously mentioned getDecimalStats() and mainly the Array::reduce() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce> : >> function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function arrayToNumber(a) { // Get the index of the first decimal number. let firstDecIdx = a.findIndex( x => Math.abs(x) > 0 && Math.abs(x) < 1 ); // Get stats about the previous decimal number. let {dZeros} = getDecimalStats(firstDecIdx >= 0 ? a[firstDecIdx] : 0); // Normalize firstDecIdx. firstDecIdx = firstDecIdx < 0 ? a.length : firstDecIdx; // Reduce the array to get the number. let number = a.reduce( ({num, dIdx, dPow}, n, i) => { // Define the correction factor. let cf = 10 ** (dPow + i - dIdx); if (i < dIdx) num += n * (10 ** (dIdx - i - 1)); else if (i === dIdx) num = ((num * cf) + (n * cf)) / cf; else num = ((num * cf) + n) / cf; return {num, dIdx, dPow}; }, {num: 0, dIdx: firstDecIdx, dPow: ++dZeros} ); return number.num; } let tests = [ [0], [2, 0, 0], [1, 0, 0, 0.0001, 5], [-1, -2, -3], [4, 0.4], [4, 4, 0.4, 4], [-0.01], [1, 2, 3], [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9], [3, 2, 1, 0.7, 0, 0, 0, 0, 0, 0, 0, 0, 1], [8, 0, 9, 0.5, 6], [1, 0.6, 1, 8, 0, 3, 3, 9, 8, 8, 7, 4, 9, 8, 9], [1, 0.9, 9, 9], [1, 0, 0, 0.01], [5, 4, 5, 4, 5, 4, 0.4, 5, 0], [-7], [-8,-3, -0.7, -8, -2], [1, 2], [1, 0.5], [1, 0, 0, 0.0001]]; let numbers = tests.map(n => arrayToNumber(n)); console.log(numbers); > Finally, I hope you can value my efforts, and obviously there can be a lot of improvements to my solution (so, any recommendation is welcome). For example, there are currently none or few checks for safety. Number (integer or decimal) to array, array to number (integer or decimal) without using strings https://stackoverflow.com/q/54433007 *Context and use cases:* BigInt <https://developers.google.com/web/updates/2018/05/bigint> is available in some browsers, though not a BigDecimal. The conversion from integer or decimal to array and array to integer or decimal should be possible using the JavaScript programming language. The input and output should not need to be converted to a string during the procedure. Ability to adjust *nth* digit of an integer or decimal by adjusting decimal or integer at *nth* index of array, to try to solve OEIS A217626 <https://oeis.org/A217626> directly, for example ~~(128.625*9*1.074)//1243 ~~(128.625*9*1.144)//1324 where the decimal portion can be manipulated by referencing the index of an array, then converting the array back to a number. Specification (WIP): [...Math.E] -> [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9] -> 2.718281828459 Input <----------> Output -123 [-1,-2,-3] 4.4 [4,0.4] 44.44 [4,4,0.4,4] -0.01 [-0.01] 123 [1,2,3] 200 [2,0,0] 2.718281828459 [2,0.7,1,8,2,8,1,8,2,8,4,5,8,9] 321.7000000001 [3,2,1,0.7,0,0,0,0,0,0,0,0,1] 809.56 [8,0,9,0.5,6] 1.61803398874989 [1,0.6,1,8,0,3,3,9,8,8,7,4,9,8,9] 1.999 [1,0.9,9,9] 100.01 [1,0,0,0.01] 545454.45 [5,4,5,4,5,4,0.4,5] -7 [-7] -83.782 [-8,-3,-0.7,-8,-2] 1.5 [1,0.5] 100.0001 [1,0,0,0.0001]
guest271314 at gmail.com (2019-03-11T14:49:31.428Z)
Original concept: Integer or decimal to array and array to decimal or integer https://codegolf.meta.stackexchange.com/a/17223 Proof of concept (with bugs) function numberToArray(n) { if (Math.abs(n) == 0 || Math.abs(n) == -0) { return [n] } const r = []; let [ a, int = Number.isInteger(a), d = g = [], e = i = 0 ] = [ n || this.valueOf()]; if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } for (; ~~a; r.unshift(~~(a % 10)), a /= 10); if (!int) { for (; ~~d; g.unshift(~~(d % 10)), d /= 10); g[0] = g[0] * (1 * (10 ** -i)) r.push(...g); } return r; } function arrayToNumber(a) { if ((Math.abs(a[0]) == 0 || Math.abs(a[0]) == -0) && a.length == 1) return a[0]; const [ g, r = x => x.length == 1 ? x[0] : x.length === 0 ? x : x.reduce((a, b) => a + b) , b = a.find(x => g(x)), p = a.findIndex(x => g(x)) ] = [x => !Number.isInteger(x)]; let [i, j] = [b ? p : a.length, -1]; return a.length === 1 ? a[0] : b && p ? r(a.slice(0, p).map(x => i ? x * (10 ** --i) : x)) + (a[p] + (a[p + 1] !== undefined ? r(a.slice(p + 1).map(x => x * (10 ** --j))) : 0)) : r(a.map(x => i ? x * (10 ** --i) : x)) } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123 , 2.718281828459, 321.7000000001, 809.56 , 1.61803398874989, 1.999, 100.01, 545454.45 , -7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); let numbers = arrays.map(n => arrayToNumber(n)); console.log({tests, arrays, numbers}); and working code (fixed bugs) by Stack Overflow user Shidersz https://stackoverflow.com/users/10366495/shidersz > Method numberToArray(): > I have been working some time on your implementation, and thinked to first analyze the numberToArray() method. To start, I have decided to create a method for analyze a decimal number and return statistics about it, basically, the information you where getting from this part of your code: > if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } > The method I have made on is the next one (will be used inside numberToArray()) and basically gets the next information: > *1)* Integer section (iSection) of the decimal number (as integer). > *2)* Decimal section (dSection) of the decimal number (as integer). > *3)* Number of digits after the dot (dDigits). > *4)* Number of leading zeros after the dot (dZeros). > function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; console.log(getDecimalStats(10.001)); console.log(getDecimalStats(-210.1)); console.log(getDecimalStats(-0.00001)); > Of course, if you dislike, you can put this same logic directly inside numberToArray() method. So, after making the previous function, I have done some reorganization on your code and added some commentaries to helps me understand what you where doing. Finally, and after adapted your code, I have found that the wrong mapping to the arrays was mostly because the arithmetic precision when operating with float number. After investigate some time about this problem, I found a solution that is based using a mathematical correction factor (it is commented on the code when it is applied). All in all, and until this time, I have come with the next solution to the numberToArray() method. > function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function numberToArray(n){ let r = []; if (Math.abs(n) == 0) return [n]; let [a, int = Number.isInteger(a), g = []] = [n || this.valueOf()]; // Get the stats of the decimal number. let {dSection, dZeros} = getDecimalStats(a); // Push the integer part on the array. for (; ~~a; r.unshift(~~(a % 10)), a /= 10); // Push the decimal part on the array. if (!int) { // Push decimal digits on temporal array "g". for (; ~~dSection; g.unshift(~~(dSection % 10)), dSection /= 10); // Define the correction factor for the next operation. let cf = 10 ** (++dZeros); // Map g[0] to a decimal number and push elements on the array. g[0] = (g[0] * cf) * ((10 ** -dZeros) * cf) / (cf * cf); r.push(...g); } return r; } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123,2.718281828459, 321.7000000001, 809.56,1.61803398874989, 1.999, 100.01, 545454.45,-7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); console.log({tests, arrays}); > Method arrayToNumber(): > For this one I decided to go on my own (actually ignoring your current logic). The next approach will use the previously mentioned getDecimalStats() and mainly the Array::reduce() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce> : > function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function arrayToNumber(a) { // Get the index of the first decimal number. let firstDecIdx = a.findIndex( x => Math.abs(x) > 0 && Math.abs(x) < 1 ); // Get stats about the previous decimal number. let {dZeros} = getDecimalStats(firstDecIdx >= 0 ? a[firstDecIdx] : 0); // Normalize firstDecIdx. firstDecIdx = firstDecIdx < 0 ? a.length : firstDecIdx; // Reduce the array to get the number. let number = a.reduce( ({num, dIdx, dPow}, n, i) => { // Define the correction factor. let cf = 10 ** (dPow + i - dIdx); if (i < dIdx) num += n * (10 ** (dIdx - i - 1)); else if (i === dIdx) num = ((num * cf) + (n * cf)) / cf; else num = ((num * cf) + n) / cf; return {num, dIdx, dPow}; }, {num: 0, dIdx: firstDecIdx, dPow: ++dZeros} ); return number.num; } let tests = [ [0], [2, 0, 0], [1, 0, 0, 0.0001, 5], [-1, -2, -3], [4, 0.4], [4, 4, 0.4, 4], [-0.01], [1, 2, 3], [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9], [3, 2, 1, 0.7, 0, 0, 0, 0, 0, 0, 0, 0, 1], [8, 0, 9, 0.5, 6], [1, 0.6, 1, 8, 0, 3, 3, 9, 8, 8, 7, 4, 9, 8, 9], [1, 0.9, 9, 9], [1, 0, 0, 0.01], [5, 4, 5, 4, 5, 4, 0.4, 5, 0], [-7], [-8,-3, -0.7, -8, -2], [1, 2], [1, 0.5], [1, 0, 0, 0.0001]]; let numbers = tests.map(n => arrayToNumber(n)); console.log(numbers); > Finally, I hope you can value my efforts, and obviously there can be a lot of improvements to my solution (so, any recommendation is welcome). For example, there are currently none or few checks for safety. Number (integer or decimal) to array, array to number (integer or decimal) without using strings https://stackoverflow.com/q/54433007 *Context and use cases:* BigInt <https://developers.google.com/web/updates/2018/05/bigint> is available in some browsers, though not a BigDecimal. The conversion from integer or decimal to array and array to integer or decimal should be possible using the JavaScript programming language. The input and output should not need to be converted to a string during the procedure. Ability to adjust *nth* digit of an integer or decimal by adjusting decimal or integer at *nth* index of array, to try to solve OEIS A217626 <https://oeis.org/A217626> directly, for example ~~(128.625*9*1.074)//1243 ~~(128.625*9*1.144)//1324 where the decimal portion can be manipulated by referencing the index of an array, then converting the array back to a number. Specification (WIP): [...Math.E] -> [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9] -> 2.718281828459 Input <----------> Output -123 [-1,-2,-3] 4.4 [4,0.4] 44.44 [4,4,0.4,4] -0.01 [-0.01] 123 [1,2,3] 200 [2,0,0] 2.718281828459 [2,0.7,1,8,2,8,1,8,2,8,4,5,8,9] 321.7000000001 [3,2,1,0.7,0,0,0,0,0,0,0,0,1] 809.56 [8,0,9,0.5,6] 1.61803398874989 [1,0.6,1,8,0,3,3,9,8,8,7,4,9,8,9] 1.999 [1,0.9,9,9] 100.01 [1,0,0,0.01] 545454.45 [5,4,5,4,5,4,0.4,5] -7 [-7] -83.782 [-8,-3,-0.7,-8,-2] 1.5 [1,0.5] 100.0001 [1,0,0,0.0001]
guest271314 at gmail.com (2019-03-07T21:57:06.546Z)
Original concept: Integer or decimal to array and array to decimal or integer https://codegolf.meta.stackexchange.com/a/17223 Proof of concept (with bugs) function numberToArray(n) { if (Math.abs(n) == 0 || Math.abs(n) == -0) { return [n] } const r = []; let [ a, int = Number.isInteger(a), d = g = [], e = i = 0 ] = [ n || this.valueOf()]; if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } for (; ~~a; r.unshift(~~(a % 10)), a /= 10); if (!int) { for (; ~~d; g.unshift(~~(d % 10)), d /= 10); g[0] = g[0] * (1 * (10 ** -i)) r.push(...g); } return r; } function arrayToNumber(a) { if ((Math.abs(a[0]) == 0 || Math.abs(a[0]) == -0) && a.length == 1) return a[0]; const [ g, r = x => x.length == 1 ? x[0] : x.length === 0 ? x : x.reduce((a, b) => a + b) , b = a.find(x => g(x)), p = a.findIndex(x => g(x)) ] = [x => !Number.isInteger(x)]; let [i, j] = [b ? p : a.length, -1]; return a.length === 1 ? a[0] : b && p ? r(a.slice(0, p).map(x => i ? x * (10 ** --i) : x)) + (a[p] + (a[p + 1] !== undefined ? r(a.slice(p + 1).map(x => x * (10 ** --j))) : 0)) : r(a.map(x => i ? x * (10 ** --i) : x)) } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123 , 2.718281828459, 321.7000000001, 809.56 , 1.61803398874989, 1.999, 100.01, 545454.45 , -7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); let numbers = arrays.map(n => arrayToNumber(n)); console.log({tests, arrays, numbers}); and working code (fixed bugs) by Stack Overflow user Shidersz https://stackoverflow.com/users/10366495/shidersz Method numberToArray(): I have been working some time on your implementation, and thinked to first analyze the numberToArray() method. To start, I have decided to create a method for analyze a decimal number and return statistics about it, basically, the information you where getting from this part of your code: if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } The method I have made on is the next one (will be used inside numberToArray()) and basically gets the next information: *1)* Integer section (iSection) of the decimal number (as integer). *2)* Decimal section (dSection) of the decimal number (as integer). *3)* Number of digits after the dot (dDigits). *4)* Number of leading zeros after the dot (dZeros). function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; console.log(getDecimalStats(10.001)); console.log(getDecimalStats(-210.1)); console.log(getDecimalStats(-0.00001)); Of course, if you dislike, you can put this same logic directly inside numberToArray() method. So, after making the previous function, I have done some reorganization on your code and added some commentaries to helps me understand what you where doing. Finally, and after adapted your code, I have found that the wrong mapping to the arrays was mostly because the arithmetic precision when operating with float number. After investigate some time about this problem, I found a solution that is based using a mathematical correction factor (it is commented on the code when it is applied). All in all, and until this time, I have come with the next solution to the numberToArray() method. function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function numberToArray(n){ let r = []; if (Math.abs(n) == 0) return [n]; let [a, int = Number.isInteger(a), g = []] = [n || this.valueOf()]; // Get the stats of the decimal number. let {dSection, dZeros} = getDecimalStats(a); // Push the integer part on the array. for (; ~~a; r.unshift(~~(a % 10)), a /= 10); // Push the decimal part on the array. if (!int) { // Push decimal digits on temporal array "g". for (; ~~dSection; g.unshift(~~(dSection % 10)), dSection /= 10); // Define the correction factor for the next operation. let cf = 10 ** (++dZeros); // Map g[0] to a decimal number and push elements on the array. g[0] = (g[0] * cf) * ((10 ** -dZeros) * cf) / (cf * cf); r.push(...g); } return r; } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123,2.718281828459, 321.7000000001, 809.56,1.61803398874989, 1.999, 100.01, 545454.45,-7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); console.log({tests, arrays}); Method arrayToNumber(): For this one I decided to go on my own (actually ignoring your current logic). The next approach will use the previously mentioned getDecimalStats() and mainly the Array::reduce() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce> : function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function arrayToNumber(a) { // Get the index of the first decimal number. let firstDecIdx = a.findIndex( x => Math.abs(x) > 0 && Math.abs(x) < 1 ); // Get stats about the previous decimal number. let {dZeros} = getDecimalStats(firstDecIdx >= 0 ? a[firstDecIdx] : 0); // Normalize firstDecIdx. firstDecIdx = firstDecIdx < 0 ? a.length : firstDecIdx; // Reduce the array to get the number. let number = a.reduce( ({num, dIdx, dPow}, n, i) => { // Define the correction factor. let cf = 10 ** (dPow + i - dIdx); if (i < dIdx) num += n * (10 ** (dIdx - i - 1)); else if (i === dIdx) num = ((num * cf) + (n * cf)) / cf; else num = ((num * cf) + n) / cf; return {num, dIdx, dPow}; }, {num: 0, dIdx: firstDecIdx, dPow: ++dZeros} ); return number.num; } let tests = [ [0], [2, 0, 0], [1, 0, 0, 0.0001, 5], [-1, -2, -3], [4, 0.4], [4, 4, 0.4, 4], [-0.01], [1, 2, 3], [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9], [3, 2, 1, 0.7, 0, 0, 0, 0, 0, 0, 0, 0, 1], [8, 0, 9, 0.5, 6], [1, 0.6, 1, 8, 0, 3, 3, 9, 8, 8, 7, 4, 9, 8, 9], [1, 0.9, 9, 9], [1, 0, 0, 0.01], [5, 4, 5, 4, 5, 4, 0.4, 5, 0], [-7], [-8,-3, -0.7, -8, -2], [1, 2], [1, 0.5], [1, 0, 0, 0.0001]]; let numbers = tests.map(n => arrayToNumber(n)); console.log(numbers); Finally, I hope you can value my efforts, and obviously there can be a lot of improvements to my solution (so, any recommendation is welcome). For example, there are currently none or few checks for safety. Number (integer or decimal) to array, array to number (integer or decimal) without using strings https://stackoverflow.com/q/54433007 *Context and use cases:* BigInt <https://developers.google.com/web/updates/2018/05/bigint> is available in some browsers, though not a BigDecimal. The conversion from integer or decimal to array and array to integer or decimal should be possible using the JavaScript programming language. The input and output should not need to be converted to a string during the procedure. Ability to adjust *nth* digit of an integer or decimal by adjusting decimal or integer at *nth* index of array, to try to solve OEIS A217626 <https://oeis.org/A217626> directly, for example ~~(128.625*9*1.074)//1243 ~~(128.625*9*1.144)//1324 where the decimal portion can be manipulated by referencing the index of an array, then converting the array back to a number. Specification (WIP): [...Math.E] -> [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9] -> 2.718281828459 Input <----------> Output -123 [-1,-2,-3] 4.4 [4,0.4] 44.44 [4,4,0.4,4] -0.01 [-0.01] 123 [1,2,3] 200 [2,0,0] 2.718281828459 [2,0.7,1,8,2,8,1,8,2,8,4,5,8,9] 321.7000000001 [3,2,1,0.7,0,0,0,0,0,0,0,0,1] 809.56 [8,0,9,0.5,6] 1.61803398874989 [1,0.6,1,8,0,3,3,9,8,8,7,4,9,8,9] 1.999 [1,0.9,9,9] 100.01 [1,0,0,0.01] 545454.45 [5,4,5,4,5,4,0.4,5] -7 [-7] -83.782 [-8,-3,-0.7,-8,-2] 1.5 [1,0.5] 100.0001 [1,0,0,0.0001]
guest271314 at gmail.com (2019-03-07T20:59:23.946Z)
Original concept: Integer or decimal to array and array to decimal or integer https://codegolf.meta.stackexchange.com/a/17223 Proof of concept (with bugs) function numberToArray(n) { if (Math.abs(n) == 0 || Math.abs(n) == -0) { return [n] } const r = []; let [ a, int = Number.isInteger(a), d = g = [], e = i = 0 ] = [ n || this.valueOf()]; if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } for (; ~~a; r.unshift(~~(a % 10)), a /= 10); if (!int) { for (; ~~d; g.unshift(~~(d % 10)), d /= 10); g[0] = g[0] * (1 * (10 ** -i)) r.push(...g); } return r; } function arrayToNumber(a) { if ((Math.abs(a[0]) == 0 || Math.abs(a[0]) == -0) && a.length == 1) return a[0]; const [ g, r = x => x.length == 1 ? x[0] : x.length === 0 ? x : x.reduce((a, b) => a + b) , b = a.find(x => g(x)), p = a.findIndex(x => g(x)) ] = [x => !Number.isInteger(x)]; let [i, j] = [b ? p : a.length, -1]; return a.length === 1 ? a[0] : b && p ? r(a.slice(0, p).map(x => i ? x * (10 ** --i) : x)) + (a[p] + (a[p + 1] !== undefined ? r(a.slice(p + 1).map(x => x * (10 ** --j))) : 0)) : r(a.map(x => i ? x * (10 ** --i) : x)) } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123 , 2.718281828459, 321.7000000001, 809.56 , 1.61803398874989, 1.999, 100.01, 545454.45 , -7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); let numbers = arrays.map(n => arrayToNumber(n)); console.log({tests, arrays, numbers}); and working code (fixed bugs) by Stack Overflow user Shidersz https://stackoverflow.com/users/10366495/shidersz Method numberToArray(): I have been working some time on your implementation, and thinked to first analyze the numberToArray() method. To start, I have decided to create a method for analyze a decimal number and return statistics about it, basically, the information you where getting from this part of your code: if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } The method I have made on is the next one (will be used inside numberToArray()) and basically gets the next information: *1)* Integer section (iSection) of the decimal number (as integer). *2)* Decimal section (dSection) of the decimal number (as integer). *3)* Number of digits after the dot (dDigits). *4)* Number of leading zeros after the dot (dZeros). function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; console.log(getDecimalStats(10.001)); console.log(getDecimalStats(-210.1)); console.log(getDecimalStats(-0.00001)); Of course, if you dislike, you can put this same logic directly inside numberToArray() method. So, after making the previous function, I have done some reorganization on your code and added some commentaries to helps me understand what you where doing. Finally, and after adapted your code, I have found that the wrong mapping to the arrays was mostly because the arithmetic precision when operating with float number. After investigate some time about this problem, I found a solution that is based using a mathematical correction factor (it is commented on the code when it is applied). All in all, and until this time, I have come with the next solution to the numberToArray() method. function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function numberToArray(n){ let r = []; if (Math.abs(n) == 0) return [n]; let [a, int = Number.isInteger(a), g = []] = [n || this.valueOf()]; // Get the stats of the decimal number. let {dSection, dZeros} = getDecimalStats(a); // Push the integer part on the array. for (; ~~a; r.unshift(~~(a % 10)), a /= 10); // Push the decimal part on the array. if (!int) { // Push decimal digits on temporal array "g". for (; ~~dSection; g.unshift(~~(dSection % 10)), dSection /= 10); // Define the correction factor for the next operation. let cf = 10 ** (++dZeros); // Map g[0] to a decimal number and push elements on the array. g[0] = (g[0] * cf) * ((10 ** -dZeros) * cf) / (cf * cf); r.push(...g); } return r; } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123,2.718281828459, 321.7000000001, 809.56,1.61803398874989, 1.999, 100.01, 545454.45,-7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); console.log({tests, arrays}); Method arrayToNumber(): For this one I decided to go on my own (actually ignoring your current logic). The next approach will use the previously mentioned getDecimalStats() and mainly the Array::reduce() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce> : function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function arrayToNumber(a) { // Get the index of the first decimal number. let firstDecIdx = a.findIndex( x => Math.abs(x) > 0 && Math.abs(x) < 1 ); // Get stats about the previous decimal number. let {dZeros} = getDecimalStats(firstDecIdx >= 0 ? a[firstDecIdx] : 0); // Normalize firstDecIdx. firstDecIdx = firstDecIdx < 0 ? a.length : firstDecIdx; // Reduce the array to get the number. let number = a.reduce( ({num, dIdx, dPow}, n, i) => { // Define the correction factor. let cf = 10 ** (dPow + i - dIdx); if (i < dIdx) num += n * (10 ** (dIdx - i - 1)); else if (i === dIdx) num = ((num * cf) + (n * cf)) / cf; else num = ((num * cf) + n) / cf; return {num, dIdx, dPow}; }, {num: 0, dIdx: firstDecIdx, dPow: ++dZeros} ); return number.num; } let tests = [ [0], [2, 0, 0], [1, 0, 0, 0.0001, 5], [-1, -2, -3], [4, 0.4], [4, 4, 0.4, 4], [-0.01], [1, 2, 3], [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9], [3, 2, 1, 0.7, 0, 0, 0, 0, 0, 0, 0, 0, 1], [8, 0, 9, 0.5, 6], [1, 0.6, 1, 8, 0, 3, 3, 9, 8, 8, 7, 4, 9, 8, 9], [1, 0.9, 9, 9], [1, 0, 0, 0.01], [5, 4, 5, 4, 5, 4, 0.4, 5, 0], [-7], [-8,-3, -0.7, -8, -2], [1, 2], [1, 0.5], [1, 0, 0, 0.0001]]; let numbers = tests.map(n => arrayToNumber(n)); console.log(numbers); Finally, I hope you can value my efforts, and obviously there can be a lot of improvements to my solution (so, any recommendation is welcome). For example, there are currently none or few checks for safety. Number (integer or decimal) to array, array to number (integer or decimal) without using strings https://stackoverflow.com/q/54433007 *Context and use cases:* BigInt <https://developers.google.com/web/updates/2018/05/bigint> in available in some browsers, though not a BigDecimal. The conversion from integer or decimal to array and array to integer or decimal should be possible using the JavaScript programming language. The input and output should not need to be converted to a string during the procedure. Ability to adjust *nth* digit of an integer or decimal by adjusting decimal or integer at *nth* index of array, to try to solve OEIS A217626 <https://oeis.org/A217626> directly, for example ~~(128.625*9*1.074)//1243 ~~(128.625*9*1.144)//1324 where the decimal portion can be manipulated by referencing the index of an array, then converting the array back to a number. Specification (WIP): [...Math.E] -> [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9] -> 2.718281828459 Input <----------> Output -123 [-1,-2,-3] 4.4 [4,0.4] 44.44 [4,4,0.4,4] -0.01 [-0.01] 123 [1,2,3] 200 [2,0,0] 2.718281828459 [2,0.7,1,8,2,8,1,8,2,8,4,5,8,9] 321.7000000001 [3,2,1,0.7,0,0,0,0,0,0,0,0,1] 809.56 [8,0,9,0.5,6] 1.61803398874989 [1,0.6,1,8,0,3,3,9,8,8,7,4,9,8,9] 1.999 [1,0.9,9,9] 100.01 [1,0,0,0.01] 545454.45 [5,4,5,4,5,4,0.4,5] -7 [-7] -83.782 [-8,-3,-0.7,-8,-2] 1.5 [1,0.5] 100.0001 [1,0,0,0.0001]
guest271314 at gmail.com (2019-03-07T20:58:06.184Z)
Original concept: Integer or decimal to array and array to decimal or integer https://codegolf.meta.stackexchange.com/a/17223 Proof of concept (with bugs) function numberToArray(n) { if (Math.abs(n) == 0 || Math.abs(n) == -0) { return [n] } const r = []; let [ a, int = Number.isInteger(a), d = g = [], e = i = 0 ] = [ n || this.valueOf()]; if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } for (; ~~a; r.unshift(~~(a % 10)), a /= 10); if (!int) { for (; ~~d; g.unshift(~~(d % 10)), d /= 10); g[0] = g[0] * (1 * (10 ** -i)) r.push(...g); } return r; } function arrayToNumber(a) { if ((Math.abs(a[0]) == 0 || Math.abs(a[0]) == -0) && a.length == 1) return a[0]; const [ g, r = x => x.length == 1 ? x[0] : x.length === 0 ? x : x.reduce((a, b) => a + b) , b = a.find(x => g(x)), p = a.findIndex(x => g(x)) ] = [x => !Number.isInteger(x)]; let [i, j] = [b ? p : a.length, -1]; return a.length === 1 ? a[0] : b && p ? r(a.slice(0, p).map(x => i ? x * (10 ** --i) : x)) + (a[p] + (a[p + 1] !== undefined ? r(a.slice(p + 1).map(x => x * (10 ** --j))) : 0)) : r(a.map(x => i ? x * (10 ** --i) : x)) } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123 , 2.718281828459, 321.7000000001, 809.56 , 1.61803398874989, 1.999, 100.01, 545454.45 , -7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); let numbers = arrays.map(n => arrayToNumber(n)); console.log({tests, arrays, numbers}); and working code (fixed bugs) by Stack Overflow user Shidersz https://stackoverflow.com/users/10366495/shidersz Method numberToArray(): I have been working some time on your implementation, and thinked to first analyze the numberToArray() method. To start, I have decided to create a method for analyze a decimal number and return statistics about it, basically, the information you where getting from this part of your code: if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } The method I have made on is the next one (will be used inside numberToArray()) and basically gets the next information: *1)* Integer section (iSection) of the decimal number (as integer). *2)* Decimal section (dSection) of the decimal number (as integer). *3)* Number of digits after the dot (dDigits). *4)* Number of leading zeros after the dot (dZeros). function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; console.log(getDecimalStats(10.001)); console.log(getDecimalStats(-210.1)); console.log(getDecimalStats(-0.00001)); Of course, if you dislike, you can put this same logic directly inside numberToArray() method. So, after making the previous function, I have done some reorganization on your code and added some commentaries to helps me understand what you where doing. Finally, and after adapted your code, I have found that the wrong mapping to the arrays was mostly because the arithmetic precision when operating with float number. After investigate some time about this problem, I found a solution that is based using a mathematical correction factor (it is commented on the code when it is applied). All in all, and until this time, I have come with the next solution to the numberToArray() method. function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function numberToArray(n){ let r = []; if (Math.abs(n) == 0) return [n]; let [a, int = Number.isInteger(a), g = []] = [n || this.valueOf()]; // Get the stats of the decimal number. let {dSection, dZeros} = getDecimalStats(a); // Push the integer part on the array. for (; ~~a; r.unshift(~~(a % 10)), a /= 10); // Push the decimal part on the array. if (!int) { // Push decimal digits on temporal array "g". for (; ~~dSection; g.unshift(~~(dSection % 10)), dSection /= 10); // Define the correction factor for the next operation. let cf = 10 ** (++dZeros); // Map g[0] to a decimal number and push elements on the array. g[0] = (g[0] * cf) * ((10 ** -dZeros) * cf) / (cf * cf); r.push(...g); } return r; } let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123,2.718281828459, 321.7000000001, 809.56,1.61803398874989, 1.999, 100.01, 545454.45,-7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); console.log({tests, arrays}); Method arrayToNumber(): For this one I decided to go on my own (actually ignoring your current logic). The next approach will use the previously mentioned getDecimalStats() and mainly the Array::reduce() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce> : function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits}; }; function arrayToNumber(a) { // Get the index of the first decimal number. let firstDecIdx = a.findIndex( x => Math.abs(x) > 0 && Math.abs(x) < 1 ); // Get stats about the previous decimal number. let {dZeros} = getDecimalStats(firstDecIdx >= 0 ? a[firstDecIdx] : 0); // Normalize firstDecIdx. firstDecIdx = firstDecIdx < 0 ? a.length : firstDecIdx; // Reduce the array to get the number. let number = a.reduce( ({num, dIdx, dPow}, n, i) => { // Define the correction factor. let cf = 10 ** (dPow + i - dIdx); if (i < dIdx) num += n * (10 ** (dIdx - i - 1)); else if (i === dIdx) num = ((num * cf) + (n * cf)) / cf; else num = ((num * cf) + n) / cf; return {num, dIdx, dPow}; }, {num: 0, dIdx: firstDecIdx, dPow: ++dZeros} ); return number.num; } let tests = [ [0], [2, 0, 0], [1, 0, 0, 0.0001, 5], [-1, -2, -3], [4, 0.4], [4, 4, 0.4, 4], [-0.01], [1, 2, 3], [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9], [3, 2, 1, 0.7, 0, 0, 0, 0, 0, 0, 0, 0, 1], [8, 0, 9, 0.5, 6], [1, 0.6, 1, 8, 0, 3, 3, 9, 8, 8, 7, 4, 9, 8, 9], [1, 0.9, 9, 9], [1, 0, 0, 0.01], [5, 4, 5, 4, 5, 4, 0.4, 5, 0], [-7], [-8,-3, -0.7, -8, -2], [1, 2], [1, 0.5], [1, 0, 0, 0.0001]]; let numbers = tests.map(n => arrayToNumber(n)); console.log(numbers); Finally, I hope you can value my efforts, and obviously there can be a lot of improvements to my solution (so, any recommendation is welcome). For example, there are currently none or few checks for safety. Number (integer or decimal) to array, array to number (integer or decimal) without using strings https://stackoverflow.com/q/54433007 *Context and use cases:* BigInt <https://developers.google.com/web/updates/2018/05/bigint> in available in some browsers, though not a BigDecimal. The conversion from integer or decimal to array and array to integer or decimal should be possible using the JavaScript programming language. The input and output should not need to be converted to a string during the procedure. Ability to adjust *nth* digit of an integer or decimal by adjusting decimal or integer at *nth* index of array, to try to solve OEIS A217626 <https://oeis.org/A217626> directly, for example ~~(128.625*9*1.074)//1243~~(128.625*9*1.144)//1324 where the decimal portion can be manipulated by referencing the index of an array, then converting the array back to a number. Specification (WIP): [...Math.E] -> [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9] -> 2.718281828459 Input <----------> Output -123 [-1,-2,-3] 4.4 [4,0.4] 44.44 [4,4,0.4,4] -0.01 [-0.01] 123 [1,2,3] 200 [2,0,0] 2.718281828459 [2,0.7,1,8,2,8,1,8,2,8,4,5,8,9] 321.7000000001 [3,2,1,0.7,0,0,0,0,0,0,0,0,1] 809.56 [8,0,9,0.5,6] 1.61803398874989 [1,0.6,1,8,0,3,3,9,8,8,7,4,9,8,9] 1.999 [1,0.9,9,9] 100.01 [1,0,0,0.01] 545454.45 [5,4,5,4,5,4,0.4,5] -7 [-7] -83.782 [-8,-3,-0.7,-8,-2] 1.5 [1,0.5] 100.0001 [1,0,0,0.0001]
guest271314 at gmail.com (2019-03-07T20:50:35.134Z)
Original concept: Integer or decimal to array and array to decimal or integer https://codegolf.meta.stackexchange.com/a/17223 Proof of concept (with bugs) function numberToArray(n) { if (Math.abs(n) == 0 || Math.abs(n) == -0) { return [n] } const r = []; let [ a, int = Number.isInteger(a), d = g = [], e = i = 0 ] = [ n || this.valueOf()]; if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } for (; ~~a; r.unshift(~~(a % 10)), a /= 10); if (!int) { for (; ~~d; g.unshift(~~(d % 10)), d /= 10); g[0] = g[0] * (1 * (10 ** -i)) r.push(...g); } return r; } function arrayToNumber(a) { if ((Math.abs(a[0]) == 0 || Math.abs(a[0]) == -0) && a.length == 1) return a[0]; const [ g, r = x => x.length == 1 ? x[0] : x.length === 0 ? x : x.reduce((a, b) => a + b) , b = a.find(x => g(x)), p = a.findIndex(x => g(x)) ] = [x => !Number.isInteger(x)]; let [i, j] = [b ? p : a.length, -1]; return a.length === 1 ? a[0] : b && p ? r(a.slice(0, p).map(x => i ? x * (10 ** --i) : x)) + (a[p] + (a[p + 1] !== undefined ? r(a.slice(p + 1).map(x => x * (10 ** --j))) : 0)) : r(a.map(x => i ? x * (10 ** --i) : x))} let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123 , 2.718281828459, 321.7000000001, 809.56 , 1.61803398874989, 1.999, 100.01, 545454.45 , -7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); let numbers = arrays.map(n => arrayToNumber(n)); console.log({tests, arrays, numbers}); and working code (fixed bugs) by Stack Overflow user Shidersz https://stackoverflow.com/users/10366495/shidersz Method numberToArray(): I have been working some time on your implementation, and thinked to first analyze the numberToArray() method. To start, I have decided to create a method for analyze a decimal number and return statistics about it, basically, the information you where getting from this part of your code: if (!int) { let e = ~~a; d = a - e; do { if (d < 1) ++i; d *= 10; } while (!Number.isInteger(d)); } The method I have made on is the next one (will be used inside numberToArray()) and basically gets the next information: *1)* Integer section (iSection) of the decimal number (as integer). *2)* Decimal section (dSection) of the decimal number (as integer). *3)* Number of digits after the dot (dDigits). *4)* Number of leading zeros after the dot (dZeros). function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits};}; console.log(getDecimalStats(10.001)); console.log(getDecimalStats(-210.1)); console.log(getDecimalStats(-0.00001)); Of course, if you dislike, you can put this same logic directly inside numberToArray() method. So, after making the previous function, I have done some reorganization on your code and added some commentaries to helps me understand what you where doing. Finally, and after adapted your code, I have found that the wrong mapping to the arrays was mostly because the arithmetic precision when operating with float number. After investigate some time about this problem, I found a solution that is based using a mathematical correction factor (it is commented on the code when it is applied). All in all, and until this time, I have come with the next solution to the numberToArray() method. function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits};}; function numberToArray(n){ let r = []; if (Math.abs(n) == 0) return [n]; let [a, int = Number.isInteger(a), g = []] = [n || this.valueOf()]; // Get the stats of the decimal number. let {dSection, dZeros} = getDecimalStats(a); // Push the integer part on the array. for (; ~~a; r.unshift(~~(a % 10)), a /= 10); // Push the decimal part on the array. if (!int) { // Push decimal digits on temporal array "g". for (; ~~dSection; g.unshift(~~(dSection % 10)), dSection /= 10); // Define the correction factor for the next operation. let cf = 10 ** (++dZeros); // Map g[0] to a decimal number and push elements on the array. g[0] = (g[0] * cf) * ((10 ** -dZeros) * cf) / (cf * cf); r.push(...g); } return r;} let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123,2.718281828459, 321.7000000001, 809.56,1.61803398874989, 1.999, 100.01, 545454.45,-7, -83.782, 12, 1.50, 100.0001]; let arrays = tests.map(n => [...numberToArray(n)]); console.log({tests, arrays}); Method arrayToNumber(): For this one I decided to go on my own (actually ignoring your current logic). The next approach will use the previously mentioned getDecimalStats() and mainly the Array::reduce() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce> : function getDecimalStats(dec){ let dDigits = 0, test = dec, factor = 1, dZeros = 0; // Store the integer section of the decimal number. let iSection = ~~dec; // Get the numbers of digits and zeros after the comma. while (!Number.isInteger(test)) { factor = Math.pow(10, ++dDigits); test = dec * factor; dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0; } // Store the decimal section as integer. let dSection = test - (iSection * factor); // Return an object with all statistics. return {iSection, dSection, dZeros, dDigits};}; function arrayToNumber(a){ // Get the index of the first decimal number. let firstDecIdx = a.findIndex( x => Math.abs(x) > 0 && Math.abs(x) < 1 ); // Get stats about the previous decimal number. let {dZeros} = getDecimalStats(firstDecIdx >= 0 ? a[firstDecIdx] : 0); // Normalize firstDecIdx. firstDecIdx = firstDecIdx < 0 ? a.length : firstDecIdx; // Reduce the array to get the number. let number = a.reduce( ({num, dIdx, dPow}, n, i) => { // Define the correction factor. let cf = 10 ** (dPow + i - dIdx); if (i < dIdx) num += n * (10 ** (dIdx - i - 1)); else if (i === dIdx) num = ((num * cf) + (n * cf)) / cf; else num = ((num * cf) + n) / cf; return {num, dIdx, dPow}; }, {num: 0, dIdx: firstDecIdx, dPow: ++dZeros} ); return number.num;} let tests = [ [0], [2, 0, 0], [1, 0, 0, 0.0001, 5], [-1, -2, -3], [4, 0.4], [4, 4, 0.4, 4], [-0.01], [1, 2, 3], [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9], [3, 2, 1, 0.7, 0, 0, 0, 0, 0, 0, 0, 0, 1], [8, 0, 9, 0.5, 6], [1, 0.6, 1, 8, 0, 3, 3, 9, 8, 8, 7, 4, 9, 8, 9], [1, 0.9, 9, 9], [1, 0, 0, 0.01], [5, 4, 5, 4, 5, 4, 0.4, 5, 0], [-7], [-8,-3, -0.7, -8, -2], [1, 2], [1, 0.5], [1, 0, 0, 0.0001]]; let numbers = tests.map(n => arrayToNumber(n)); console.log(numbers); Finally, I hope you can value my efforts, and obviously there can be a lot of improvements to my solution (so, any recommendation is welcome). For example, there are currently none or few checks for safety. Number (integer or decimal) to array, array to number (integer or decimal) without using strings https://stackoverflow.com/q/54433007 *Context and use cases:* BigInt <https://developers.google.com/web/updates/2018/05/bigint> in available in some browsers, though not a BigDecimal. The conversion from integer or decimal to array and array to integer or decimal should be possible using the JavaScript programming language. The input and output should not need to be converted to a string during the procedure. Ability to adjust *nth* digit of an integer or decimal by adjusting decimal or integer at *nth* index of array, to try to solve OEIS A217626 <https://oeis.org/A217626> directly, for example ~~(128.625*9*1.074)//1243~~(128.625*9*1.144)//1324 where the decimal portion can be manipulated by referencing the index of an array, then converting the array back to a number. Specification (WIP): [...Math.E] -> [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9] -> 2.718281828459 Input <----------> Output -123 [-1,-2,-3] 4.4 [4,0.4] 44.44 [4,4,0.4,4] -0.01 [-0.01] 123 [1,2,3] 200 [2,0,0] 2.718281828459 [2,0.7,1,8,2,8,1,8,2,8,4,5,8,9] 321.7000000001 [3,2,1,0.7,0,0,0,0,0,0,0,0,1] 809.56 [8,0,9,0.5,6] 1.61803398874989 [1,0.6,1,8,0,3,3,9,8,8,7,4,9,8,9] 1.999 [1,0.9,9,9] 100.01 [1,0,0,0.01] 545454.45 [5,4,5,4,5,4,0.4,5] -7 [-7] -83.782 [-8,-3,-0.7,-8,-2] 1.5 [1,0.5] 100.0001 [1,0,0,0.0001]