如何在JavaScript中避免使用大数字的科学记数法?

时间:2009-11-06 05:54:02

标签: javascript

当数字变大时,JavaScript会将大型INT转换为科学记数法。我怎样才能防止这种情况发生?

23 个答案:

答案 0 :(得分:96)

Number.toFixed,但是如果数字是> = 1e21并且最大精度为20,它使用科学记数法。除此之外,你可以自己滚动,但它会很乱。

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;
}

上面使用便宜的''n'-easy字符串重复((new Array(n+1)).join(str))。您可以使用俄语Peasant Multiplication定义String.prototype.repeat并使用它。

此答案应仅适用于问题的上下文:不使用科学记数法显示大量数字。对于其他任何内容,您应该使用BigInt库,例如BigNumber,Leemon的BigIntBigInteger。展望未来,应该原生支持BigInt(注意:不是Leemon's)(Chrome有支持,并且正在为Firefox工作。)

答案 1 :(得分:18)

对于较小的数字,你知道你想要多少小数,你可以使用toFixed,然后使用正则表达式删除尾随的零。

Number(1e-7).toFixed(8).replace(/\.?0+$/,"") //0.000

答案 2 :(得分:17)

我知道这是一个较旧的问题,但显示最近处于活动状态。 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"

您可以使用选项来格式化输出。

注意:

Number.toLocaleString()在小数点后16位舍入,这样...

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

...返回...

586084736227728400000000000000000000000

如果准确性对预期结果很重要,那么这可能是不希望的。

答案 3 :(得分:16)

另一个可能的解决方案:

function toFix(i){
 var str='';
 do{
   let a = i%10;
   i=Math.trunc(i/10);
   str = a+str;
 }while(i>0)
 return str;
}

答案 4 :(得分:8)

以下是Number.prototype.toFixed方法的简短变体,适用于任何数字:

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

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

1e21.toFixedSpecial(2);       // "1000000000000000000000.00"
2.1e24.toFixedSpecial(0);     // "2100000000000000000000000"
1234567..toFixedSpecial(1);   // "1234567.0"
1234567.89.toFixedSpecial(3); // "1234567.890"

答案 5 :(得分:6)

以下解决方案绕过了非常大和非常小的数字的自动指数格式。这是outis's solution带有错误修正:它不适用于非常小的负数。

&#13;
&#13;
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));
&#13;
&#13;
&#13;

答案 6 :(得分:5)

帖子的问题是避免使用 e 符号数字并将数字作为普通数字。

因此,如果只需要将 e(科学)记数法数字转换为普通数字(包括小数)而不会损失准确性,那么必须避免使用Math 对象和其他 javascript 数字方法,以便在处理大数字和大分数时不会发生舍入(由于二进制格式的内部存储总是发生这种情况)。 >

以下函数将 e(科学)记数法数字转换为普通数字(包括分数),可以同时处理大数和大分数而不会损失准确性,因为它不使用内置数学和数字函数来处理或操作数字.

该函数还处理普通数字,因此可以将怀疑变成“e”符号的数字传递给函数进行修复。

该函数应该使用不同的语言环境小数点。

提供了 94 个测试用例。

对于大的电子符号数字,将数字作为字符串传递。

示例:

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

Javascript 中有效的电子符号数字包括以下内容:

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];
  let 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());
  if (!+w) w = 0; 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;
  }
}

答案 7 :(得分:5)

消除正则表达式。这没有精度问题,也不是很多代码。

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'));

答案 8 :(得分:3)

其他人的答案并没有给你确切的数字!
此函数准确计算所需的数字并将其返回到字符串中,以防止它被javascript更改!
如果你需要一个数值结果,只需将函数的结果乘以第一个!

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;
}

答案 9 :(得分:3)

这就是我最终用来从输入中获取值,扩展小于17的数字并将指数数转换为x10 y

// 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;
  }
}

答案 10 :(得分:2)

我尝试使用字符串形式而不是数字,这似乎有效。我只在Chrome上测试了它,但它应该是通用的:

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;
}

答案 11 :(得分:2)

我认为可能有几个类似的答案,但这是我提出的一件事

// 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);

注意:这只是与javascript数学函数一样准确,并且在for循环之前使用log而不是log10时遇到问题;它将在10-base中写入1000作为000,因此我将其更改为log10,因为无论如何人们将主要使用base-10。

这可能不是一个非常准确的解决方案,但我很自豪地说它可以成功地在各个基础上翻译数字并附带逗号选项!

答案 12 :(得分:2)

你可以循环数字并实现舍入

  

//在给定索引处替换char的功能

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

//循环数字开始

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--;
 }
}

答案 13 :(得分:1)

我知道它已经很多年了,但我最近一直在研究类似的问题,我想发布我的解决方案。当前接受的答案用0表示填充指数部分,并且我试图找到确切的答案,尽管由于JS的浮点精度限制,对于非常大的数字通常并不完全准确。

这适用于Math.pow(2, 100),返回正确的值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

答案 14 :(得分:1)

你的问题:

number :0x68656c6c6f206f72656f display:4.9299704811152646e+23

你可以用这个: https://github.com/MikeMcl/bignumber.js

  

用于任意精度十进制和非十进制算术的JavaScript库。

像这样:

let ten =new BigNumber('0x68656c6c6f206f72656f',16); console.log(ten.toString(10)); display:492997048111526447310191

答案 15 :(得分:1)

使用.toPrecision.toFixed等。您可以将数字转换为包含.toString的字符串,然后查看其.length来计算数字中的位数。

答案 16 :(得分:0)

如果你只是为显示而做,你可以在它们被舍入之前从数字构建一个数组。

var num = Math.pow(2, 100);
var reconstruct = [];
while(num > 0) {
    reconstruct.unshift(num % 10);
    num = Math.floor(num / 10);
}
console.log(reconstruct.join(''));

答案 17 :(得分:0)

目前没有解决科学记数法的原生功能。但是,为此您必须编写自己的功能。

这是我的:

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("");
}

答案 18 :(得分:0)

您可以使用from-exponential模块。它轻巧且经过全面测试。

import fromExponential from 'from-exponential';

fromExponential(1.123e-10); // => '0.0000000001123'

答案 19 :(得分:0)

您还可以使用YourJS.fullNumber。例如,YourJS.fullNumber(Number.MAX_VALUE)产生以下结果: 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

它也适用于非常小的数字。 YourJS.fullNumber(Number.MIN_VALUE)返回以下内容: 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005

请注意,此函数将始终以字符串形式返回有限数字,但将以NaN形式返回非有限数字(例如Infinityundefined)。

您可以在YourJS Console here中对其进行测试。

答案 20 :(得分:0)

17.3.2

有一些问题:

  • 0.9显示为“ 0”
  • -0.9显示为“ -0”
  • 1e100显示为“ 1”
  • 仅适用于〜1e99以下的数字=>对更大的数字使用其他常数;或更小以进行优化。

答案 21 :(得分:-1)

您可以使用number.toString(10.1)

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

注意:目前适用于Chrome,但不适用于Firefox。规范说基数必须是整数,因此这会导致不可靠的行为。

答案 22 :(得分:-4)

我遇到了与oracle返回科学符号相同的问题,但我需要一个url的实际数字。我只是通过减去零来使用PHP技巧,并得到正确的数字。

例如5.4987E7是val。

newval = val - 0;

newval现在等于54987000

相关问题