【问题标题】:How to avoid scientific notation for large numbers in JavaScript?如何避免 JavaScript 中大数的科学记数法?
【发布时间】:2010-12-13 17:29:36
【问题描述】:

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

【问题讨论】:

  • 你想让 1E21 显示为 '1000000000000000000000' 吗?您是否关心数字的显示方式或存储方式?
  • 我担心它的显示方式:我有一个 document.write(myvariable) 命令
  • 我需要将数字作为 URL 的一部分
  • @outis:人类用户并不是唯一想要阅读数字的人。似乎 D3 在遇到包含科学计数法坐标的translate 转换时会抛出异常。
  • 当您处理达到一定大小的数字时,它仍然有用。毕竟不懂科学记数法的用户会很难看懂科学记数法。

标签: javascript


【解决方案1】:

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

【讨论】:

  • 由于某种原因,toPrecision 不起作用。如果你尝试:window.examplenum = 1352356324623461346,然后说alert(window.examplenum.toPrecision(20)),它不会弹出警报
  • 实际上它有时会弹出以显示科学计数法,而其他时候则根本不弹出。我做错了什么?
  • 这两种建议方法都不适用于大(或小)数字。 (2e64).toString() 会返回"2e+64",所以.length 没用。
【解决方案2】:

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()

例子:

const n = 13523563246234613317632;
console.log("toFixed (wrong): " + n.toFixed());
console.log("BigInt (right):  " + 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");

例子:

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

【讨论】:

  • 您的解决方案在 2^1000 上给我的结果与 wolframalpha 截然不同。有什么指点吗?
  • @Shane:这个问答是关于将浮点数显示为基数为 10 的整数,而不是解决无法以浮点格式表示的数字(转换为基数 10 时会出现这种情况) )。你需要一个JS bigint 库,正如最后一行中提到的那样。
  • @PeterOlson:看起来我漏掉了Math.abs。感谢您的提醒。
  • toFixed(Number.MAX_VALUE) == Number.MAX_VALUE 应该返回 true,但它不会......
  • 实际上这段代码不适用于非常小的负数:toFixed(-1E-20) -> "0.0000000000000000000.09999999999999999"
【解决方案3】:

我在 oracle 返回科学记数法时遇到了同样的问题,但我需要 URL 的实际数字。我只是使用了一个 PHP 技巧,减去零,我得到了正确的数字。

例如 5.4987E7 是 val。

newval = val - 0;

newval 现在等于 54987000

【讨论】:

  • 这没有效果。 5.4987E7 的指数小于 21,因此无论何时转换为字符串,它都会显示为完整数字。 (5.4987E21 - 0).toString() => "5.4987e+21"
【解决方案4】:

你可以遍历数字并实现四舍五入

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

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

