JavaScriptにおける計算精度の喪失に関する問題(二)
2922 ワード
3.3加減乗除
指定した数字を四捨五入するにはfloor/ceilまたは正規表現で四捨五入することができますが、四則演算はコンピュータが正確に認識できる整数にアップグレードして計算し、計算が終わってから降格することもできますか?この答えは肯定的です.まず加算法を見てみましょう.
このとき前の加算を行います
alert(Number(0.1).add(0.2));//0.3をイジェクト
この時、正確な結果を計算することができます.
同様に減算を書き出すことができます.
類似は乗算を書き出すことができます.
同様に除算を書くことができます.
重要なヒント:除算は数桁の小数まで正確にできないため、計算が完了する時に必要に応じて適切な四捨五入を行い、精度の違いを避けるべきである.
4.結論
コンピュータは2進数で数字を格納処理しているため、浮動小数点数を正確に表すことができないため、この精度の違いはほとんどすべてのプログラミング言語(例えばC/C+/C#,Java)に現れ、正確には「IEEE 754浮動小数点数フォーマットを使用した」と浮動小数点タイプ(float 32,double 64)を格納するどのプログラミング言語にもこの問題がある.C#、Javaはパッケージクラスdecimal、BigDecimalを提供して対応する処理を行うため、この精度の違いを避けた.
精度の違いを避けるために、計算する必要がある数字をフルアップグレード(10のn乗を乗じる)してコンピュータが正確に識別できる整数にし、計算が完了してから降格(10のn乗を除く)するのが、ほとんどのプログラミング言語で精度の違いを処理する一般的な方法です.
指定した数字を四捨五入するにはfloor/ceilまたは正規表現で四捨五入することができますが、四則演算はコンピュータが正確に認識できる整数にアップグレードして計算し、計算が終わってから降格することもできますか?この答えは肯定的です.まず加算法を見てみましょう.
Number.prototype.add = function(arg)
{
var n, n1, n2, s, s1, s2, ps;
s1 = this.toString();
ps = s1.split('.');
n1 = ps[1] ? ps[1].length : 0;
s2 = arg.toString();
ps = s2.split('.');
n2 = ps[1] ? ps[1].length : 0;
n = n1 > n2 ? n1 : n2;
s = Number(s1.movePoint(n)) + Number(s2.movePoint(n));
s = s.toString().movePoint(-n);
return Number(s);
}
このとき前の加算を行います
alert(Number(0.1).add(0.2));//0.3をイジェクト
この時、正確な結果を計算することができます.
同様に減算を書き出すことができます.
Number.prototype.sub = function(arg)
{
var n, n1, n2, s, s1, s2, ps;
s1 = this.toString();
ps = s1.split('.');
n1 = ps[1] ? ps[1].length : 0;
s2 = arg.toString();
ps = s2.split('.');
n2 = ps[1] ? ps[1].length : 0;
n = n1 > n2 ? n1 : n2;
s = Number(s1.movePoint(n)) - Number(s2.movePoint(n));
s = s.toString().movePoint(-n);
return Number(s);
}
類似は乗算を書き出すことができます.
Number.prototype.mul = function(arg)
{
var n, n1, n2, s, s1, s2, ps;
s1 = this.toString();
ps = s1.split('.');
n1 = ps[1] ? ps[1].length : 0;
s2 = arg.toString();
ps = s2.split('.');
n2 = ps[1] ? ps[1].length : 0;
n = n1 + n2;
s = Number(s1.replace('.', '')) * Number(s2.replace('.', ''));
s = s.toString().movePoint(-n);
return Number(s);
}
同様に除算を書くことができます.
Number.prototype.div = function(arg)
{
var n, n1, n2, s, s1, s2, ps;
s1 = this.toString();
ps = s1.split('.');
n1 = ps[1] ? ps[1].length : 0;
s2 = arg.toString();
ps = s2.split('.');
n2 = ps[1] ? ps[1].length : 0;
n = n1 - n2;
s = Number(s1.replace('.', '')) / Number(s2.replace('.', ''));
s = s.toString().movePoint(-n);
return Number(s);
}
重要なヒント:除算は数桁の小数まで正確にできないため、計算が完了する時に必要に応じて適切な四捨五入を行い、精度の違いを避けるべきである.
4.結論
コンピュータは2進数で数字を格納処理しているため、浮動小数点数を正確に表すことができないため、この精度の違いはほとんどすべてのプログラミング言語(例えばC/C+/C#,Java)に現れ、正確には「IEEE 754浮動小数点数フォーマットを使用した」と浮動小数点タイプ(float 32,double 64)を格納するどのプログラミング言語にもこの問題がある.C#、Javaはパッケージクラスdecimal、BigDecimalを提供して対応する処理を行うため、この精度の違いを避けた.
精度の違いを避けるために、計算する必要がある数字をフルアップグレード(10のn乗を乗じる)してコンピュータが正確に識別できる整数にし、計算が完了してから降格(10のn乗を除く)するのが、ほとんどのプログラミング言語で精度の違いを処理する一般的な方法です.