JavaScriptで浮動小数点数の精度を処理する方法は?


620

次のダミーテストスクリプトがあります。

function test() {
  var x = 0.1 * 0.2;
  document.write(x);
}
test();

これは結果0.020000000000000004を印刷しますが、0.02(計算機を使用する場合)印刷する必要があります。私が理解している限り、これは浮動小数点乗算精度のエラーによるものです。

そのような場合に私が正しい結果を得るように誰かが良い解決策を持っています0.02か?などの関数があることはわかっていますがtoFixed、丸めが別の可能性になることもありますが、丸めたり丸めたりせずに実際に整数を印刷したいです。誰かが素敵でエレガントな解決策を持っているかどうか知りたいだけです。

もちろん、それ以外の場合は、10桁程度に丸めます。


118
実際、エラーは0.1有限の2進浮動小数点数にマップする方法がないためです。
アーロンディグラ

10
ほとんどの分数は、正確な精度の10進数に変換できません。良い説明はこちら:docs.python.org/release/2.5.1/tut/node16.html
Nate Zaugg


53
@SalmanA:JavaScriptランタイムがこの問題をあなたから隠しているということは、私が間違っていることを意味するものではありません。
アーロンDigulla

5
Aaronに同意しない場合、0.1を完全に完全にバイナリでコーディングする方法があります。しかし、IEEE 754はこれを必ずしも定義していません。一方の整数部分を2進数で、他方の小数点部分をn桁まで、通常の整数> 0のように2進数でコーディングし、最後に小数点の位置をコーディングする表現を想像してみてください。 。まあ、あなたはエラーなしで完全に0.1を表すでしょう。ところで、JSは有限数の小数を内部で使用するため、開発者は最後の小数でその間違いをしないように根性をコーディングすることもできます。
Fabien Haddadi 2016年

回答:


469

浮動小数点ガイド

この問題を回避するにはどうすればよいですか?

それは、どのような計算を行っているかによって異なります。

  • 結果を正確に合計する必要がある場合、特にお金を扱う場合は、特別な10進データ型を使用してください。
  • これらの余分な小数点以下の桁をすべて表示したくない場合は、結果を表示するときに、結果を固定小数点以下の桁数に丸めるだけです。
  • 利用可能な10進数のデータ型がない場合、代わりに整数を使用することもできます。たとえば、お金の計算はすべてセントで行います。しかし、これはより多くの作業であり、いくつかの欠点があります。

最初の点は、特定の正確な10進数の動作が本当に必要な場合にのみ適用されることに注意してください。ほとんどの人はそれを必要とせず、1/3で発生した場合に同じエラーで点滅することさえないことに気付かずに、プログラムが1/10のような数値で正しく機能しないことに単にイライラします。

最初の点が本当に当てはまる場合は、BigDecimal for JavaScriptを使用してください。これはエレガントではありませんが、不完全な回避策を提供するのではなく、実際に問題を解決します。


11
BigDecimalのデッドリンクに気づき、ミラーを探しているときにBigNumberという別の方法を見つけました:jsfromhell.com/classes/bignumber
Jacksonkr

4
@ bass-t:はい。ただし、浮動小数点数は仮数部の長さまでの整数を正確に表すことができ、ECMA標準に従って64ビットの浮動小数点数です。したがって、2 ^ 52までの整数を正確に表すことができます
Michael Borgwardt '25 / 07/25

5
@Karl:小数の1/10は、底が2の有限の2進数の小数として表すことはできません。これがJavaScriptの数値です。だから、ある実際には正確に同じ問題。
Michael Borgwardt 2014

12
私は今日、整数でもJavaScriptの精度に問題があることを学びました。console.log(9332654729891549)実際に印刷する9332654729891548(つまり、1つずつオフにする)ことを検討してください
mlathe

12
@mlathe:Doh .. ;P... 2⁵²= 4,503,599,627,370,4962⁵³= 9,007,199,254,740,992の間の表現可能な数は、正確に整数です。次の範囲については、から2⁵³2⁵⁴、すべてがさを乗じた2表現可能な数があるので、ものも含めなどから、前の範囲については逆に、2⁵¹2⁵²、間隔がある0.5などの基本を下げる| |単に増加に起因するこれがあります基数2 | 64ビットのfloat値の内/外の2進指数(これtoPrecision()により0、との間のの値について、まれに文書化された「予期しない」動作が説明されます1)。
GitaarLAB

