理由:JSは、2に従って追加、減算、乗算、および小数の分割を処理します。Arg1に基づいて、Arg2の精度が拡大または逆に拡張されるため、次の状況が発生します。
JavaScript(JS)の小数点の追加、減算、乗算、分割の問題は、0.3*1 = 0.2999999999などのJSのバグです。
関数accdiv(arg1、arg2){var t1 = 0、t2 = 0、r1、r2; try {t1 = arg1.tostring()。split( "。")[1] .length} catch(e){} try {t2 = arg2.tostring()。split( "。")[1] .length} catch(e){} with(math){r1 = number(arg1.tostring()。 r2 = number(arg2.toString()。置換( "。"、 "))return accmul((r1/r2)、pow(10、t2-t1)); }} //複数関数accmul(arg1、arg2){var m = 0、s1 = arg1.toString()、s2 = arg2.toString(); {m+= s1.split( "。")[1] .length} catch(e){} try {m+= s2.split( "。"。 ")[1] .length} catch(e){} return number(s1.replace("。 "、"、 "))*number(s2.replace(10、" "、" accadd(arg1、arg2){var r1、r2、m; {r1 = arg1.tostring()。split( "。")[1] .length} catch(e){r1 = 0} try {r2 = arg2.tostring() (arg1*m+arg2*m)/m} //減算関数subtr(arg1、arg2){var r1、r2、m、n; try {r1 = arg1.tostring()。split( "。")[1] .length} catch(e){r1 = 0} try {r2 = arg2.tostring()。 n =(r1> = r2)?r1:r2; return((arg1*m-arg2*m)/m).tofixed(n); }JavaScriptのデジタル精度の喪失を分析しましょう。
1. JSデジタル精密損失のいくつかの典型的な問題
1. 2つの単純なフローティングポイント番号を追加します
0.1 + 0.2!= 0.3 // True
Firebug
これは実際にはファイアバグの問題ではありません。アラート(ハハ、冗談)で試すことができます。
Javaの計算結果をご覧ください
Pythonをご覧ください
2。大規模な整数操作
99999999999999999 == 10000000000000000001 //?
Firebug
16桁の数字と17桁の数字は実際には等しく、不合理です。
同じように
var x = 9007199254740992x + 1 == x //?
結果を参照してください
3つのビューは再び破壊されました。
3。Tofixedは丸くない(Chrome)
1.335.tofixed(2)// 1.33
Firebug
Chromeやその他のブラウザではオンラインで一貫性のない価格があり、まさに互換性のある問題が原因です。
2。JS数の損失の精度の理由
コンピューターのバイナリ実装とビット制限により、いくつかの数値を有限で表現することはできません。 Pi 3.1415926 ...、1.3333 ...など、いくつかの不合理な数値を有限に表現できないように。JSはIEEE 754仕様に従い、二重精度ストレージを採用し、64ビットを占有します。示されているように
意義
浮動小数点数、例えば
0.1 >> 0.0001 1001 1001 1001…(1001 Infinite Loop)0.2 >> 0.0011 0011 0011…(0011 Infinite Loop)
この時点では、小数システムを模倣することでのみ丸くすることができますが、2つのバイナリシステムのみがあります。0と1しかありません。したがって、0になり、1倍になります。これが、コンピューターの一部の浮動小数点数がエラーと精度の低下である基本的な理由です。
大整数の精度損失は、本質的に浮動小数点数と同じです。マンティッサの最大ビットは52ビットなので、JSで正確に表現できる最大整数はMath.Pow(2、53)で、9007199254740992です。
9007199254740992を超えると、精度が失われる可能性があります
9007199254740992 >> 100000000000000000 ... 000 //合計53 0900199254740992 + 1 >> 1000000000000000000 ... 001 //
実際には
9007199254740992 + 1 //失われた9007199254740992 + 2 //失われていない9007199254740992 + 3 //失われた9007199254740992 + 4 //失われていない
結果は図に示されています
上記のように、コンピューターのバイナリ表現では、一見有限の数値が無限であることがわかります。ストレージビット制限により、「逃げ出し」があり、精度の損失が発生します。
詳細な分析のために、このペーパー(Long and Smelly)を読むことができます:すべてのコンピューター科学者が浮動小数点算術について知っておくべきこと
3。解決策
整数の場合、フロントエンドの問題の確率は比較的低い場合があります。結局のところ、非常に大規模な整数を使用する必要がある企業はほとんどありません。計算結果がMath.Pow(2、53)を超えない限り、精度は失われません。
デシマルの場合、特に金額などのデータを含むいくつかのeコマースWebサイトでは、フロントエンドに問題の可能性がまだ多くあります。解決策:小数を整数(倍数)に入れてから、元の倍数(分割倍数)に縮小します
// 0.1 + 0.2(0.1*10 + 0.2*10) / 10 == 0.3 // true
以下は、加算、減算、乗算、および小数の分割の精度の損失をブロックするために書いたオブジェクトです。もちろん、変換された整数は9007199254740992を超えることはできません。
/*** FloatoBJには、追加、減算、乗算、および分割の4つの方法が含まれています。これにより、浮動小数点数の計算が精度を失わないようにします**フローティングポイント数の計算に精度の損失(または丸めエラー)があることを知っています。根本的な原因は、いくつかの数値をバイナリで表現できないこととビット制限を実装できないことです*以下は、小数点以下の小数に対応するバイナリ表現です。たとえば、JavaScriptは64ビットストレージ数値タイプを使用するため、それらを超えるものは破棄されます。失われた部分は、精度が失われる部分です。 ** ** method ***追加 /削除 /増殖** ** **説明*** 0.1 + 0.2 == 0.3000000000000004(0.0000000000000000004 More)* 0.2 + 0.4 == 0.6000000000000001(0.000000000000001)* 19.9* (0.0000000000000000002より少ない)** floatobj.add(0.1、0.2)>> 0.3*floatobj.multiply(19.9、100)>> 1990 **/var floatobj = function(){/** objが整数であるかどうかを判断します*/function isinteger整数に浮かんでいるポイント番号が浮かんで、整数と複数を返します。たとえば、3.14 >> 314、倍数は100* @param floatnum {number} decimal* @return {object}* {times:100、num:314}*/function tointeger(floatnum){var ret = {times:1、num:0} if(isinteger(floatnum){ret.numtun) floatnum + '' var dotpos = strfi.indexof( '。')var len = strfi.substr(dotpos + 1).lengthvar times = math.pow.pow(10、len)var intnum = parseint(floatnum* times + 0.5、10)ret.times = numturn ret.numturn ret./* core精度が失われないようにするために*アイデア:小数を整数(乗数)に拡大し、算術操作を実行してから小数点以下(分割)** @param a {number}操作番号1* @param b {number}操作番号2* @param digits {number} {number} curcy of decimal platess of the necimal as a decimal plass of papp app op paprasy {string}操作タイプ、追加、減算、乗算、および分割(追加/減算/乗算/除算)**/関数操作(a、b、digits、op){var o1 = to1 = var o2 = tointeger(b)var n1 = o1.numvar n2 = o2.numvar t1 = o1.t1.t1.t1.timsvar t1 T2? T1:t2var result = nullswitch(op){case 'add':if(t1 === t2){// 2つの小数点は同じ結果= n1 + n2} else if(t1> t2){// o1 decimal placesがO2Result = n1 + n2 *(t1 / t2) (T2 / T1) + n2} return result / maxcase 'subtract':if(t1 === t2){result = n1 -n2} else if(t1> t2){result = n1 -n2 *(t1 / t2)} (T1 * T2)return resultcase 'divide':result =(n1 / n2) *(t2 / t1)return result}} //追加の4つのインターフェイス、減算、乗算、除算機能add(a、b、digits、 'add')} function wittr(a、b、digit、 'bed opert(a、b、a b、a b、a ben)乗算(a、b、桁){return操作(a、b、桁、 '倍数')} function divition(a、b、digits){return operation(a、b、digits、 'divide')} // exportsreturn {add:add、spract:subtract、multiply:multiply、visid:divide}(divide}();Tofixedの修正は次のとおりです
// tofixed fix function tofixed(num、s){var times = math.pow(10、s)var des = num * times + 0.5des = parseint(des、10) / timesreturn des + ''}