JavaScriptで多数の科学表記を回避する方法は?


183

JavaScript は、数値が大きくなると、大きなINT科学表記に変換します。これを防ぐにはどうすればよいですか?


1
1E21を「1000000000000000000000」と表示しますか?番号がどのように表示されるか、またはどのように保存されるかについて心配していますか?
outis 2009年

3
私はそれがどのように表示されるのか心配しています:document.write(myvariable)コマンドがあります
chris

1
番号がURLの一部として必要
クリス

3
@outis:数字を読みたいのは人間のユーザーだけではありません。translate科学表記法で座標を含む変換が発生すると、D3は例外をスローするようです。
またはMapper

2
特定のサイズまでの数を処理する場合、これはまだ使用されます。結局、科学的記法を知らないユーザーにとっては、科学的記法は読みにくいでしょう。
ヒッピートレイル2017

回答:


110

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

上記では、安価で簡単な文字列の繰り返し((new Array(n+1)).join(str))を使用しています。あなたはString.prototype.repeatロシアの農民乗算を使用して定義し、代わりにそれを使用することができます。

この回答は、科学的表記を使用せずに多数を表示するという質問のコンテキストにのみ適用する必要があります。何か他のもののために、あなたが使用する必要があるのBigIntなど、ライブラリをなBigNumber、LeemonのBigInt型、またはBigIntegerを。今後、新しいネイティブのBigInt(注:ないLeemonさん)が利用可能であるべきです。Chromiumとそれに基づくブラウザー(Chrome、新しいEdge [v79 +]、Brave)、Firefoxはすべてサポートされています。Safariのサポートが進行中です。

BigIntを使用する方法は次のとおりです。 BigInt(n).toString()

例:

注意より15-16桁(より具体的には、より大のJavaScript番号(ないのBigInt)などの任意の整数もし出力することを、しかし、Number.MAX_SAFE_INTEGER + 1[9,007,199,254,740,992])はJavaScriptのの番号タイプ(IEEE-754倍精度ので、丸められてもよいです浮動小数点)は、そのポイントを超えるすべての整数を正確に保持することはできません。とおりNumber.MAX_SAFE_INTEGER + 1、それは2の倍数で働いている、それはもう奇数を保持することはできませんので、(とsimiliarly、18,014,398,509,481,984でそれは...、16、その後、8そして、4の倍数で作業を開始)。

したがって、BigIntサポートに依存できる場合は、BigInt関数に渡す文字列として数値を出力します。

const n = BigInt("YourNumberHere");

例:


あなたの解決策では、2 ^ 1000の結果はwolframalphaとは非常に異なります。ポインタはありますか?
シェーンリスル

4
@Shane:このQ&Aは、浮動小数点数を10進数の整数として表示することに関するものであり、浮動小数点形式で表現できない数値(10進数に変換すると発生します)には対応していません。最後の行で述べたように、JS bigintライブラリが必要です。
outis

1
@PeterOlson:私が省略したように見えますMath.abs。ヘッドアップをありがとう。
outis

1
toFixed(Number.MAX_VALUE) == Number.MAX_VALUEその場合はtrueを返すはずですが、そうではありません...
manonthemat

3
実際、このコードは非常に小さい負の数では機能しません。toFixed(-1E-20)-> "0.0000000000000000000.09999999999999999"
davidthings

44

これは古い質問ですが、最近アクティブになっているようです。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

意図した結果で精度が重要な場合、これはおそらく望ましくありません。


2
これは間違いのない答えです。
アリア

これはPhantomJS 2.1.1では機能しません-それでも科学的表記になります。Chromeでは問題ありません。
Egor Nepomnyaschih

1
これは、非常に小さい小数では機能しないようです。varmyNumb = 0.0000000001; console.log(myNumb.toLocaleString( 'fullwide'、{useGrouping:false}));
eh1160