【讨论】:

    【解决方案5】:

    这就是我最终用来从输入中获取值,扩展小于 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;
      }
    }
    

    【讨论】:

      【解决方案6】:

      我知道这是多年后的事了,但我最近一直在处理类似的问题,我想发布我的解决方案。当前接受的答案用 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

      【讨论】:

      • @Oriol - 是的,你是对的;我想我以前尝试过的任何东西都是由于其他因素而导致的。我会在我的回答中删除那个小注释。
      • 不起作用:toFixed(Number.MAX_VALUE) == Number.MAX_VALUE
      • 这只是意外地适用于 2 的幂,因为浮点数就是这样保存在内存中的。事实上,如果你从 Math.pow(2, 100) 中减去一些数字,它仍然会给出相同的答案。如果数字高于Number.MAX_SAFE_INTEGER = 9007199254740991,它只会失去精度。任何高于此的数字都不会精确存储,因此无法读取它
      【解决方案7】:

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

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

      【讨论】:

      • 小心避免 0 作为 toFixed 调用的参数 - 它最终会擦除重要的尾随零:(1000).toFixed(0).replace(/\.?0+$/,"") // 1, not 1000
      【解决方案8】:

      你可以使用number.toString(10.1):

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

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

      【讨论】:

      • 这到底是做什么的? 10.1 的基数?
      • 这不起作用。从 ES5 开始,实现需要在参数上使用 ToInteger。所以使用10.110 或没有任何等效项。
      • 是的,这确实在最近停止了工作。有点难过,但这个答案现在已经无关紧要了。
      【解决方案9】:

      另一种可能的解决方案:

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

      【讨论】:

      • 这不会保留原始值...例如 31415926535897932384626433832795 变为 31415926535897938480804068462624
      • 不是肯定的,但可能与 JavaScript 处理大量数字的方式有关。
      • @domsson 基本上是因为 IEEE 浮点数算法适用。 Javascript 中的数字实际上表示为浮点数以及“十进制数”,没有原生的“整数精确类型”。你可以在这里阅读更多:medium.com/dailyjs/javascripts-number-type-8d59199db1b6
      • @zero_cool 任何大于Number.MAX_SAFE_INTEGER 的数字都可能遇到这个问题。
      【解决方案10】:

      这是我的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。如果将第一个转换为 Number,您将看到它们绝对 相等:jsfiddle.net/qd6hpnyx/1。你可以收回你的反对票:P
      • 很公平......我只是注意到我不能,除非你正在编辑你的答案。
      • 最好也用空字符串替换任何尾随.0
      • 当我尝试console.log(2.2e307.toFixedSpecial(10)) 时,我得到了一个有点奇怪的值。我的意思是......我得到了几个尾随零。无论如何都赞成,因为这似乎最接近我的需要。
      • @peter.petrov 是的,您有 .0000000000,因为您将 10 指定为参数。如果您想摆脱它们,请使用0
      【解决方案11】:

      你的问题:

      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
      

      【讨论】:

      • 好吧,请注意 bignumber.js 不能超过 15 位有效数字...
      【解决方案12】:

      如果你只是为了显示,你可以在四舍五入之前从数字构建一个数组。

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

      【讨论】:

      • 这将返回正确的答案,但会花费很多时间并且可能最终导致执行超时。
      【解决方案13】:

      别人的答案没有给你确切的数字!
      这个函数精确计算出想要的数字,并在字符串中返回,防止被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;
      }
      

      【讨论】:

      • 有关此代码唯一答案的一些附加信息可能会有用。
      • 对函数添加的评论。
      【解决方案14】:

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

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

      【讨论】:

      • numberToString(0.0000002) "0.00000019999999999999998"
      • @raphadko 这就是臭名昭著的 Javascript 浮点精度 问题,这是在 JS 中使用数字时的另一个完全不同的痛苦……例如,参见 stackoverflow.com/questions/1458633/…
      【解决方案15】:

      我尝试使用字符串形式而不是数字,这似乎有效。我只在 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;
      }
      

      【讨论】:

      • 函数在某些数字上失败。请参阅我上面帖子中的测试用例。谢谢。
      【解决方案16】:

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

      这是我的:

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

      【讨论】:

      • 这对于非常大的数字会失败。我试过 2830869077153280552556547081187254342445169156730 并得到 28308690771532805000000000000000000000000000000000
      【解决方案17】:

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

      // 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 为底的。

      这可能不是一个非常准确的解决方案,但我很自豪地说它可以成功地跨基数转换数字并带有逗号选项!

      【讨论】:

        【解决方案18】:

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

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

        【讨论】:

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

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

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

        【讨论】:

          【解决方案20】:

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

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

          请务必注意,此函数将始终将有限数字作为字符串返回,但会将非有限数字(例如 NaNInfinity)作为 undefined 返回。

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

          【讨论】:

            【解决方案21】:
            function printInt(n) { return n.toPrecision(100).replace(/\..*/,""); }
            

            有一些问题:

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

            【讨论】:

            • 是的,这些都是一些问题。
            【解决方案22】:

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

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

            【讨论】:

            • 这适用于引用的纯数字、未引用的纯数字、引用的科学记数法和未引用的科学记数法。
            • 这里有一个错误。 console.log(toPlainString("1e-8")); console.log(toPlainString("1.0e-8"));不要给出相同的结果
            • 还是个问题。试试:console.log(toPlainString("1e-5")); console.log(toPlainString("1e-6")); console.log(toPlainString("1e-7")); 1e-7 突然跳到小数点后 8 位,虽然 1,2,3,4,5,6 都可以。
            • @MohsenAlyafei (-0).toString() 返回"0",我并不想在这里扩展科学记数法。这需要明确测试-0 或使用 toLocaleString/Intl.NumberFormat。
            • @MohsenAlyafei 0 === -0
            【解决方案23】:

            帖子的问题是避免使用 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],
                  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;
              }
            }

            【讨论】:

            • 我们确定这将在每个国家/地区始终有效吗?我有点担心这个 toLocaleString() 但我无法测试它。可能没有人这样做,所以我们需要依靠我们对这个函数的理解并确保它是可靠的。
            • @FlorianB 我已经使用 DevTools 对不同的语言环境再次进行了广泛的测试,并且当小数点分隔符是点“。”时工作正常。或逗号“,”。发现一个非常奇怪的情况,当数字为 0,00 时表示 0.00 并修复它。
            • 你在这段代码上做得很好。问题:您是否还编写了一个反向转换的工具?如果是这样,我也想看看。
            • @LonnieBest 我认为我需要改进和优化它,并在时间允许的情况下反其道而行之。谢谢
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-22
            • 2015-09-12
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多