126

私はPedro Ladariaのソリューションが好きで、似たようなものを使用しています。

function strip(number) {
    return (parseFloat(number).toPrecision(12));
}

Pedrosソリューションとは異なり、これは0.999を切り上げます...繰り返し、最下位桁のプラス/マイナス1まで正確です。

注:32ビットまたは64ビットの浮動小数点数を処理する場合、最良の結果を得るにはtoPrecision(7)およびtoPrecision(15)を使用する必要があります。理由については、この質問を参照してください。


21
12を選んだ理由は?
qwertymk 2015

18
toPrecision数値の代わりに文字列を返します。これは常に望ましいとは限りません。
SStanley 2016年

7
parseFloat(1.005).toPrecision(3)=> 1.00
Peter

5
@ user2428118、わかっています、丸め誤差を示すつもりでした。結果は1.01ではなく1.00です
Peter

9
:何user2428118 @十分に明らかではないかもしれないと述べた(9.99*5).toPrecision(2)= 50の代わりに、49.95 toPrecisionは全体の数だけでなく、小数がカウントされるため。その後、を使用できtoPrecision(4)ますが、結果が> 100の場合、最初の3つの数値と1つの小数点を許可し、ドットをシフトして、これを多かれ少なかれ使用不可能にするため、再び運が悪くなります。toFixed(2)
最終的に

79

数学的に傾いている場合:http : //docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

推奨されるアプローチは、補正係数を使用することです(整数間で計算が行われるように、適切な10の累乗を掛けます)。たとえば、の場合0.1 * 0.2、補正係数は10であり、計算を実行しています。

> var x = 0.1
> var y = 0.2
> var cf = 10
> x * y
0.020000000000000004
> (x * cf) * (y * cf) / (cf * cf)
0.02

(非常に迅速な)ソリューションは次のようになります。

var _cf = (function() {
  function _shift(x) {
    var parts = x.toString().split('.');
    return (parts.length < 2) ? 1 : Math.pow(10, parts[1].length);
  }
  return function() { 
    return Array.prototype.reduce.call(arguments, function (prev, next) { return prev === undefined || next === undefined ? undefined : Math.max(prev, _shift (next)); }, -Infinity);
  };
})();

Math.a = function () {
  var f = _cf.apply(null, arguments); if(f === undefined) return undefined;
  function cb(x, y, i, o) { return x + f * y; }
  return Array.prototype.reduce.call(arguments, cb, 0) / f;
};

Math.s = function (l,r) { var f = _cf(l,r); return (l * f - r * f) / f; };

Math.m = function () {
  var f = _cf.apply(null, arguments);
  function cb(x, y, i, o) { return (x*f) * (y*f) / (f * f); }
  return Array.prototype.reduce.call(arguments, cb, 1);
};

Math.d = function (l,r) { var f = _cf(l,r); return (l * f) / (r * f); };

この場合:

> Math.m(0.1, 0.2)
0.02

SinfulJSのようなテスト済みライブラリを使用することをお勧めします


1
Ilはこのエレガントな回避策を愛していますが、完璧ではないようです:jsfiddle.net/Dm6F5/1 Math.a(76.65、38.45)は115.10000000000002を返します
nicolallias

3
Math.m(10,2332226616)は "-19627406800"を返します。これは負の値です...上限がある必要があります-これがこの問題の原因である可能性があります。提案してください
Shiva Komuravelly 2014

1
これはすべて見栄えは良いですが、どこかに間違いがあるようです。
MrYellow 2015年

5
彼が言った非常に迅速な解決策...誰も言ったことのない修正された修正。
Cozzbie

2
上記のコードは使用しないでください。それが機能しない場合、それは絶対に「迅速な解決策」ではありません。これは数学関連の質問なので、正確さが必要です。
ドレナイ2017年

49

乗算のみを実行していますか?もしそうなら、あなたはあなたの利点に小数算術についてのきちんとした秘密を使うことができます。それですNumberOfDecimals(X) + NumberOfDecimals(Y) = ExpectedNumberOfDecimals。つまり、0.123 * 0.12小数点以下0.1233桁と小数点以下0.122 桁なので、小数点以下5桁になることがわかっている場合です。したがって、JavaScriptによって、0.014760000002精度を失うことを恐れずに小数点以下5桁まで安全に丸めることができるような数値が得られた場合。


