-
-
Save jiggzson/b5f489af9ad931e3d186 to your computer and use it in GitHub Desktop.
/** | |
* Removes the minus sign from the beginning of the string | |
* | |
* @param str | |
* @returns an array with the first item as true if a minus | |
* was found and the string minus the minus sign. | |
*/ | |
function stripSign(str) { | |
// Check if it has a minus sign | |
let hasMinus = str.charAt(0) === '-'; | |
// Remove it if it does | |
if (hasMinus || str.charAt(0) === '+') { | |
str = str.substring(1); | |
} | |
return [hasMinus, str]; | |
} | |
/** | |
* Converts a string from scientific notation form to decimal form | |
* | |
* @param str | |
* @returns | |
*/ | |
function scientificToDecimal(str) { | |
if (/\d+\.?\d*e[\+\-]*\d+/i.test(str)) { | |
let isNegative, isSmall; | |
// Remove the sign by slicing the string | |
[isNegative, str] = stripSign(str); | |
// Split it into coefficient and exponent | |
let [c, e] = str.toLowerCase().split('e'); | |
// Split the coefficient into the whole and decimal portion | |
let [w, d] = c.split('.'); | |
// Provide and empty sting for safety if in the form n(e)n | |
d = d || ''; | |
// The total length of the string | |
let length = w.length + d.length; | |
// The total string minus the dot | |
let numString = w + d; | |
// If it's small then we need to calculate the leading zeros | |
// The shift of the decimal place to the left | |
const dotLocation = w.length + Number(e); | |
// Is the dot needed or not | |
const dot = dotLocation === length ? '' : '.'; | |
let value; | |
if (dotLocation <= 0) { | |
// Join the value but pad after the dot with zeroes | |
value = `0${dot}${'0'.repeat(Math.abs(dotLocation))}${numString}`; | |
} | |
else if (dotLocation > length) { | |
value = `${numString}${'0'.repeat(Math.abs(dotLocation - length))}`; | |
} | |
else { | |
value = `${numString.substring(0, dotLocation)}${dot}${numString.substring(dotLocation)}`; | |
} | |
return isNegative ? '-' + value : value; | |
} | |
return str; | |
} |
var expect = function(value) { | |
return { | |
toEqual: function(otherValue) { | |
if(value !== otherValue) { | |
console.error(value+' did not yield the correct result!'); | |
} | |
} | |
}; | |
}; | |
expect(scientificToDecimal(2.5e25)).toEqual('25000000000000000000000000'); | |
expect(scientificToDecimal(-1.123e-10)).toEqual('-0.0000000001123'); | |
expect(scientificToDecimal(-1e-3)).toEqual('-0.001'); | |
expect(scientificToDecimal(-1.2e-2)).toEqual('-0.012'); | |
expect(scientificToDecimal(12.12)).toEqual(12.12); | |
expect(scientificToDecimal(141120000000000000)).toEqual(141120000000000000); | |
expect(scientificToDecimal('0')).toEqual(0); | |
expect(scientificToDecimal(1.23423534e-12)).toEqual(0.00000000000123423534); |
@epcliff. Thanks
@epcliff, new version does not work for (-1e-3) and returns a positive number. If I have time, i'm going to try to debug and fix it.
It works for me using @epcliff code by changing
if (sign < 0) {
num = -num;
}
to
if (sign < 0) {
num = '-'+ num;
}
I have fixed the sign thing on the function. Here is the final code
module.exports.scientificToDecimal = function(number) {
let numberHasSign = number.startsWith("-") || number.startsWith("+");
let sign = numberHasSign ? number[0] : "";
number = numberHasSign ? number.replace(sign, "") : number;
//if the number is in scientific notation remove it
if (SCIENTIFIC_NUMBER_REGEX.test(number)) {
let zero = '0';
let parts = String(number).toLowerCase().split('e'); //split into coeff and exponent
let e = parts.pop();//store the exponential part
let l = Math.abs(e); //get the number of zeros
let sign = e / l;
let coeff_array = parts[0].split('.');
if (sign === -1) {
coeff_array[0] = Math.abs(coeff_array[0]);
number = zero + '.' + new Array(l).join(zero) + coeff_array.join('');
} else {
let dec = coeff_array[1];
if (dec) l = l - dec.length;
number = coeff_array.join('') + new Array(l + 1).join(zero);
}
}
return `${sign}${number}`;
};
Here are the tests
it("Tests scientificToDecimal function", function(done) {
expect(CommonMath.scientificToDecimal("-1.2e2")).toBe("-120");
expect(CommonMath.scientificToDecimal("1.2e2")).toBe("120");
expect(CommonMath.scientificToDecimal("1.2e+2")).toBe("120");
expect(CommonMath.scientificToDecimal("1.2e-2")).toBe("0.012");
expect(CommonMath.scientificToDecimal("-1.2e-2")).toBe("-0.012");
expect(CommonMath.scientificToDecimal("-1e-3")).toBe("-0.001");
done();
});
@afkhalid It does not support bigger numbers:
scientificToDecimal('12345.6e-1') // "0.123456" wrong!!
Yes, it doesn't work for large values. This number:
const foo = scientificToDecimal("3.4028236692093846346e+38");
Is incorrectly parsed as 340282366920938500000000000000000000000
.
TypeScript version, if anyone needs it:
function parseScientific(num: string): string {
// If the number is not in scientific notation return it as it is.
if (!/\d+\.?\d*e[+-]*\d+/i.test(num)) {
return num;
}
// Remove the sign.
const numberSign = Math.sign(Number(num));
num = Math.abs(Number(num)).toString();
// Parse into coefficient and exponent.
const [coefficient, exponent] = num.toLowerCase().split("e");
let zeros = Math.abs(Number(exponent));
const exponentSign = Math.sign(Number(exponent));
const [integer, decimals] = (coefficient.indexOf(".") != -1 ? coefficient : `${coefficient}.`).split(".");
if (exponentSign === -1) {
zeros -= integer.length;
num =
zeros < 0
? integer.slice(0, zeros) + "." + integer.slice(zeros) + decimals
: "0." + "0".repeat(zeros) + integer + decimals;
} else {
if (decimals) zeros -= decimals.length;
num =
zeros < 0
? integer + decimals.slice(0, zeros) + "." + decimals.slice(zeros)
: integer + decimals + "0".repeat(zeros);
}
return numberSign < 0 ? "-" + num : num;
}
Taken from balancer-core-v2.
@PaulRBerg your code excludes some valid scientific notations such as -5e5, and floating such as .5e5.
Also you may want to start by casting Number(num) then toString, it will help avoid many edge cases.
Thanks for the heads-ups, @elhoucine!
Yes, it doesn't work for large values. This number:
const foo = scientificToDecimal("3.4028236692093846346e+38");Is incorrectly parsed as
340282366920938500000000000000000000000
.
it doesnt work for me if number is "115792089237316195423570985008687907853269984665640564039457584007913129639935"
it returns "115792089237316200000000000000000000000000000000000000000000000000000000000000"
did you find any solution for this?
did you find any solution for this?
Yes, check out from-exponential. Also in case you're doing Ethereum development, check out my package evm-bn, which you can use like this:
import { toBn } from "evm-bn";
// 3141500000000000000
const foo: BigNumber = toBn("3.1415");
I write the simple to convert the SN to RN checkout this code
https://github.com/zohaibtahir/Math-Calculations/blob/main/Scientific-notation-to-real_number.js
Updated.
Hi,
Thank you for this but I modified it a bit: