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

IT技术 javascript
2021-02-08 07:17:25

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

6个回答

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))。您可以String.prototype.repeat使用俄罗斯农民乘法定义并使用它。

此答案应仅适用于问题的上下文:在不使用科学记数法的情况下显示大量数字。对于其他任何事情,您都应该使用BigInt库,例如BigNumber、Leemon 的BigIntBigInteger展望未来,新的原生BigInt(注意:不是 Leemon 的)应该可用;Chromium和基于它的浏览器(Chrome、新的Edge [v79+]、Brave)和Firefox都有支持;Safari 的支持正在进行中。

以下是使用 BigInt 的方法: BigInt(n).toString()

例子:

但是请注意,您作为 JavaScript 数字(不是 BigInt)输出的任何超过 15-16 位(特别是大于Number.MAX_SAFE_INTEGER + 1[9,007,199,254,740,992])的整数都可能会被四舍五入,因为 JavaScript 的数字类型(IEEE-754 双精度浮点数)不能精确地保存超出该点的所有整数。由于Number.MAX_SAFE_INTEGER + 1它以 2 的倍数工作,所以它不能再容纳奇数(同样,在 18,014,398,509,481,984 开始以 4 的倍数工作,然后是 8,然后是 16,......)。

因此,如果您可以依靠BigInt支持,请将您的号码输出为您传递给BigInt函数的字符串

const n = BigInt("YourNumberHere");

例子:

您的解决方案为 2^1000 提供了与 wolframalpha 截然不同的结果。任何指针?
2021-03-10 07:17:25
@PeterOlson:看起来我遗漏了一个Math.abs. 谢谢你的提醒。
2021-03-13 07:17:25
@Shane:此问答是关于将浮点数显示为以 10 为基数的整数,并且不涉及无法以浮点格式表示的数字(转换为以 10 为基数时会出现这种情况)。您需要一个JS bigint库,如最后一行所述。
2021-04-02 07:17:25
实际上这段代码不适用于非常小的负数: toFixed( -1E-20 ) -> "0.0000000000000000000.09999999999999999"
2021-04-02 07:17:25
toFixed(Number.MAX_VALUE) == Number.MAX_VALUE 那么应该返回true,但它不会......
2021-04-06 07:17:25

我知道这是一个较旧的问题,但最近显示活跃。MDN 到LocaleString

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

如果准确性在预期结果中很重要,这可能是不可取的。

maximumFractionDigits 默认为 3,所以我认为实际的 sol'n 是 value.toLocaleString('fullwide',{useGrouping:false,maximumFractionDigits:20})
2021-03-11 07:17:25
这是万无一失的答案。
2021-03-12 07:17:25
这似乎不适用于非常小的小数: var myNumb = 0.0000000001; console.log( myNumb.toLocaleString('fullwide', { useGrouping: false }) );
2021-03-18 07:17:25
这在 PhantomJS 2.1.1 中不起作用 - 它仍然以科学记数法结束。在 Chrome 中很好。
2021-03-20 07:17:25
可以设置 maximumSignificantDigits 选项(最大 21)来格式化非常小的小数,即: js console.log( myNumb.toLocaleString('fullwide', { useGrouping: true, maximumSignificantDigits:6}) );
2021-04-04 07:17:25

对于小数,并且您知道需要多少位小数,您可以使用 toFixed 然后使用正则表达式删除尾随零。

Number(1e-7).toFixed(8).replace(/\.?0+$/,"") //0.000
字面意思是问大量的问题
2021-03-27 07:17:25
小心避免 0 作为 toFixed 调用的参数 - 它最终会擦除重要的尾随零: (1000).toFixed(0).replace(/\.?0+$/,"") // 1, not 1000
2021-03-28 07:17:25

另一种可能的解决方案:

function toFix(i){
 var str='';
 do{
   let a = i%10;
   i=Math.trunc(i/10);
   str = a+str;
 }while(i>0)
 return str;
}
@domsson 基本上是因为 IEEE 浮点数算法适用。Javascript 中的数字实际上表示为浮点数和“十进制数”,没有原生的“整数精确类型”。您可以在此处阅读更多信息:medium.com/dailyjs/javascripts-number-type-8d59199db1b6
2021-03-15 07:17:25
不是肯定的,但可能与 JavaScript 处理大数字的方式有关。
2021-03-20 07:17:25
这不会保留原始值...例如 31415926535897932384626433832795 变为 31415926535897938480804068462624
2021-04-04 07:17:25
@zero_cool 任何大Number.MAX_SAFE_INTEGER于此问题的数字都可能会遇到此问题。
2021-04-08 07:17:25

这是我Number.prototype.toFixed适用于任何数字方法的简短变体

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"

@manonthemat 当然它们不相等,因为第一个是格式化字符串,第二个是Number. 如果您将第一个转换为 a Number,您将看到它们绝对相等:jsfiddle.net/qd6hpnyx/1你可以收回你的反对票:P
2021-03-12 07:17:25
足够公平......我只是注意到我不能,除非你正在编辑你的答案。
2021-03-17 07:17:25
当我尝试时,我得到了一个有点奇怪的值console.log(2.2e307.toFixedSpecial(10))我的意思是......我得到了几个尾随零。无论如何都要投票,因为这似乎最接近我的需要。
2021-03-21 07:17:25
@peter.petrov 是的,.0000000000因为您指定10为参数。如果您想摆脱它们,请使用0.
2021-04-01 07:17:25
最好也.0用空字符串替换任何尾随
2021-04-06 07:17:25