JavaScriptの減算危機 - なぜこのような結果?

日常業務の計算では、〜私たちは、薄い氷の上で足踏みが、JavaScriptは常に私たちに驚きのこの種を与えます

  1. 0.1 + 0.2 =
  2. 1から0.9 =?

ジュニアパートナーは、心臓の結果を与えた場合:

  1. 0.1 + 0.2 = 0.3
  2. 1から0.9 = 0.1

だから、小さなパートナーは厳しくファンの顔の事実になります。

console.log(0.1 + 0.2)。// 0.30000000000000004 
にconsole.log(1から0.9)。// 0.09999999999999998

これはなぜ起こるのでしょうか?それをチェックしよう!

再現するためにIII

目次に戻ります

以下に、我々は問題を再現するためにIEEE 754規格と同様に、加算と減算のJavaScriptの計算で説明します。

3.1根本的な原因:IEEE 754規格

目次に戻ります

IEEE 754標準64ビットの倍精度浮動小数点を使用してJavaScriptで数。この仕様は、1つの最高のシンボル、インデックス11、残りの有効番号52、具体的であり、メモリ内の64ビット浮動小数点表現のための浮動小数点形式を定義しています。

  • ビット0:符号ビット。S 0によって負の数として表さ、正の数を示す表現。
  • 1 - 11:指数部を格納します。Eで表されます。
  • 12から63:記憶小数部(即ち、有効数字)。彼はfで表されます。

 

JavaScriptの減算危機 - なぜこのような結果?

 

 

負の符号ビット数を決定し、インデックス値のサイズは、値の小数部の精度を決定する、部分的に決定しました。

IEEE 754は、第一桁のデフォルトは64ビット浮動小数点数に保存されていない、常に1で提供します。

64ビットの浮動小数点数に格納されているXX ...... XX部分は、52まで取ることができる言い換えれば、常に有効なデジタル形式1.XX ...... XX、。

したがって、JavaScriptは(事実上最初のビットが1の後に52 + 64ビット浮動小数点数)53ビットの最大有効桁数を提供します。

3.2再現:計算プロセス

目次に戻ります

JavaScriptの0.1 + 0.2で計算すると、何が起こるのだろうか?

1、0.1及びバイナリ表現への0.2:

0.1 - > 0.0001100110011001 ...(無制限)
0.2 - > 0.0011001100110011 ...(無制限

浮動小数点2進表現は無限大です

2つのバイナリの添加後に得られるように図2に示すように、53ビットのIEEE 754規格サポートの64ビットの倍精度浮動小数点小数部以来最大:

0.0100110011001100110011001100110011001100110011001100

浮動小数点の制限ので、この2進数小数点以下にこの2進数を変換し、切り捨てられ、それは0.30000000000000004、それによって発生するエラー算術演算が実行されることになります。

3.3拡張機能:デジタルセキュリティ

目次に戻ります

また、いくつかの問題があるため、上記の計算小数点以下が不正確読んだ後、jsliangは別の整数に話をする必要があり、整数を感じます。

console.log(19571992547450991)。
// 19571992547450990

にconsole.log(19571992547450991 === 19571992547450994)。
//真

それは非常に驚くべきことではありません!

番号タイプでJavaScriptが浮動小数点処理によって統一されるので、整数は、質問を免れることはできません。

//最大值
CONST MAXNUMBER = Math.pow(2、53) - 1。
console.log(MAXNUMBER)。// 9007199254740991
にconsole.log(Number.MAX_SAFE_INTEGER)。// 9007199254740991

//最小值
CONST MinNumber = - (Math.pow(2、53) - 1)。
console.log(MinNumber)。// -9007199254740991
にconsole.log(Number.MIN_SAFE_INTEGER)。// -9007199254740991

つまり、セキュリティの範囲の整数である:[-9,007,199,254,740,991、9007199254740991]。

もっとこの範囲よりも、精度の問題が破棄されているがあります。

もちろん、この問題は、ほとんどすべてIEEE-745標準のプログラミング言語を使用して、JavaScriptで存在していないこの問題を持っていますが、他の多くの言語では精度の問題を回避する方法の良いパッケージを持っています。

  • PHPのフロートフロート - マニュアル
  • Javaのあなたの小数点に行きますか? - ブライアン・ゲッツ

JavaScriptは弱い型付けの言語であるためと、デザイン思考から浮くように厳密なデータ型が存在しない、精度誤差の問題が特に顕著です。

これまでのところ、我々は、操作のデジタル・タイプを処理するときにJavaScriptが、い​​くつかの問題を抱えていることがわかります。

実際には、仕事は本当に問題になります!

ある日、私は、ワークシートの計算に対処した後、次の日は疑問視されている製品はほとんどの姉妹の後に、問題の行と言われました。

  • なぜ小数の学生は、あなたのコンピュータスアンBULE、それを計算することができますか?

沈黙3秒、および探査を見つけるために、上記の生成は、最終的には、次の解決策を見つけました。

四つの問題解決

目次に戻ります

さまざまな方法で浮動小数点演算の問題を解決するには、次の試み。

4.1 toFixed()

目次に戻ります

toFixed()メソッドは、数値形式表記固定小数点を使用します。

  • 「toFixed - MDN」

構文:numObj.toFixed(桁)

パラメータ:数字。小数点以下の桁数は、0から20(両端を含む)の間で、環境がより広い範囲をサポートするために実装されてもよいです。省略した場合、デフォルトは0です。

12345.6789 NUM =定数; 

num.toFixed(); // '12346':丸めは、小数部が含まれていません。
num.toFixed(1); // '12345.7 ': 丸め、小数点以下1桁。
num.toFixed(6); // '12345.678900 ': 予約6桁は、不十分な長さ0で満たされています。
(1.23e + 20).toFixed(2 ); // 123000000000000000000.00 通常のデジタルタイプに科学的表記法

String型の結果を()toFixed、Number型に変換することを忘れないでください。

toFixed()メソッドは、固定小数点数形式の表記法を使用し、結果は丸められます。

toFixed()によって、私たちは問題の一部を解決することができます。

オリジナル修正乗数:

console.log(1.0から0.9)。
// 0.09999999999999998

にconsole.log(0.3 / 0.1)。
// 2.9999999999999996

にconsole.log(9.7 * 100);
// 969.9999999999999

にconsole.log(2.22 + 0.1)。
// 2.3200000000000003

使用toFixed():

; parseFloatは((数式).toFixed(桁)):式@ 
// toFixed()精度パラメータ0と20の間でなければならないである

; - parseFloatは(0.9).toFixed(10)(1.0)
// 0.1

parseFloatは((0.3 / 0.1).toFixed(10));
// 3

parseFloatは(* 100(9.7).toFixed(10));
// 970

parseFloatは((2.22 + 0.1).toFixed(10));
// 2.32

だから、これについて話して、疑問が生じます:

  • parseFloatは(1.005.toFixed(2))

何がそれを得るでしょう、あなたの反応は1.01ではないでしょうか?

しかし、そうではありません、結果は次のとおりです。1。

そう言って、ENM ...投げます!O(╥﹏╥)O

toFixed()、それは実証済みでも最も安全なソリューションですされています。

手書き数学簡単4.2

目次に戻ります

JavaScriptの独自のメソッドが自分自身を助けることができないので、我々は唯一の考え方に変更することができます。

  • 小数部分は計算されたJavaScriptの文字列に変換しました
/ ** 
*検出されたデータか否か@nameオーバーラン
* @param {ナンバー数}
* /
CONST checkSafeNumber =(番号)=> {
IF(数>数値Number.MAX_SAFE_INTEGER || <Number.MIN_SAFE_INTEGER){
にconsole.log( `デジタル$ {番号}オーバーラン、 `リスクにしてください注意を払う);!
}
};

/ **
* @name補正データ
* @param {番号}数のニーズがデジタル補正すべき
数字の* @param {番号}精度正しい番号を
* /
改訂=一定(数、精度= 12である)=> {
リターンparseFloatは+(Number.toPrecision(精密));
}

/ **
*小数点の@nameの長さを取得する
* @param {数}デジタル必要に変換
* /
CONST = digitLength(番号)=> {
リターン(にNumber.toString()スプリット()[1] || '' '').LENGTH;
};

/ **
* @Name桁を除去
変換* @param {数}デジタル必要
* /
CONST floatToInt =(番号)=> {
リターンナンバー(にNumber.toString()に置き換え( '')。 '');
} ;

/ **
*精度乗算、@name
。* @param {数値} ARG1乗数1
ナンバー乗数2 ARG2 * @param {}
* /
CONST =乗算(ARG1、ARG2)=> {
CONST = BaseNum digitLength(ARG1) digitLength +(ARG2)
; CONST = floatToInt(ARG1)* floatToInt(ARG2)結果
checkSafeNumber(結果);
リターン結果/ Math.pow(10、BaseNum);
整数除算のための2つの整数//安全な範囲ではありません問題
//もしそうなら、私に証明
};

はconsole.log( '------ \ n型乗算:');
はconsole.log(* 100 9.7); // 969.9999999999999
console.log(乗算(9.7、100)); // 970

はconsole.log(0.01 * 0.07); // 0.0007000000000000001
はconsole.log(乗算(0.01、0.07)); // 0.0007

はconsole.log(* 100 1207.41) ; // 120,741.00000000001
はconsole.log(乗算(1207.41、100)); // 0.0007

/ **
*計算@name加算精度
誤差を* @description JavaScriptの加算結果、2つの浮動小数点数0.1 0.3 + 0.2 == ,!このエラーは、メソッドを使用して除去することができます。
* @Param {数値} ARG1の加数1
* @param {数加算値ARG2} 2
* + ARG1 ARG2 @return
* /
CONST =追加(ARG1、ARG2)=> {
CONST = BaseNum Math.pow(10、数学。 MAX(digitLength(ARG1)、digitLength(ARG2)));
リターン(乗算(ARG1、BaseNum)+乗算(ARG2、BaseNum))/ BaseNum;
}

はconsole.log( '------ \ N付加' );
console.log(1.001 + 0.003); // 1.0039999999999998
はconsole.log(追加(1.001、0.003)); // 1.004

はconsole.log(3.001 + 0.07); // 3.0709999999999997
はconsole.log(追加(3.001、0.07)) ; // 3.071

/ **
*減算演算@name精度
* @param {数値} ARG1の減数を1。
* @param {}番号ARG2被減数2
* /
CONST =減算(ARG1、ARG2)=> {
CONST = BaseNum数学.pow(10、Math.max(digitLength(ARG1)、digitLength(ARG2)));
リターン(乗算(ARG1、BaseNum) -乗算(ARG2、BaseNum))/ BaseNum;
};

はconsole.log(「--- --- \ N-減算:「);
はconsole.log(0.3から0.1); // 0.19999999999999998
はconsole.log(減算(0.3、0.1)); // 0.2

/ **
* @name精度計算分割
* @param {番号} arg1に除数
* @param {数値} ARG2除数2
* /
constの分割=(ARG1、ARG2)=> {
CONST baseNum = Math.pow(10、Math.max(digitLength(ARG1)、digitLength(ARG2)))。
リターン乗算(引数1、baseNum)/乗算(ARG2、baseNum)。
}。

console.log( '------ \ nは除法:');
console.log(0.3 / 0.1)。// 2.9999999999999996
にconsole.log(分割(0.3、0.1))。// 3

にconsole.log(1.21 / 1.1)。// 1.0999999999999999
にconsole.log(分割(1.21、1.1))。// 1.1

にconsole.log(1.02 / 1.1); // 0.9272727272727272
にconsole.log(分割(1.02、1.1))。!//数字9272727272727272超限、请注意风险0.9272727272727272

はconsole.log(1207.41 / 100); // 12.074100000000001
にconsole.log(分割(1207.41、100)); // 12.0741

/ **
*指定した桁数を丸める@Name
* @param {数値}番号オフ必要数
* @param {数値}最も近い小数点数に対する割合
* /
CONST = ROUND(数値、比)=> {
CONST = BaseNum Math.pow (10、比);
戻り課(恐らくMath.round(乗算(番号、BaseNum))、BaseNum);
問題がある場合は、//恐らくMath.round後の()があれば、それを証明してください、小数点以下の位を四捨五入して
// HTTPS ://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/round
}

はconsole.log( '------ \ N-丸み:');
はconsole.log(0.105 .toFixed(2)); // '0.10'
にconsole.log(2、0.105(丸); 0.11 //

はconsole.log(1.335.toFixed(2)); // '1.33'
はconsole.log(ラウンド( 1.335、2)); 1.34 //

はconsole.log(-Round(2.5、0)); // -3
はconsole.log(-Round(20.51、0)); // -21

このコードでは、まず、セキュアなデータが得られ、ロックハンマーを乗算して整数に変換計算するデジタルすることによって計算します。

JavaScriptの整数演算問題になることはないでしょうか?

乗算を計算し、乗算が仮定されているという問題は、3つの演算によって加算、減算、除算、乗算の導入。

最後に、丸め規則は、乗算や除算によって行われました。

それによって生成されたデジタルのJavaScript恐らくMath.round()が問題になることはありません、

したがって、我々は二つの数字(予約指定された長さ)、そこではありません、問題を丸め加算、減算とを取得しますか?

もしそうなら、それを記入してください。

そうでない場合、あなたは、上記のほかに従った3つの数字2つの数の引き算することはできませんプラスまたはマイナス、さらに乗算と除算の数を実現しますか?

ファイブ既製のフレームワーク

目次に戻ります

このような重要な計算は、彼らが書く場合、あなたは常に危機の完全な感じ、安全でないと感じるだろう。

彼らはギャングスターは私たちにテストの多くを助け、そして大幅に私たちはクラスを書くために他の誰かを呼び出すことができますので、私たちの手書きの問題の問題を軽減しているように、多くの時間が、我々は、JavaScriptのコンピューティング・ベースを書かれた大物を使用することができますライブラリ。

次の推奨いくつかの良いライブラリ:

  • Math.js.

Math.jsは、JavaScriptとNode.jsの拡張数学ライブラリのための1つです。

これは、可撓性支持シンボリック計算式パーサー、組み込み関数と定数を多数有しており、数字、多数、複素数、画分、及び単位行列のような、異なるタイプのデータを処理するための統合ソリューションを提供します。

パワフルで使いやすいです。

  • decimal.js

あらゆるタイプのJavaScriptの小数精度。

  • big.js

任意精度の小数演算のために小さな、迅速、簡単に使用するライブラリ。

  • bignumber.js

任意精度の算術JavaScriptライブラリの一つ。

最後に、最後には、それは言及する価値がある:数字の計算は非常に厳格である場合は、おそらくあなたは、計算の後端が、その後、あなたに結果を返すようにすることを、バックエンド投げたパラメータを使用することができます。

たとえば〜ビットクレジット、コモディティ価格計算モールに関し、

おすすめ

転載: www.cnblogs.com/guchengnan/p/11959748.html