:一つは、非常に小さい小数、つまりフォーマットするmaximumSignificantDigitsオプション(最大21)を設定することができますjs console.log( myNumb.toLocaleString('fullwide', { useGrouping: true, maximumSignificantDigits:6}) );
サー。MaNiAl

20

数が少なく、小数点以下の桁数がわかっている場合は、toFixedを使用してから正規表現を使用して末尾のゼロを削除できます。

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

26
文字通り多数の質問
swyx '11

1
toFixed呼び出しの引数として0を避けるために注意してください-それは大きな末尾のゼロを消去するに終わるだろう:(1000).toFixed(0).replace(/\.?0+$/,"") // 1, not 1000
Egor Nepomnyaschih

15

もう1つの可能な解決策:

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

7
これは元の値を保持しません...たとえば、31415926535897932384626433832795は31415926535897938480804068462624
zero_cool

ポジティブではありませんが、JavaScriptが多数を処理する方法に関係している可能性があります。
zero_cool

@domsson基本的に、IEEE浮動小数点数の演算が適用されるため。Javascriptの数値は、実際には浮動小数点数および「10進数」として表されます。ネイティブの「整数型」はありません。詳しくは、medium.com
dailyjs

@zero_cool Number.MAX_SAFE_INTEGERこの問題が発生する可能性が高い数より大きい数値。
Pac0

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(p, b) {
    return p + Array(b - p.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"


Number.MAX_VALUE.toFixedSpecial(2)をNumber.MAX_VALUEと比較すると、それらが等しくないことがわかります。
manonthemat 2017年

4
@manonthematもちろん、最初の文字列はフォーマットされた文字列で、2番目の文字列はなので、これらは等しくありませんNumber。最初のものをにキャストNumberすると、それらが完全に等しいことがわかります:jsfiddle.net/qd6hpnyx/1。反対投票を取り消すことができます:P
VisioN

十分に公平です...あなたの答えを編集しない限り、私はできないことに気づきました。
manonthemat

末尾も.0空の文字列に置き換える方が適切です。
vsync

試してみると、ちょっと変な値になりconsole.log(2.2e307.toFixedSpecial(10))ます。つまり...後続のゼロがいくつか表示されます。とにかくこれが私が必要とするものに最も近いと思われるので賛成票を投じます。
peter.petrov

6

次のソリューションは、非常に大きな数値と非常に小さな数値の自動指数形式をバイパスします。これはバグ修正を伴うoutisの解決策です:非常に小さな負の数では機能しませんでした。

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


1
numberToString(0.0000002) "0.00000019999999999999998"
raphadko

1
悪名高いJavascriptのだ@raphadko 浮動小数点精度の例のためのJS ...を参照してください内の数値を使用した場合、別の完全に異なる痛みである問題、stackoverflow.com/questions/1458633/...
user56reinstatemonica8

3

他の人の答えはあなたに正確な数を与えません!
この関数は目的の数値を正確に計算し、JavaScriptで変更されないように文字列に返します。
数値結果が必要な場合は、関数の結果を1に乗算するだけです!

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

このコードのみの回答に関するいくつかの追加情報がおそらく役立つでしょう。
パイブ2017

関数に追加されたコメント。

2

使用.toPrecision.toFixedなどあなたがして、文字列に変換することにより、あなたの番号の桁数をカウントすることができ .toString、その時に見ています.length


何らかの理由で、toPrecisionが機能しません。試してみた場合:window.examplenum = 1352356324623461346の後に「alert(window.examplenum.toPrecision(20))」と発声しても、ポップアップは表示されません
chris

実際には、科学的表記が表示されることもあれば、まったく表示されないこともあります。何がいけないの?
クリス

18
どちらの提案方法も、大きい(または小さい)数に対しては機能しません。(2e64).toString()戻ります"2e+64"ので.length、役に立ちません。
CodeManX 2014年

2

これは、入力から値を取得するために使用したもので、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;
  }
}

1

あなたは数をループして丸めを達成することができます