6
...そして、小数点以下の正確な量を取得する方法。
line-o

7
0.5 * 0.2 = 0.10; 小数点以下2桁(またはそれ以下)で切り捨てることができます。しかし、この法則を超えて数学的重要性を持つ数は決してありません。
Nate Zaugg、2014

3
これについての引用はありますか?また、除算についても同様ではありません。
グリフィン

3
@NateZauggオーバーフローする小数を切り捨てることはできません。2090.5* 8.61は17999.205ですが、浮動小数点数では17999.204999999998であるため、金額を丸める必要があります
Lostfields

3
@Lostfields-あなたは正しいです!回答を更新しました。
ネイト・ザグ

29

sprintfJavaScriptの実装を探しているので、(バイナリ形式で保存されているため)小さなエラーのある浮動小数点数を期待どおりの形式で書き出すことができます。

javascript-sprintfを試してください。次のように呼び出します。

var yourString = sprintf("%.2f", yourNumber);

小数点以下2桁の浮動小数点数として数値を出力します。

浮動小数点を特定の精度に丸めるためだけにファイルを追加しない場合は、表示目的でNumber.toFixed()を使用することも できます。


4
これが最もクリーンなソリューションだと思います。結果が本当に0.02である必要がない限り、小さなエラーは無視できます。重要なのは、数値が適切に表示されることであり、任意の精度を持っているということではないようです。
ロング欧陽

2
表示については、これが確かに最良のオプションです。複雑な計算については、Borgwardtの回答を確認してください。
使用不可

4
ただし、これでもyourNumber.toFixed(2)とまったく同じ文字列が返されます。
ロバート

27

BigNumber.jsが私のニーズを満たしていることがわかりました

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

良いドキュメントがありますあり、著者はフィードバックに非常に注意深く対応しています。

同じ作者が他に2つの類似したライブラリを持っています:

Big.js

任意精度の小数演算用の小さくて高速なJavaScriptライブラリ。bignumber.jsの妹。

およびDecimal.js

JavaScriptの任意精度のDecimalタイプ。

BigNumberを使用したコードは次のとおりです。

$(function(){

  
  var product = BigNumber(.1).times(.2);  
  $('#product').text(product);

  var sum = BigNumber(.1).plus(.2);  
  $('#sum').text(sum);


});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<!-- 1.4.1 is not the current version, but works for this example. -->
<script src="http://cdn.bootcss.com/bignumber.js/1.4.1/bignumber.min.js"></script>

.1 &times; .2 = <span id="product"></span><br>
.1 &plus; .2 = <span id="sum"></span><br>


3
私の意見では、ライブラリを使用することは間違いなく最良の選択です。
アンソニー

1
このリンクからgithub.com/MikeMcl/big.js/issues/45 bignumber.js- > Financial decimal.js-> Scientific big.js-> ???
VEE

20
var times = function (a, b) {
    return Math.round((a * b) * 100)/100;
};

---または---

var fpFix = function (n) {
    return Math.round(n * 100)/100;
};

fpFix(0.1*0.2); // -> 0.02

---また---

var fpArithmetic = function (op, x, y) {
    var n = {
            '*': x * y,
            '-': x - y,
            '+': x + y,
            '/': x / y
        }[op];        

    return Math.round(n * 100)/100;
};

---のように---

fpArithmetic('*', 0.1, 0.2);
// 0.02

fpArithmetic('+', 0.1, 0.2);
// 0.3

fpArithmetic('-', 0.1, 0.2);
// -0.1

fpArithmetic('/', 0.2, 0.1);
// 2

4
その結果、同じ問題が発生すると思います。浮動小数点を返すため、戻り値も「正しくない」可能性が高くなります。
Gertjan、2010

1
とても賢くて便利です、+ 1。
Jonatas Walker、2016

18

この関数は、2つの浮動小数点数の乗算から必要な精度を決定し、適切な精度で結果を返します。エレガントではありませんが。

function multFloats(a,b){
  var atens = Math.pow(10,String(a).length - String(a).indexOf('.') - 1), 
      btens = Math.pow(10,String(b).length - String(b).indexOf('.') - 1); 
  return (a * atens) * (b * btens) / (atens * btens); 
}

ええ。はい、数値を浮動小数点演算用の文字列に変換し、それを答えとして提案しましょう。
アンドリュー

17

