JavaScript浮動小数点演算精度問題

2421 ワード

JavaScript浮動小数点演算精度問題
JavaScript浮動小数点演算には精度の問題があります.ここでは問題の発生原因と解決方法を説明します.
問題の説明
例:
var x = 0.3 - 0.2; //30    20  
var y = 0.2 - 0.1; //20    10  
x == y; // =>false,     
x == 0.1; // =>false,    :0.09999999999999998
y == 0.1; // =>true
この問題はJavascriptの中だけではなく、バイナリ浮動小数点を使用したプログラミング言語にも問題があります.C++/C啣/Javaという言語にはすでにパッケージされています.精度の問題を回避する方法があります.JavaScriptは弱いタイプの言語です.デザイン思想から浮動小数点に対して厳しいデータタイプがありません.精度誤差の問題は特に顕著である.
原因が生ずる
JavascriptはIEEE-755の浮動小数点表現法を採用しています.これはバイナリ表現法で、スコアを正確に表します.例えば、1/2、1/8、1/1024.残念なことに、私たちがよく使うスコア(特に金融の計算)は10進数の1/10、1/100などです.バイナリ浮動小数点数表現法は0.1のような単純な数字を正確に表現できません.上訴コードの中のxとyの値は最終的な正しい値に非常に近いです.この計算結果は大多数の計算任務に適することができます.javascriptの未来バージョンはおそらく、これらの丸め問題を避けるために十進数のタイプをサポートします.その前に、大きな整数を使って重要な金融計算を行いたいです.例えば、小数点以下の‘円’を使って単位の演算を行うのではなく、整数‘分’を使ってください.以上は『Javascript権威ガイドP 37』から整理します.
0.1+0.2の計算
まず、私たちはコンピュータの角度に立って、0.1+0.2という小児科のような問題を考えます.コンピュータで読めるのはバイナリで、十進法ではないことを知っていますので、まず0.1と0.2をバイナリに変えてみます.
0.1 => 0.0001 1001 1001 1001…(    )
0.2 => 0.0011 0011 0011 0011…(    )
ダブル精度浮動小数部は最大52桁まで対応していますので、このように0.0100110011001100110010010001011001000110010010001100の浮動小数点数の制限で切り捨てられたバイナリ数字を2列加算した後、10進数に変換すると0.3000万0004になります.
ソリューション
浮動小数点演算の不正確な問題を解決するために、演算前に参加演算の数を整数にアップグレードします.計算が終わったら降格します.(0.1のXの二乗).
//  
Number.prototype.add = function(arg){
  var r1,r2,m;
  try{r1=this.toString().split(".")[1].length}catch(e){r1=0}
  try{r2=arg.toString().split(".")[1].length}catch(e){r2=0}
  m=Math.pow(10,Math.max(r1,r2))
  return (this*m+arg*m)/m
}
//  
Number.prototype.sub = function (arg){
  return this.add(-arg);
}

//  
Number.prototype.mul = function (arg)
{
  var m=0,s1=this.toString(),s2=arg.toString();
  try{m+=s1.split(".")[1].length}catch(e){}
  try{m+=s2.split(".")[1].length}catch(e){}
  return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
}

//  
Number.prototype.div = function (arg){
  var t1=0,t2=0,r1,r2;
  try{t1=this.toString().split(".")[1].length}catch(e){}
  try{t2=arg.toString().split(".")[1].length}catch(e){}
  with(Math){
  r1=Number(this.toString().replace(".",""))
  r2=Number(arg.toString().replace(".",""))
    return (r1/r2)*pow(10,t2-t1);
  }
}
みんなは後で自分のコードの中で浮動小数点に出会ってjs演算のこのような1つの特性を思い出して、必要でない誤りを免れます!