//指定されたインデックスで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--;
 }
}

1

数値ではなく文字列形式を使用してみましたが、これは機能するようでした。私はこれを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;
}

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ループの前の行でlog10ではなくlogを使用すると問題が発生します。1000をbase-10に000と書くので、人々はほとんどとにかくbase-10を使用するため、log10に変更しました。

これは非常に正確な解決策ではないかもしれませんが、私はそれがベース間で数値を正常に変換でき、コンマのオプションが付いていると言って誇りに思います!


1

あなたの質問:

number :0x68656c6c6f206f72656f
display:4.9299704811152646e+23

これを使用できます:https : //github.com/MikeMcl/bignumber.js

任意精度の10進数および非10進数の算術演算用のJavaScriptライブラリ。

このような:

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

まあ、bignumber.jsは15桁を超えることができないことに注意してください...
Michael Heuberger '29

0

私はそれが何年後かを知っていますが、私は最近同様の問題に取り組んでいて、自分の解決策を投稿したいと思いました。現在受け入れられている答えは、指数部を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


@オリオール-そうです、あなたは正しいです。私が以前にそれを使って試したものは、他の要因のためにその方法でうまくいったと思います。私は私の答えからその小さなメモを削除します。
アンディ

1
動作しません:toFixed(Number.MAX_VALUE) == Number.MAX_VALUE
manonthemat 2017年

0
function printInt(n) { return n.toPrecision(100).replace(/\..*/,""); }

いくつかの問題があります:

  • 0.9は「0」と表示されます
  • -0.9は「-0」と表示されます
  • 1e100は「1」と表示されます
  • 〜1e99までの数値に対してのみ機能します=>より大きい数値には他の定数を使用します。または最適化のために小さくなります。

ええ、それらはいくつかの問題です。
アダムLeggett

0

正規表現を破壊する。これには精度の問題はなく、コードも多くありません。

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


-1

表示するためだけに行う場合は、丸められる前の数字から配列を作成できます。

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

これは正しい答えを返しますが、非常に時間がかかり、実行がタイムアウトになる可能性があります。
ハンナ

-1

現在、科学表記法を解くためのネイティブ関数はありません。ただし、このためには独自の機能を作成する必要があります。

これが私のものです:

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を試して2830869077153280500000000000000000000000000000000
コールバック

-1

from-exponentialモジュールを使用できます。軽量で完全にテストされています。

import fromExponential from 'from-exponential';

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

-1

YourJS.fullNumberを使用することもできます。たとえばYourJS.fullNumber(Number.MAX_VALUE)、次のような結果になります。 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

また、非常に少ない数でも機能します。 YourJS.fullNumber(Number.MIN_VALUE)これを返します: 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005

この関数は常に有限数を文字列として返しますが、非有限数(例:NaNまたはInfinity)を次のように返します。undefined

こちらYourJSコンソールでテストできます


-3

使用できますnumber.toString(10.1)

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

注:これは現在Chromeでは機能しますが、Firefoxでは機能しません。仕様では、基数は整数でなければならないため、これは信頼性のない動作になります。


これは一体何をしますか?10.1の基数?
joniba 2016年

これは機能しません。ES5以降、実装は引数でToIntegerを使用する必要があります。したがって、10.1 orまたは10orの使用は同等です。
Oriol

はい、これは確かに最近やや機能しなくなりました。ちょっと悲しいですが、この答えは関係ありません。
Zambonifofex 2017年

-6

私はoracleが科学表記を返すのと同じ問題がありましたが、URLの実際の数が必要でした。私はちょうどゼロを引くことによってPHPトリックを使用し、正しい数を取得します。

たとえば、5.4987E7はvalです。

newval = val - 0;

newvalは54987000に等しい


2
これは効果がありません。5.4987E7の指数は21未満であるため、文字列に変換すると、整数として表示されます。(5.4987E21-0).toString()=> "5.4987e + 21"
Dwight
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.