驚いたことに、この関数はまだ投稿されていませんが、他の関数には同様のバリエーションがあります。これは、Math.round()のMDN Webドキュメントからのものです。簡潔であり、さまざまな精度が可能です。

function precisionRound(number, precision) {
  var factor = Math.pow(10, precision);
  return Math.round(number * factor) / factor;
}

console.log(precisionRound(1234.5678、1)); //予想される出力:1234.6

console.log(precisionRound(1234.5678、-1)); //予想される出力:1230

var inp = document.querySelectorAll('input');
var btn = document.querySelector('button');

btn.onclick = function(){
  inp[2].value = precisionRound( parseFloat(inp[0].value) * parseFloat(inp[1].value) , 5 );
};

//MDN function
function precisionRound(number, precision) {
  var factor = Math.pow(10, precision);
  return Math.round(number * factor) / factor;
}
button{
display: block;
}
<input type='text' value='0.1'>
<input type='text' value='0.2'>
<button>Get Product</button>
<input type='text'>

更新:Aug / 20/2019このエラーに気づきました。Math.round()の浮動小数点精度エラーが原因だと思います。

precisionRound(1.005, 2) // produces 1, incorrect, should be 1.01

これらの条件は正しく機能します。

precisionRound(0.005, 2) // produces 0.01
precisionRound(1.0005, 3) // produces 1.001
precisionRound(1234.5, 0) // produces 1235
precisionRound(1234.5, -1) // produces 1230

修正:

function precisionRoundMod(number, precision) {
  var factor = Math.pow(10, precision);
  var n = precision < 0 ? number : 0.01 / factor + number;
  return Math.round( n * factor) / factor;
}

これは、小数を丸めるときに右側に数字を追加するだけです。MDNはMath.roundページを更新したので、誰かがより良い解決策を提供できるかもしれません。


間違った答え。10.2は常に10.19を返します。jsbin.com/tozogiwide/edit?html,js,console,output
Žilvinas

@Žilvinas投稿したJSBinリンクは、上記のMDN関数を使用していません。あなたのコメントは間違った人に向けられていると思います。
HelloWorldPeace

13

あなたは本当にあなたが実際に欲しい10進数をいくつ決めるかを決めなければなりません-ケーキを持ってそれを食べることもできません:-)

数値エラーは、それ以降の操作ごとに蓄積され、それを早期に切り落とさなければ、それは大きくなるだけです。きれいに見える結果を示す数値ライブラリは、すべてのステップで最後の2桁を単純に切り捨てます。数値コプロセッサにも、同じ理由で「通常」と「完全」の長さがあります。Cuf-offは、プロセッサにとっては安価ですが、スクリプト(pov(...)の乗算と除算および使用)では非常に高価です。良い数学ライブラリは、カットオフを行うためにfloor(x、n)を提供します。

したがって、少なくとも、pov(10、n)を使用してグローバルvar / constantを作成する必要があります。つまり、必要な精度を決定したことになります。

Math.floor(x*PREC_LIM)/PREC_LIM  // floor - you are cutting off, not rounding

結果を表示するだけで、if-sを実行していないと仮定して、計算を続け、最後に切り捨てることもできます。それができる場合は、.toFixed(...)の方が効率的です。

if-s / comparisonsを実行していて、切り捨てたくない場合は、通常はepsと呼ばれる小さな定数も必要です。これは、予想される最大エラーよりも小数点第1位高い値です。カットオフが最後の2つの小数点であるとすると、epsは最後から3番目に1(最下位3番目)であり、それを使用して結果が期待されるepsの範囲内にあるかどうかを比較できます(0.02 -eps <0.1 * 0.2 <0.02 + eps)。


貧しい人の丸めを行うために0.5を追加することもできます:Math.floor(x * PREC_LIM + 0.5)/ PREC_LIM
cmroanirgo

ただし、たとえばMath.floor(-2.1)-3です。だから多分例えば使用Math[x<0?'ceil':'floor'](x*PREC_LIM)/PREC_LIM
MikeM

なぜfloor代わりにround
Quinn Comendant、2015年

12

あなたは使用することができますparseFloat()し、toFixed()あなたが小さな操作のために、この問題のバイパスにしたい場合:

a = 0.1;
b = 0.2;

a + b = 0.30000000000000004;

c = parseFloat((a+b).toFixed(2));

c = 0.3;

a = 0.3;
b = 0.2;

a - b = 0.09999999999999998;

c = parseFloat((a-b).toFixed(2));

