如何在JavaScript中避免使用科学计数法表示大数字?

303

当JavaScript在字符串上下文中使用时,它将大于21位数的整数转换为科学计数法。我正在将整数作为URL的一部分打印出来。如何防止发生此转换?


6
您希望将1E21显示为“1000000000000000000000”吗?您关心的是数字的显示方式还是存储方式? - outis
7
我关心它的显示方式:我有一个document.write(myvariable)命令。 - chris
3
我需要数字作为URL的一部分。 - chris
9
人类用户并不是唯一想要读取数字的群体。当遇到包含科学计数法坐标的"translate"转换时,D3似乎会抛出异常。 - O. R. Mapper
5
当你处理一定范围内的数字时,仍然有使用价值。毕竟,对于不了解科学计数法的用户来说,科学计数法将很难阅读。 - hippietrail
显示剩余2条评论
28个回答

3

这并没有帮助我:

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

但这个:

value.toLocaleString("fullwide", { 
   useGrouping: false, 
   maximumSignificantDigits: 20,
})

2
你可以循环数字并实现四舍五入。

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

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

2

这是我最终使用的方法,用于获取输入值,将小于17位数的数字扩展,并将指数形式的数字转换为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;
  }
}

2

使用.toPrecision.toFixed等方法。您可以通过将数字转换为字符串并查看其.length来计算数字中的位数。


由于某些原因,toPrecision 不起作用。如果您尝试:window.examplenum = 1352356324623461346,然后说 alert(window.examplenum.toPrecision(20)),它不会弹出警报。 - chris
实际上,有时它会弹出科学计数法,而其他时候则根本不会弹出。我做错了什么? - chris
21
两种建议的方法都不适用于大(或小)的数字。(2e64).toString() 将返回 "2e+64",所以 .length 毫无用处。 - CodeManX

2

您的问题:

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

1
小心,bignumber.js 不能超过15个有效数字... - Michael Heuberger

2

我刚刚用我的 Chrome 113 进行了基准测试,以比较:

  • BigInt(integer).toString()
  • 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

number转换为bigint并将其字符串化,结果比使用toLocaleString快了一百倍以上

此外,请注意BigInt(-0)会丢弃符号,而toLocaleString会保留符号。


翻译成中文。只返回翻译的文本内容:这样做是否会得到相同的结果? - undefined
@Fed 是的,除了 -0 - undefined

1

我认为可能会有几个类似的答案,但这是我想到的一个东西。

// 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为底的1000写成000,因此我将其更改为log10,因为大多数人都会使用10进制。
这可能不是非常准确的解决方案,但我很自豪地说它可以成功地在不同进制之间转换数字,并带有逗号选项!

1

试试这个:

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

目前没有原生函数可以解决科学计数法。但是,为了实现这个目的,您必须编写自己的功能。

这是我的:

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

1
这对于非常大的数字会失败。我尝试了2830869077153280552556547081187254342445169156730,结果得到了2830869077153280500000000000000000000000000000000。 - callback

0
我尝试使用字符串形式而不是数字进行工作,这似乎可行。我只在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;
}

该函数在某些数字上失败了。请参见我上面发布的测试用例。谢谢。 - Mohsen Alyafei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接