301

JavaScript converts integers with more than 21 digits to scientific notation when used in a string context. I'm printing an integer as part of a URL. How can I prevent the conversion from happening?

outis
  • 75,655
  • 22
  • 151
  • 221
chris
  • 20,791
  • 29
  • 77
  • 90
  • 6
    Do you want 1E21 to display as '1000000000000000000000'? Are you concerned with how the number is displayed, or how it is stored? – outis Nov 06 '09 at 06:19
  • 7
    i am concerned about how it is displayed: I have a document.write(myvariable) command – chris Nov 06 '09 at 06:20
  • Fixed point notation will be hard to read when numbers are very large or very small. Why do you want to do this? – outis Nov 06 '09 at 07:10
  • 3
    i need the number as part of a URL – chris Nov 06 '09 at 21:43
  • 9
    @outis: Human users are not the only ones who want to read numbers. It seems D3 will throw an exception when encountering a `translate` transformation that contains coordinates in scientific notation. – O. R. Mapper Sep 07 '17 at 09:05
  • 5
    There is still a use for this when you are dealing with numbers up to a certain size. Scientific notation will be hard to read for users who don't know scientific notation too after all. – hippietrail Sep 15 '17 at 03:08
  • I just needed this, and because it’s apparently impossible in py3k and JavaScript, I wrote a small shell script https://evolvis.org/plugins/scmgit/cgi-bin/gitweb.cgi?p=shellsnippets/shellsnippets.git;a=blob;f=mksh/fixfloat.sh;hb=HEAD to postprocess the numbers and dissolve the scientific notation using string operations. – mirabilos Aug 23 '19 at 22:37

28 Answers28

187

There's Number.toFixed, but it uses scientific notation if the number is >= 1e21 and has a maximum precision of 20. Other than that, you can roll your own, but it will be messy.

function toFixed(x) {
  if (Math.abs(x) < 1.0) {
    var e = parseInt(x.toString().split('e-')[1]);
    if (e) {
        x *= Math.pow(10,e-1);
        x = '0.' + (new Array(e)).join('0') + x.toString().substring(2);
    }
  } else {
    var e = parseInt(x.toString().split('+')[1]);
    if (e > 20) {
        e -= 20;
        x /= Math.pow(10,e);
        x += (new Array(e+1)).join('0');
    }
  }
  return x;
}

Above uses cheap-'n'-easy string repetition ((new Array(n+1)).join(str)). You could define String.prototype.repeat using Russian Peasant Multiplication and use that instead.

This answer should only be applied to the context of the question: displaying a large number without using scientific notation. For anything else, you should use a BigInt library, such as BigNumber, Leemon's BigInt, or BigInteger. Going forward, the new native BigInt (note: not Leemon's) should be available; Chromium and browsers based on it (Chrome, the new Edge [v79+], Brave) and Firefox all have support; Safari's support is underway.

Here's how you'd use BigInt for it: BigInt(n).toString()

Example:

const n = 13523563246234613317632;
console.log("toFixed (wrong): " + n.toFixed());
console.log("BigInt (right):  " + BigInt(n).toString());

Beware, though, that any integer you output as a JavaScript number (not a BigInt) that's more than 15-16 digits (specifically, greater than Number.MAX_SAFE_INTEGER + 1 [9,007,199,254,740,992]) may be be rounded, because JavaScript's number type (IEEE-754 double-precision floating point) can't precisely hold all integers beyond that point. As of Number.MAX_SAFE_INTEGER + 1 it's working in multiples of 2, so it can't hold odd numbers anymore (and similiarly, at 18,014,398,509,481,984 it starts working in multiples of 4, then 8, then 16, ...).

Consequently, if you can rely on BigInt support, output your number as a string you pass to the BigInt function:

const n = BigInt("YourNumberHere");

Example:

const n1 = BigInt(18014398509481985); // WRONG, will round to 18014398509481984
                                      // before `BigInt` sees it