c = 0.1;

11

phpjs.orgのround()関数はうまく動作します:http ://phpjs.org/functions/round

num = .01 + .06;  // yields 0.0699999999999
rnum = round(num,12); // yields 0.07

2
@jrg慣例により、「5」で終わる数値は最も近い偶数に丸められます(常に切り上げまたは切り捨ては結果にバイアスをもたらすため)。したがって、4.725は小数点第2位に四捨五入され、実際には4.72になります。
マークA.ダラム

9

0.6 * 3それは素晴らしいです!))私にとってこれはうまくいきます:

function dec( num )
{
    var p = 100;
    return Math.round( num * p ) / p;
}

非常に非常にシンプル))


これは次のようなものでも機能し8.22e-8 * 1.3ますか?
Paul Carlton

0.6 x 3 = 1.8、結果を2に与えるコード...良くない。
Zyo

@Zyoこのインスタンスでは1.8を返します。どのように実行しましたか?
Drenai

面白い。これで乗算と除算の演算子を入れ替えることができ、それも機能します。
アンドリュー

9

一般的な用途では、この動作は許容できる可能性が高いことに注意してください。
これらの浮動小数点値を比較して適切なアクションを決定すると、問題が発生します。
ES6の出現によりNumber.EPSILON、許容可能なエラーマージンを決定するために新しい定数が定義されています。
したがって、このような比較を実行する代わりに

0.1 + 0.2 === 0.3 // which returns false

次のように、カスタム比較関数を定義できます。

function epsEqu(x, y) {
    return Math.abs(x - y) < Number.EPSILON;
}
console.log(epsEqu(0.1+0.2, 0.3)); // true

出典:http : //2ality.com/2015/04/numbers-math-es6.html#numberepsilon


私の場合、Number.EPSILONが小さすぎたため、たとえば、0.9 !== 0.8999999761581421
Tom

8

あなたが得た結果は、異なる言語、プロセッサ、オペレーティングシステムでの浮動小数点の実装全体で正確でかなり一貫しています-変化するのは、フロートが実際にdouble(またはそれ以上)であるときの不正確さのレベルです。

2進浮動小数点の0.1は10進の1/3(つまり、0.3333333333333 ...永遠に)のようなものであり、正確に処理する方法はありません。

フロート処理している場合は、常に小さな丸め誤差が予想されるため、表示された結果を常に適切な丸めにする必要があります。代わりに、すべての計算がプロセッサのネイティブバイナリで行われるため、非常に高速で強力な演算が得られます。

ほとんどの場合、解決策は固定小数点演算に切り替えることではありません。これは主に、速度が非常に遅く、99%の時間で精度が必要ないためです。そのレベルの精度が必要なもの(金融取引など)を扱っている場合は、JavaScriptはおそらく使用するのに最適なツールではありません(固定小数点型を強制したいので、静的言語の方が良いでしょう) )。

あなたはエレガントな解決策を探しています、それは恐らくこれです:フロートは高速ですが小さな丸め誤差があります-結果を表示するときは常に賢明なものに丸めます。


8

これを回避するには、浮動小数点ではなく整数値を使用する必要があります。したがって、2つの位置の精度が必要な場合は、値* 100を使用します。3つの位置の場合は1000を使用します。表示するときは、フォーマッタを使用して区切り記号を挿入します。

多くのシステムは、このように小数での作業を省略します。これが、多くのシステムがドル/ユーロ(浮動小数点)ではなくセント(整数)で機能する理由です。


7

問題

浮動小数点は、すべての小数値を正確に格納することはできません。したがって、浮動小数点形式を使用する場合、入力値には常に丸め誤差があります。もちろん、入力のエラーは出力のエラーになります。離散関数または演算子の場合、関数または演算子が離散しているポイントの周りの出力に大きな違いが生じる可能性があります。

浮動小数点値の入力と出力

したがって、浮動小数点変数を使用する場合は、常にこれに注意する必要があります。また、浮動小数点を使用した計算で必要な出力は、これを念頭に置いて表示する前に、常にフォーマット/条件付けする必要があります。
連続関数と演算子のみを使用する場合は、必要な精度に丸めることがよくあります(切り捨てないでください)。浮動小数点数を文字列に変換するために使用される標準のフォーマット機能は通常これを行います。
丸めによりエラーが追加され、合計エラーが目的の精度の半分を超える可能性があるため、出力は、入力の期待される精度と出力の目的の精度に基づいて修正する必要があります。あなたがすべき

  • 入力を予想される精度に丸めるか、より高い精度で値を入力できないようにします。
  • 丸め/フォーマットする前に、出力に小さな値を追加します。これは、必要な精度の1/4以下で、入力時および計算時の丸め誤差によって引き起こされる最大予想誤差よりも大きくなります。それが不可能な場合は、使用するデータ型の精度の組み合わせでは、計算に必要な出力精度を実現するには不十分です。