console.log(n1.toString() + " <== WRONG");
const n2 = BigInt("18014398509481985"); // RIGHT, BigInt handles it
console.log(n2.toString() + " <== Right");
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
outis
  • 75,655
  • 22
  • 151
  • 221
  • 2
    Your solution gives me a very different result for 2^1000 than wolframalpha. Any pointers? – Shane Reustle Aug 10 '11 at 22:50
  • 5
    @Shane: This Q&A is about displaying floating point numbers as base-10 integers and doesn't address numbers that can't be represented in a floating point format (which will arise when converting to base 10). You need a [JS bigint](http://stackoverflow.com/questions/3072307/is-there-a-bignum-library-for-javascript) library, as is mentioned in the final line. – outis Aug 11 '11 at 01:05
  • 1
    @PeterOlson: look like I left out a `Math.abs`. Thanks for the heads-up. – outis Mar 23 '12 at 17:38
  • 1
    `toFixed(Number.MAX_VALUE) == Number.MAX_VALUE` should return true then, but it doesn't... – manonthemat Jan 17 '17 at 22:02
  • 3
    Actually this code as it is does not work for very small negative numbers: toFixed( -1E-20 ) -> "0.0000000000000000000.09999999999999999" – davidthings Jun 15 '17 at 00:37
  • @davidthings is right. A bugfixed version can be found here: https://stackoverflow.com/a/46545519/434742 – Krisztián Balla Oct 03 '17 at 13:16
  • Not Working for scientific numbers – Akshay Pethani Nov 09 '17 at 07:39
  • @davidthings: the question was specifically about large numbers, so `toFixed()` doesn't address small ones. As mentioned in this answer, a bigint library addresses the requested functionality (and other functionality beyond the question). – outis Nov 16 '17 at 23:52
  • 1
    @manonthemat: that's due to imprecision/rounding errors in `Math.pow()`. As an alternative, `parseFloat('1e'+e)` could be used, but ultimately a bigint library is a better choice than trying to get a bespoke function to cover 100% of cases; given the original question, this is one of those "80% of use cases is enough, more than 20% effort is too much" scenarios for custom code (which is also why cheap-'n'-easy string repetition is used). – outis Nov 17 '17 at 09:53
  • 1
    Also, any number greater than `Number.MAX_SAFE_INTEGER` may (and probably wont) be represented exactly. – Pac0 Jan 28 '19 at 14:00
  • how to say if dynamic data that could sometimes be scientific notation or just numeric , how to tell or to know so that i could execute the code above –  Feb 15 '19 at 03:47
  • 1
    My solution below operates on a similar principle but does not engage in JS arithmetic and avoids the precision issues. – Adam Leggett Apr 20 '20 at 19:46
128

I know this is an older question, but shows recently active. MDN toLocaleString

const myNumb = 1000000000000000000000;
console.log( myNumb ); // 1e+21
console.log( myNumb.toLocaleString() ); // "1,000,000,000,000,000,000,000"
console.log( myNumb.toLocaleString('fullwide', {useGrouping:false}) ); // "1000000000000000000000"

you can use options to format the output.

Note:

Number.toLocaleString() rounds after 16 decimal places, so that...

const myNumb = 586084736227728377283728272309128120398;
console.log( myNumb.toLocaleString('fullwide', { useGrouping: false }) );

...returns...

586084736227728400000000000000000000000

This is perhaps undesirable if accuracy is important in the intended result.

bigsee
  • 927
  • 8
  • 14
flapjack17
  • 1,754
  • 1
  • 11
  • 10
  • This doesn't work in PhantomJS 2.1.1 - it still ends up in scientific notation. Fine in Chrome. – Egor Nepomnyaschih Mar 01 '19 at 14:43
  • 5
    This doesn't appear to work for very small decimals: var myNumb = 0.0000000001; console.log( myNumb.toLocaleString('fullwide', { useGrouping: false }) ); – eh1160 Aug 26 '19 at 14:15
  • 5
    One can set maximumSignificantDigits option (max 21) to format very small decimals, ie: ```js console.log( myNumb.toLocaleString('fullwide', { useGrouping: true, maximumSignificantDigits:6}) ); ``` – Sir. MaNiAl Nov 26 '19 at 02:56
  • `maximumFractionDigits` defaults to 3, so I think the actual sol'n is `value.toLocaleString('fullwide',{useGrouping:false,maximumFractionDigits:20})` – mpen May 02 '21 at 23:57
  • 4
    The rounding after 16 places is not a `toLocaleString()` limitation; it's a `Number` limitation. `Number.MAX_SAFE_INTEGER = 9007199254740991` – forresthopkinsa Jul 20 '21 at 04:45
  • What is `fullwide` locale? – dy_ Aug 08 '21 at 14:48
  • Ok, found it https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/numberingSystem – dy_ Aug 08 '21 at 14:53
  • 4
    Using `fullwide` can give unstable results depending on the user's locale. Different locales can use either a period or a comma as a separator. Wouldn't it be better to use version `toLocaleString('en-US', { useGrouping: false, maximumFractionDigits: 20 })`? – Dartess Sep 22 '21 at 14:26
38

For small number, and you know how many decimals you want, you can use toFixed and then use a regexp to remove the trailing zeros.

Number(1e-7).toFixed(8).replace(/\.?0+$/,"") //0.000
  • 3
    Be careful to avoid 0 as an argument of toFixed call - it will end up in erasing significant trailing zeros: `(1000).toFixed(0).replace(/\.?0+$/,"") // 1, not 1000` – Egor Nepomnyaschih Mar 01 '19 at 14:33
  • A more robust regular expression is `Number(1e-7).toFixed(8).replace(/(?<=\.\d*[1-9])0+$|\.0*$/,"")` (which only removes the least significant zero-digits to the right of the decimal point) – MT0 Feb 11 '23 at 11:04
19

The question of the post was avoiding e notation numbers and having the number as a plain number.

Therefore, if all is needed is to convert e (scientific) notation numbers to plain numbers (including in the case of fractional numbers) without loss of accuracy, then it is essential to avoid the use of the Math object and other javascript number methods so that rounding does not occur when large numbers and large fractions are handled (which always happens due to the internal storage in binary format).

The following function converts e (scientific) notation numbers to plain numbers (including fractions) handling both large numbers and large fractions without loss of accuracy as it does not use the built-in math and number functions to handle or manipulate the number.

The function also handles normal numbers, so that a number that is suspected to become in an 'e' notation can be passed to the function for fixing.

The function should work with different locale decimal points.

94 test cases are provided.

For large e-notation numbers pass the number as a string.

Examples:

eToNumber("123456789123456789.111122223333444455556666777788889999e+50");
// output:
"12345678912345678911112222333344445555666677778888999900000000000000"
eToNumber("123.456123456789123456895e-80");
// output:
"0.00000000000000000000000000000000000000000000000000000000000000000000000000000123456123456789123456895"
eToNumber("123456789123456789.111122223333444455556666777788889999e-50");
// output:
"0.00000000000000000000000000000000123456789123456789111122223333444455556666777788889999"

Valid e-notation numbers in Javascript include the following:

123e1   ==> 1230
123E1   ==> 1230
123e+1  ==> 1230
123.e+1 ==> 1230
123e-1  ==> 12.3
0.1e-1  ==> 0.01
.1e-1   ==> 0.01
-123e1  ==> -1230

/******************************************************************
 * Converts e-Notation Numbers to Plain Numbers
 ******************************************************************
 * @function eToNumber(number)
 * @version  1.00
 * @param   {e nottation Number} valid Number in exponent format.
 *          pass number as a string for very large 'e' numbers or with large fractions
 *          (none 'e' number returned as is).
 * @return  {string}  a decimal number string.
 * @author  Mohsen Alyafei
 * @date    17 Jan 2020
 * Note: No check is made for NaN or undefined input numbers.
 *
 *****************************************************************/
function eToNumber(num) {
  let sign = "";
  (num += "").charAt(0) == "-" && (num = num.substring(1), sign = "-");
  let arr = num.split(/[e]/ig);
  if (arr.length < 2) return sign + num;
  let dot = (.1).toLocaleString().substr(1, 1), n = arr[0], exp = +arr[1],
      w = (n = n.replace(/^0+/, '')).replace(dot, ''),
    pos = n.split(dot)[1] ? n.indexOf(dot) + exp : w.length + exp,
    L   = pos - w.length, s = "" + BigInt(w);
    w   = exp >= 0 ? (L >= 0 ? s + "0".repeat(L) : r()) : (pos <= 0 ? "0" + dot + "0".repeat(Math.abs(pos)) + s : r());
  L= w.split(dot); if (L[0]==0 && L[1]==0 || (+w==0 && +s==0) ) w = 0; //** added 9/10/2021
  return sign + w;
  function r() {return w.replace(new RegExp(`^(.{${pos}})(.)`), `$1${dot}$2`)}
}
//*****************************************************************

//================================================
//             Test Cases
//================================================
let r = 0; // test tracker
r |= test(1, "123456789123456789.111122223333444455556666777788889999e+50", "12345678912345678911112222333344445555666677778888999900000000000000");
r |= test(2, "123456789123456789.111122223333444455556666777788889999e-50", "0.00000000000000000000000000000000123456789123456789111122223333444455556666777788889999");
r |= test(3, "123456789e3", "123456789000");
r |= test(4, "123456789e1", "1234567890");
r |= test(5, "1.123e3", "1123");
r |= test(6, "12.123e3", "12123");
r |= test(7, "1.1234e1", "11.234");
r |= test(8, "1.1234e4", "11234");
r |= test(9, "1.1234e5", "112340");
r |= test(10, "123e+0", "123");
r |= test(11, "123E0", "123");
// //============================
r |= test(12, "123e-1", "12.3");
r |= test(13, "123e-2", "1.23");
r |= test(14, "123e-3", "0.123");
r |= test(15, "123e-4", "0.0123");
r |= test(16, "123e-2", "1.23");
r |= test(17, "12345.678e-1", "1234.5678");
r |= test(18, "12345.678e-5", "0.12345678");
r |= test(19, "12345.678e-6", "0.012345678");
r |= test(20, "123.4e-2", "1.234");
r |= test(21, "123.4e-3", "0.1234");
r |= test(22, "123.4e-4", "0.01234");
r |= test(23, "-123e+0", "-123");
r |= test(24, "123e1", "1230");
r |= test(25, "123e3", "123000");
r |= test(26, -1e33, "-1000000000000000000000000000000000");
r |= test(27, "123e+3", "123000");
r |= test(28, "123E+7", "1230000000");
r |= test(29, "-123.456e+1", "-1234.56");
r |= test(30, "-1.0e+1", "-10");
r |= test(31, "-1.e+1", "-10");
r |= test(32, "-1e+1", "-10");
r |= test(34, "-0", "-0");
r |= test(37, "0e0", "0");
r |= test(38, "123.456e+4", "1234560");
r |= test(39, "123E-0", "123");
r |= test(40, "123.456e+50", "12345600000000000000000000000000000000000000000000000");

r |= test(41, "123e-0", "123");
r |= test(42, "123e-1", "12.3");
r |= test(43, "123e-3", "0.123");
r |= test(44, "123.456E-1", "12.3456");
r |= test(45, "123.456123456789123456895e-80", "0.00000000000000000000000000000000000000000000000000000000000000000000000000000123456123456789123456895");
r |= test(46, "-123.456e-50", "-0.00000000000000000000000000000000000000000000000123456");

r |= test(47, "-0e+1", "-0");
r |= test(48, "0e+1", "0");
r |= test(49, "0.1e+1", "1");
r |= test(50, "-0.01e+1", "-0.1");
r |= test(51, "0.01e+1", "0.1");
r |= test(52, "-123e-7", "-0.0000123");
r |= test(53, "123.456e-4", "0.0123456");

r |= test(54, "1.e-5", "0.00001"); // handle missing base fractional part
r |= test(55, ".123e3", "123"); // handle missing base whole part

// The Electron's Mass:
r |= test(56, "9.10938356e-31", "0.000000000000000000000000000000910938356");
// The Earth's Mass:
r |= test(57, "5.9724e+24", "5972400000000000000000000");
// Planck constant:
r |= test(58, "6.62607015e-34", "0.000000000000000000000000000000000662607015");

r |= test(59, "0.000e3", "0");
r |= test(60, "0.000000000000000e3", "0");
r |= test(61, "-0.0001e+9", "-100000");
r |= test(62, "-0.0e1", "-0");
r |= test(63, "-0.0000e1", "-0");


r |= test(64, "1.2000e0", "1.2000");
r |= test(65, "1.2000e-0", "1.2000");
r |= test(66, "1.2000e+0", "1.2000");
r |= test(67, "1.2000e+10", "12000000000");
r |= test(68, "1.12356789445566771234e2", "112.356789445566771234");

// ------------- testing for Non e-Notation Numbers -------------
r |= test(69, "12345.7898", "12345.7898") // no exponent
r |= test(70, 12345.7898, "12345.7898") // no exponent
r |= test(71, 0.00000000000001, "0.00000000000001") // from 1e-14
r |= test(72, 0.0000000000001, "0.0000000000001") // from 1e-13
r |= test(73, 0.000000000001, "0.000000000001") // from 1e-12
r |= test(74, 0.00000000001, "0.00000000001") // from 1e-11
r |= test(75, 0.0000000001, "0.0000000001") // from 1e-10
r |= test(76, 0.000000001, "0.000000001") // from 1e-9
r |= test(77, 0.00000001, "0.00000001") // from 1e-8
r |= test(78, 0.0000001, "0.0000001") // from 1e-7
r |= test(79, 1e-7, "0.0000001") // from 1e-7
r |= test(80, -0.0000001, "-0.0000001") // from 1e-7
r |= test(81, 0.0000005, "0.0000005") // from 1e-7
r |= test(82, 0.1000005, "0.1000005") // from 1e-7
r |= test(83, 1e-6, "0.000001") // from 1e-6

r |= test(84, 0.000001, "0.000001"); // from 1e-6
r |= test(85, 0.00001, "0.00001"); // from 1e-5
r |= test(86, 0.0001, "0.0001"); // from 1e-4
r |= test(87, 0.001, "0.001"); // from 1e-3
r |= test(88, 0.01, "0.01"); // from 1e-2
r |= test(89, 0.1, "0.1") // from 1e-1
r |= test(90, -0.0000000000000345, "-0.0000000000000345"); // from -3.45e-14
r |= test(91, -0, "0");
r |= test(92, "-0", "-0");
r |= test(93,2e64,"20000000000000000000000000000000000000000000000000000000000000000");
r |= test(94,"2830869077153280552556547081187254342445169156730","2830869077153280552556547081187254342445169156730");

if (r == 0) console.log("All 94 tests passed.");

//================================================
//             Test function
//================================================
function test(testNumber, n1, should) {
  let result = eToNumber(n1);
  if (result !== should) {
    console.log(`Test ${testNumber} Failed. Output: ${result}\n             Should be: ${should}`);
    return 1;
  }
}
Mohsen Alyafei
  • 4,765
  • 3
  • 30
  • 42
  • Are we sure this will always work in every country? I'm a bit concerned about this toLocaleString() but I have no way of testing it. Probably that no one does so we need to rely on our understanding of this function and make sure this is solid. – FlorianB Sep 24 '21 at 16:33
  • 1
    @FlorianB I have tested it again extensively with different Locales using DevTools and works fine when the decimal separator is a dot "." or a comma ",". Found a very odd case when the number is 0,00 meaning 0.00 and fixed it. – Mohsen Alyafei Oct 08 '21 at 23:14
  • 1
    You've done a great job on this code. Question: Have you also written a tool that converts in the opposite direction? If so, I'd like to see that too. – Lonnie Best Oct 19 '21 at 06:43
  • @LonnieBest I think I need to improve it and optimise it and do the opposite when time permits. Thanks – Mohsen Alyafei Oct 26 '21 at 05:20
  • I don't know if I'm missing anything, but throwing in `console.log(eToNumber(9999999999999999999999999999999999999999999))` did round up to "10000000000000000000000000000000000000000000" for me – RoboKy Jul 27 '23 at 07:43
16

Busting out the regular expressions. This has no precision issues and is not a lot of code.

function toPlainString(num) {
  return (''+ +num).replace(/(-?)(\d*)\.?(\d*)e([+-]\d+)/,
    function(a,b,c,d,e) {
      return e < 0
        ? b + '0.' + Array(1-e-c.length).join(0) + c + d
        : b + c + d + Array(e-d.length+1).join(0);
    });
}

console.log(toPlainString(12345e+12));
console.log(toPlainString(12345e+24));
console.log(toPlainString(-12345e+24));
console.log(toPlainString(12345e-12));
console.log(toPlainString(123e-12));
console.log(toPlainString(-123e-12));
console.log(toPlainString(-123.45e-56));
console.log(toPlainString('1e-8'));
console.log(toPlainString('1.0e-8'));
erdomke
  • 4,980
  • 1
  • 24
  • 30
Adam Leggett
  • 3,714
  • 30
  • 24
  • 3
    this worked for quoted plain number, unquoted plain number, quoted scientific notation, and unquoted scientific notation. – a_a Sep 17 '20 at 18:02
  • There is a bug in this. console.log(toPlainString("1e-8")); console.log(toPlainString("1.0e-8")); Do not give same result – otterslide Nov 17 '20 at 18:54
  • 1
    Still an issue. Try: console.log(toPlainString("1e-5")); console.log(toPlainString("1e-6")); console.log(toPlainString("1e-7")); The 1e-7 suddenly jumps to 8 decimal places, although 1,2,3,4,5,6 all work ok. – otterslide Nov 19 '20 at 17:44
  • @AdamLeggett Still the following numbers do not convert 1e-7 it should be 0.0000001 but gives 0.00000001 i.e. with one more zero inserted. Similarly for 1e-8, 1e-9 and higher. – Mohsen Alyafei Feb 02 '21 at 22:13
  • @otterslide change the regex to the following `replace(/(-?)(\d*)\.?(\d*)e([+-]\d+)/` to get it working. – Mohsen Alyafei Feb 02 '21 at 23:03
  • @AdamLeggett even after the above change, still -0 will be converted to 0. – Mohsen Alyafei Feb 03 '21 at 06:11
  • 2
    @MohsenAlyafei `(-0).toString()` returns `"0"`, and I'm not trying to go farther than expanding scientific notation here. That would require testing explicitly for `-0` or using toLocaleString/Intl.NumberFormat. – Adam Leggett Feb 04 '21 at 19:58
  • 1
    @MohsenAlyafei 0 === -0 – dsasmblr Feb 21 '21 at 17:18
15

one more possible solution:

function toFix(i){
 var str='';
 do{
   let a = i%10;
   i=Math.trunc(i/10);
   str = a+str;
 }while(i>0)
 return str;
}
Mirodil
  • 2,321
  • 2
  • 30
  • 38
  • 7
    This doesn't preserve the original value...for instance 31415926535897932384626433832795 becomes 31415926535897938480804068462624 – zero_cool Feb 02 '18 at 03:39
  • Not positive but likely to do with how JavaScript handles large numbers. – zero_cool Jan 13 '19 at 01:33
  • 1
    @domsson Basically because IEEE floating point numbers arithmetic apply. numbers in Javascript are actually represented as floating point number as well as "decimal numbers", there is no native "integer exact type". You can read more here : https://medium.com/dailyjs/javascripts-number-type-8d59199db1b6 – Pac0 Jan 28 '19 at 13:58
  • 1
    @zero_cool Any number greater than `Number.MAX_SAFE_INTEGER` is likely to suffer this problem. – Pac0 Jan 28 '19 at 14:01
13

Here is my short variant of Number.prototype.toFixed method that works with any number:

Number.prototype.toFixedSpecial = function(n) {
  var str = this.toFixed(n);
  if (str.indexOf('e+') === -1)
    return str;

  // if number is in scientific notation, pick (b)ase and (p)ower
  str = str.replace('.', '').split('e+').reduce(function(b, p) {
    return b + Array(p - b.length + 2).join(0);
  });
  
  if (n > 0)
    str += '.' + Array(n + 1).join(0);
  
  return str;
};

console.log( 1e21.toFixedSpecial(2) );       // "1000000000000000000000.00"
console.log( 2.1e24.toFixedSpecial(0) );     // "2100000000000000000000000"
console.log( 1234567..toFixedSpecial(1) );   // "1234567.0"
console.log( 1234567.89.toFixedSpecial(3) ); // "1234567.890"
VisioN
  • 143,310
  • 32
  • 282
  • 281
  • 5
    @manonthemat Of course they are not equal, because the first one is a formatted **string** and the second one is a `Number`. If you cast the first one to a `Number`, you will see that they are *absolutely* equal: https://jsfiddle.net/qd6hpnyx/1/. You can take your downvote back `:P` – VisioN Jan 18 '17 at 22:50
  • fair enough.... I just noticed I can't, unless you're editing your answer. – manonthemat Jan 18 '17 at 23:03
  • Better to also replace any trailing `.0` with empty string. – vsync Sep 11 '18 at 07:14
  • I get a somewhat strange value when I try `console.log(2.2e307.toFixedSpecial(10))`. I mean... I get several trailing zeros. Upvoting anyway because this seems closest to what I need. – peter.petrov Oct 08 '19 at 20:42
  • @peter.petrov Yes, you have `.0000000000` because you specified `10` as a parameter. If you want to get rid of them, use `0`. – VisioN Oct 09 '19 at 09:40
  • @VisioN Oh, OK, thanks. I thought this parameter is there to specify the base of the number. – peter.petrov Oct 09 '19 at 11:17
  • This has precision issues due to calling `toFixed`, and does not work at all with negative numbers. – Adam Leggett Jul 24 '20 at 14:49
  • Nice function but base and power are flipped... you called base p and power b. – SparK Jun 09 '21 at 05:41
7

The following solution bypasses the automatic exponentional formatting for very big and very small numbers. This is outis's solution with a bugfix: It was not working for very small negative numbers.

function numberToString(num)
{
    let numStr = String(num);

    if (Math.abs(num) < 1.0)
    {
        let e = parseInt(num.toString().split('e-')[1]);
        if (e)
        {
            let negative = num < 0;
            if (negative) num *= -1
            num *= Math.pow(10, e - 1);
            numStr = '0.' + (new Array(e)).join('0') + num.toString().substring(2);
            if (negative) numStr = "-" + numStr;
        }
    }
    else
    {
        let e = parseInt(num.toString().split('+')[1]);
        if (e > 20)
        {
            e -= 20;
            num /= Math.pow(10, e);
            numStr = num.toString() + (new Array(e + 1)).join('0');
        }
    }

    return numStr;
}

// testing ...
console.log(numberToString(+0.0000000000000000001));
console.log(numberToString(-0.0000000000000000001));
console.log(numberToString(+314564649798762418795));
console.log(numberToString(-314564649798762418795));
Krisztián Balla
  • 19,223
  • 13
  • 68
  • 84
  • 1
    numberToString(0.0000002) "0.00000019999999999999998" – sigmaxf Jun 04 '18 at 05:36
  • 1
    @raphadko That's the notorious Javascript **floating point precision** problem, which is another completely different pain when using numbers in JS... See for example https://stackoverflow.com/questions/1458633/how-to-deal-with-floating-point-number-precision-in-javascript – user56reinstatemonica8 Jul 05 '18 at 10:14
4

The answers of others do not give you the exact number!
This function calculates the desired number accurately and returns it in the string to prevent it from being changed by javascript!
If you need a numerical result, just multiply the result of the function in number one!

function toNonExponential(value) {
    // if value is not a number try to convert it to number
    if (typeof value !== "number") {
        value = parseFloat(value);

        // after convert, if value is not a number return empty string
        if (isNaN(value)) {
            return "";
        }
    }

    var sign;
    var e;

    // if value is negative, save "-" in sign variable and calculate the absolute value
    if (value < 0) {
        sign = "-";
        value = Math.abs(value);
    }
    else {
        sign = "";
    }

    // if value is between 0 and 1
    if (value < 1.0) {
        // get e value
        e = parseInt(value.toString().split('e-')[1]);

        // if value is exponential convert it to non exponential
        if (e) {
            value *= Math.pow(10, e - 1);
            value = '0.' + (new Array(e)).join('0') + value.toString().substring(2);
        }
    }
    else {
        // get e value
        e = parseInt(value.toString().split('e+')[1]);

        // if value is exponential convert it to non exponential
        if (e) {
            value /= Math.pow(10, e);
            value += (new Array(e + 1)).join('0');
        }
    }

    // if value has negative sign, add to it
    return sign + value;
}
4

You can use from-exponential module. It is lightweight and fully tested.

import fromExponential from 'from-exponential';

fromExponential(1.123e-10); // => '0.0000000001123'
shrpne
  • 309
  • 1
  • 11
3

This didn't help me:

console.log( myNumb.toLocaleString('fullwide', {useGrouping:false}) );

but this:

value.toLocaleString("fullwide", { 
   useGrouping: false, 
   maximumSignificantDigits: 20,
})
Oleg Khalidov
  • 5,108
  • 1
  • 28
  • 29
2

Use .toPrecision, .toFixed, etc. You can count the number of digits in your number by converting it to a string with .toString then looking at its .length.

  • for some reason, toPrecision doesn't work. if you try: window.examplenum = 1352356324623461346, and then say alert(window.examplenum.toPrecision(20)), it doesn't pop up an alert – chris Nov 06 '09 at 06:05
  • actually it pops up sometimes showing scientific notation, and other times it doesn't pop up at all. what am i doing wrong? – chris Nov 06 '09 at 06:06
  • 21
    Neither of the suggestion methods work for large (or small) numbers. `(2e64).toString()` will return `"2e+64"`, so `.length` is useless. – CodeManX Nov 05 '14 at 23:05
2

You can loop over the number and achieve the rounding

// functionality to replace char at given index

String.prototype.replaceAt=function(index, character) {
    return this.substr(0, index) + character + this.substr(index+character.length);
}

// looping over the number starts

var str = "123456789123456799.55";
var arr = str.split('.');
str = arr[0];
i = (str.length-1);
if(arr[1].length && Math.round(arr[1]/100)){
  while(i>0){
    var intVal = parseInt(str.charAt(i));

   if(intVal == 9){
      str = str.replaceAt(i,'0');
      console.log(1,str)
   }else{
      str = str.replaceAt(i,(intVal+1).toString()); 
      console.log(2,i,(intVal+1).toString(),str)
      break;
   }
   i--;
 }
}
Kapil gopinath
  • 1,053
  • 1
  • 8
  • 18
2

This is what I ended up using to take the value from an input, expanding numbers less than 17digits and converting Exponential numbers to x10y

// e.g.
//  niceNumber("1.24e+4")   becomes 
// 1.24x10 to the power of 4 [displayed in Superscript]

function niceNumber(num) {
  try{
        var sOut = num.toString();
      if ( sOut.length >=17 || sOut.indexOf("e") > 0){
      sOut=parseFloat(num).toPrecision(5)+"";
      sOut = sOut.replace("e","x10<sup>")+"</sup>";
      }
      return sOut;

  }
  catch ( e) {
      return num;
  }
}
Tyeth
  • 699
  • 5
  • 14
2

Your question:

number :0x68656c6c6f206f72656f
display:4.9299704811152646e+23

You can use this: https://github.com/MikeMcl/bignumber.js

A JavaScript library for arbitrary-precision decimal and non-decimal arithmetic.

like this:

let ten =new BigNumber('0x68656c6c6f206f72656f',16);
console.log(ten.toString(10));
display:492997048111526447310191
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
super2bai
  • 37
  • 4
2

I’ve just run a benchmark with my Chrome 113 to compare

  • BigInt(integer).toString()
  • and integer.toLocaleString("fullwide", {useGrouping: false}).

a = BigInt(Math.floor(Math.random() * 1e20)).toString();
a = Math.floor(Math.random() * 1e20).toLocaleString("fullwide", {useGrouping: false});

Stringifying an integer avoiding the scientific notation

Creating a bigint out of the number and stringifying it, turned out to be more than a hundred times faster than the toLocaleString.

Also, do note that BigInt(-0) drops the sign, unlike toLocaleString that retains it.

1

I think there may be several similar answers, but here's a thing I came up with

// If you're gonna tell me not to use 'with' I understand, just,
// it has no other purpose, ;( andthe code actually looks neater
// 'with' it but I will edit the answer if anyone insists
var commas = false;

function digit(number1, index1, base1) {
    with (Math) {
        return floor(number1/pow(base1, index1))%base1;
    }
}

function digits(number1, base1) {
    with (Math) {
        o = "";
        l = floor(log10(number1)/log10(base1));
        for (var index1 = 0; index1 < l+1; index1++) {
            o = digit(number1, index1, base1) + o;
            if (commas && i%3==2 && i<l) {
                o = "," + o;
            }
        }
        return o;
    }
}

// Test - this is the limit of accurate digits I think
console.log(1234567890123450);

Note: this is only as accurate as the javascript math functions and has problems when using log instead of log10 on the line before the for loop; it will write 1000 in base-10 as 000 so I changed it to log10 because people will mostly be using base-10 anyways.

This may not be a very accurate solution but I'm proud to say it can successfully translate numbers across bases and comes with an option for commas!

cmarangu
  • 204
  • 4
  • 16
1

Try this:

Number.standardizenumber = function (number,n) {

  var mantissa = number.toLocaleString(
    'en-US', {
      useGrouping: false,
      signDisplay: "never",
      notation: "scientific",
      minimumFractionDigits: 16,
      maximumFractionDigits: 16
    }
  ).toLowerCase().split('e')[0].replace(/\./g,'');
  var exponentNegative = "0".repeat(Math.max(+Math.abs(number).toExponential().toLowerCase().split('e-')[1]-1,0)) + mantissa;
  var exponentPositive = Math.abs(number)<1E17?mantissa.slice(0,+Math.abs(number).toExponential().toLowerCase().split('e+')[1]+1):mantissa+(Math.abs(number).toExponential().toLowerCase().split('e+')[1]-16);
  var decimalExpPositive = Math.abs(number)<1E17?mantissa.slice(0,Math.abs(number).toExponential().toLowerCase().split('e+')[0]-16):undefined;
  var fullDec = number===0?(1/number<0?'-0':'0'):(1/Math.sign(number)<0?'-':'')+(Math.abs(number)>=1?[exponentPositive,(number%1===0?(decimalExpPositive.slice(+Math.abs(number).toExponential().toLowerCase().split('e+')[1]+1)): undefined)].join('.'):`.${exponentNegative}`);
  return isNaN(number)===false&&Math.abs(number)<1E17?((number%1===0?number.toLocaleString('en-US', {useGrouping: false}):fullDec).includes('.')===false?fullDec.split('.')[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","):fullDec.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1').replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")):number.toLocaleString('en-US');
  
}

Number.standardizenumber(.0000001) // .0000001
Number.standardizenumber(1E21) // 1,000,000,000,000,000,000,000
Number.standardizenumber(1_234_567_890.123456) // 1,234,567,890.123456
0

I know it's many years later, but I had been working on a similar issue recently and I wanted to post my solution. The currently accepted answer pads out the exponent part with 0's, and mine attempts to find the exact answer, although in general it isn't perfectly accurate for very large numbers because of JS's limit in floating point precision.

This does work for Math.pow(2, 100), returning the correct value of 1267650600228229401496703205376.

function toFixed(x) {
  var result = '';
  var xStr = x.toString(10);
  var digitCount = xStr.indexOf('e') === -1 ? xStr.length : (parseInt(xStr.substr(xStr.indexOf('e') + 1)) + 1);
  
  for (var i = 1; i <= digitCount; i++) {
    var mod = (x % Math.pow(10, i)).toString(10);
    var exponent = (mod.indexOf('e') === -1) ? 0 : parseInt(mod.substr(mod.indexOf('e')+1));
    if ((exponent === 0 && mod.length !== i) || (exponent > 0 && exponent !== i-1)) {
      result = '0' + result;
    }
    else {
      result = mod.charAt(0) + result;
    }
  }
  return result;
}

console.log(toFixed(Math.pow(2,100))); // 1267650600228229401496703205376
andi
  • 6,442
  • 1
  • 18
  • 43
  • @Oriol - yeah, you're right; I guess whatever I tried it with previously just worked out that way due to other factors. I'll remove that little note in my answer. – andi Jan 13 '17 at 06:18
  • 1
    doesn't work: `toFixed(Number.MAX_VALUE) == Number.MAX_VALUE` – manonthemat Jan 17 '17 at 22:05
  • this just accidentally works for powers of 2 because that's how floating point numbers are kept in memory. In fact if you subtract some number from Math.pow(2, 100) it will still give the same answer. It just loses precision if the number is higher than `Number.MAX_SAFE_INTEGER` = `9007199254740991`. Any number higher than this is not stored precisely so it's not possible to read it back – Adassko Sep 24 '20 at 17:06
0

I tried working with the string form rather than the number and this seemed to work. I have only tested this on Chrome but it should be universal:

function removeExponent(s) {
    var ie = s.indexOf('e');
    if (ie != -1) {
        if (s.charAt(ie + 1) == '-') {
            // negative exponent, prepend with .0s
            var n = s.substr(ie + 2).match(/[0-9]+/);
            s = s.substr(2, ie - 2); // remove the leading '0.' and exponent chars
            for (var i = 0; i < n; i++) {
                s = '0' + s;
            }
            s = '.' + s;
        } else {
            // positive exponent, postpend with 0s
            var n = s.substr(ie + 1).match(/[0-9]+/);
            s = s.substr(0, ie); // strip off exponent chars            
            for (var i = 0; i < n; i++) {
                s += '0';
            }       
        }
    }
    return s;
}
Sanford Staab
  • 239
  • 2
  • 10
0

Currently there is no native function to dissolve scientific notation. However, for this purpose you must write your own functionality.

Here is my:

function dissolveExponentialNotation(number)
{
    if(!Number.isFinite(number)) { return undefined; }

    let text = number.toString();
    let items = text.split('e');

    if(items.length == 1) { return text; }

    let significandText = items[0];
    let exponent = parseInt(items[1]);

    let characters = Array.from(significandText);
    let minus = characters[0] == '-';
    if(minus) { characters.splice(0, 1); }
    let indexDot = characters.reduce((accumulator, character, index) =>
    {
        if(!accumulator.found) { if(character == '.') { accumulator.found = true; } else { accumulator.index++; } }
        return accumulator;
    }, { index: 0, found: false }).index;

    characters.splice(indexDot, 1);

    indexDot += exponent;

    if(indexDot >= 0 && indexDot < characters.length - 1)
    {
        characters.splice(indexDot, 0, '.');
    }
    else if(indexDot < 0)
    {
        characters.unshift("0.", "0".repeat(-indexDot));
    }
    else
    {
        characters.push("0".repeat(indexDot - characters.length));
    }

    return (minus ? "-" : "") + characters.join("");
}
Martin Wantke
  • 4,287
  • 33
  • 21
  • 1
    This fails for really big numbers. I tried 2830869077153280552556547081187254342445169156730 and got 2830869077153280500000000000000000000000000000000 – callback Oct 17 '19 at 09:12
-1

If you are just doing it for display, you can build an array from the digits before they're rounded.

var num = Math.pow(2, 100);
var reconstruct = [];
while(num > 0) {
    reconstruct.unshift(num % 10);
    num = Math.floor(num / 10);
}
console.log(reconstruct.join(''));
Jake M
  • 29
  • 2
  • This will return the right answer, but will take so much time and might end up for the execution to time out. – Hani Sep 06 '18 at 02:58
-1

You can also use YourJS.fullNumber. For instance YourJS.fullNumber(Number.MAX_VALUE) results in the following: 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

It also works for really small numbers. YourJS.fullNumber(Number.MIN_VALUE) returns this: 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005

It is important to note that this function will always return finite numbers as strings but will return non-finite numbers (eg. NaN or Infinity) as undefined.

You can test it out in the YourJS Console here.

Chris West
  • 885
  • 8
  • 17
-1

If you don't mind using Lodash, it has toSafeInteger()

_.toSafeInteger(3.2);
// => 3
 
_.toSafeInteger(Number.MIN_VALUE);
// => 0
 
_.toSafeInteger(Infinity);
// => 9007199254740991
 
_.toSafeInteger('3.2');
// => 3
lauri108
  • 1,381
  • 1
  • 13
  • 22
-3
function printInt(n) { return n.toPrecision(100).replace(/\..*/,""); }

with some issues:

  • 0.9 is displayed as "0"
  • -0.9 is displayed as "-0"
  • 1e100 is displayed as "1"
  • works only for numbers up to ~1e99 => use other constant for greater numbers; or smaller for optimization.
Wiimm
  • 2,971
  • 1
  • 15
  • 25
-4

You can use number.toString(10.1):

console.log(Number.MAX_VALUE.toString(10.1));

Note: This currently works in Chrome, but not in Firefox. The specification says the radix has to be an integer, so this results in unreliable behavior.

zamfofex
  • 487
  • 1
  • 4
  • 8
  • what the heck does this do? A radix of 10.1? – joniba Nov 03 '16 at 13:47
  • This doesn't work. Since ES5, implementations are required to use ToInteger on the argument. So using `10.1` or `10` or nothing are equivalent. – Oriol Jan 12 '17 at 22:42
  • Yes, this has indeed stopped working somewhat recently. Kinda sad, but this answer is now irrelevant. – zamfofex Jan 13 '17 at 23:36
-5

If you want to convert scientific notation to integer :

parseInt("5.645656456454545e+23", 10)

result: 5

Parth Developer
  • 1,371
  • 1
  • 13
  • 30
  • 1
    Just taking the everything in front of the dot has nothing to do with converting a scientific notation into it's value as a natural number. – René Baudisch Oct 21 '22 at 12:28
-7

I had the same issue with oracle returning scientic notation, but I needed the actual number for a url. I just used a PHP trick by subtracting zero, and I get the correct number.

for example 5.4987E7 is the val.

newval = val - 0;

newval now equals 54987000

Anirudh Ramanathan
  • 46,179
  • 22
  • 132
  • 191
RaulQ
  • 3
  • 1
  • 2
    This has no effect. 5.4987E7 has an exponent less than 21, so it shows up as the full number regardless when converted to string. (5.4987E21 - 0).toString() => "5.4987e+21" – Dwight Oct 10 '13 at 23:19