これら2つのことは通常行われず、ほとんどの場合、それらを行わないことによる差異はほとんどのユーザーにとって重要であるには小さすぎますが、これらの修正なしにユーザーが出力を受け入れないプロジェクトがすでにありました。

離散関数または演算子(モジュラなど)

個別の演算子または関数が含まれる場合、出力が期待どおりであることを確認するには、追加の修正が必要になる場合があります。丸め、丸める前に小さな修正を追加しても問題は解決しません。
離散関数または演算子を適用した直後に、中間計算結果の特別なチェック/修正が必要になる場合があります。特定のケース(モジュラ演算子)については、質問の私の回答を参照してください。なぜモジュラス演算子はJavaScriptで小数を返すのですか?

問題を回避する方が良い

多くの場合、このような計算にデータ型(整数または固定小数点形式)を使用することにより、これらの問題を回避した方が効率的です。その一例は、財務計算に浮動小数点値を使用してはならないことです。


4

見てい固定小数点演算を。操作したい数値の範囲が狭い場合(通貨など)、問題はおそらく解決します。私はそれをいくつかの10進数の値に四捨五入します。これが最も簡単な解決策です。


5
問題は、浮動小数点と固定小数点ではなく、2進数と10進数の問題です。
Michael Borgwardt 2010

4

ここにある私のキリアス算術ライブラリを試してみてください。より新しいバージョンが必要な場合は、入手できます。


4

ほとんどの小数は、2進浮動小数点型(ECMAScriptが浮動小数点値を表すために使用する型)では正確に表すことができません。したがって、任意の精度の算術型または10進数ベースの浮動小数点型を使用しない限り、洗練されたソリューションはありません。たとえば、Windowsに同梱されている電卓アプリは、この問題を解決するために任意精度演算が使用されるようになりました


4

ここに画像の説明を入力してください

    You can use library https://github.com/MikeMcl/decimal.js/. 
    it will   help  lot to give proper solution. 
    javascript console output 95 *722228.630 /100 = 686117.1984999999
    decimal library implementation 
    var firstNumber = new Decimal(95);
    var secondNumber = new Decimal(722228.630);
    var thirdNumber = new Decimal(100);
    var partialOutput = firstNumber.times(secondNumber);
    console.log(partialOutput);
    var output = new Decimal(partialOutput).div(thirdNumber);
    alert(output.valueOf());
    console.log(output.valueOf())== 686117.1985

3

そうです、その理由は浮動小数点数の精度が限られているためです。有理数を2つの整数の除算として格納します。ほとんどの場合、精度を失うことなく数値を格納できます。印刷に関しては、結果を分数として表示することができます。私が提案した表現では、それは簡単になります。

もちろん、それは無理な数ではあまり役に立ちません。しかし、あなたは、彼らが最も問題が(例えばような状況を検出する原因になりますように、あなたの計算を最適化することもできますsqrt(3)^2)


あなたは正しいです、その理由は、浮動小数点数の限られた精度がある - <pedant>実際に、OPは間違っている、不正確な浮動小数点演算にそれを置く</pedant>
detly

3

mod 3で厄介な丸めエラーの問題が発生しました。0を取得する必要がある場合、.000 ... 01が返されることがあります。これは簡単に処理でき、<= .01をテストするだけです。しかし、時々2.99999999999998を取得します。痛い!

BigNumbersは問題を解決しましたが、別のやや皮肉な問題を引き起こしました。BigNumbersに8.5を読み込もうとすると、実際には8.4999であり、有効桁数が15桁以上であることが通知されました。これは、BigNumbersがそれを受け入れることができなかったことを意味しました(この問題は多少皮肉なことだと私は言ったと思います)

皮肉な問題の簡単な解決策:

x = Math.round(x*100);
// I only need 2 decimal places, if i needed 3 I would use 1,000, etc.
x = x / 100;
xB = new BigNumber(x);

2

Number(1.234443).toFixed(2);を使用します。それは1.23を印刷します

function test(){
    var x = 0.1 * 0.2;
    document.write(Number(x).toFixed(2));
}
test();

2

decimal.jsbig.jsまたはbignumber.jsは、 JavaScriptでの浮動小数点操作の問題を回避するために使用することができます。

0.1 * 0.2                                // 0.020000000000000004
x = new Decimal(0.1)
y = x.times(0.2)                          // '0.2'
x.times(0.2).equals(0.2)                  // true

big.js:ミニマリスト。使いやすい; 小数点以下の桁数で指定された精度。精度は除算にのみ適用されます。

bignumber.js:2から64のベース。構成オプション; NaN; 無限大; 小数点以下の桁数で指定された精度。除算にのみ適用される精度。ベースプレフィックス。

decimal.js:2から64を基数にします。構成オプション; NaN; 無限大; 非整数の累乗、exp、ln、log; 有効桁数で指定された精度。常に適用される精度。乱数。

詳細な比較へのリンク


2

エレガント、予測可能、再利用可能

エレガントで再利用可能な方法で問題に対処しましょう。次の7行では.decimal、数値、数式、または組み込みMath関数の末尾に追加するだけで、任意の数値に必要な浮動小数点の精度にアクセスできます。

// First extend the native Number object to handle precision. This populates
// the functionality to all math operations.

Object.defineProperty(Number.prototype, "decimal", {
  get: function decimal() {
    Number.precision = "precision" in Number ? Number.precision : 3;
    var f = Math.pow(10, Number.precision);
    return Math.round( this * f ) / f;
  }
});


// Now lets see how it works by adjusting our global precision level and 
// checking our results.

console.log("'1/3 + 1/3 + 1/3 = 1' Right?");
console.log((0.3333 + 0.3333 + 0.3333).decimal == 1); // true

console.log(0.3333.decimal); // 0.333 - A raw 4 digit decimal, trimmed to 3...

Number.precision = 3;
console.log("Precision: 3");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0.01
console.log((0.0008 + 0.0002).decimal); // 0.001

Number.precision = 2;
console.log("Precision: 2");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0.01
console.log((0.0008 + 0.0002).decimal); // 0

Number.precision = 1;
console.log("Precision: 1");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0.1
console.log((0.008 + 0.002).decimal); // 0
console.log((0.0008 + 0.0002).decimal); // 0

Number.precision = 0;
console.log("Precision: 0");
console.log((0.8 + 0.2).decimal); // 1
console.log((0.08 + 0.02).decimal); // 0
console.log((0.008 + 0.002).decimal); // 0
console.log((0.0008 + 0.0002).decimal); // 0

乾杯!


2
反対票を投じる場合は、少なくとも理由を記入してください。
Bernesto

1

使用する

var x = 0.1*0.2;
 x =Math.round(x*Math.pow(10,2))/Math.pow(10,2);

4
うーん...しかし、これは常に小数点以下2桁に丸められることに注意してください。それはもちろんオプションですが、計算0.55 * 0.55についてはどうですか(正確な数値が事前にわからないため。0.3025ではなく0.3が得られます。もちろん、を使用できますMath.round(x*Math.pow(10,4))/Math.pow(10,4);。丸めは常にオプションです。しかし、もっと良い解決策があるかどうかを知りたかっただけです
ジュリ



1

これは私にとってはうまくいきます:

function round_up( value, precision ) { 
    var pow = Math.pow ( 10, precision ); 
    return ( Math.ceil ( pow * value ) + Math.ceil ( pow * value - Math.ceil ( pow * value ) ) ) / pow; 
}

round_up(341.536, 2); // 341.54

1
残念ながら、round_up(4.15,2)=> 4.16。
jrg j '18

1

次の関数を使用して出力します。

var toFixedCurrency = function(num){
    var num = (num).toString();
    var one = new RegExp(/\.\d{1}$/).test(num);
    var two = new RegExp(/\.\d{2,}/).test(num);
    var result = null;

    if(one){ result = num.replace(/\.(\d{1})$/, '.$10');
    } else if(two){ result = num.replace(/\.(\d{2})\d*/, '.$1');
    } else { result = num*100; }

    return result;
}

function test(){
    var x = 0.1 * 0.2;
    document.write(toFixedCurrency(x));
}

test();

出力に注意してくださいtoFixedCurrency(x)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.