1

さて、私たちは皆、次のような浮動小数点数の問題を知っています:

0.23 - 1 + 1 = 0.22999999999999998

また、JavaScript では、他の言語とは異なり、すべての数値が実際には浮動小数点であり、int/decimal がないため、この問題を処理する BigDecimal などのあらゆる種類のライブラリと回避策があります。これについては、ここで説明するのが最適です。

浮動小数点数をサポートする「数値スピナー」コントロールを作成していましたが、明らかに、ユーザーが「上」をクリックしてから「下」をクリックして、最初とは異なる数値を取得したくないので、回避策 - 一種の「addPrecise」メソッド。

私の考えは次のとおりでした。

  1. 加算しようとしている 2 つの数値を取り、それらの「精度」、つまり小数点以下の桁数を計算します。
  2. 2 つの数値を float として追加します
  3. toFixed()2 つの最大精度で結果に適用する

例えば:

float #1: 1.23
float #2: -1

それらを追加すると通常は結果になります0.22999999999999998が、小数点以下の最大桁数、つまり#1の2桁toFixed(2)を取得して適用すると、0.23希望どおりになります。

次のコードでこれを行いましたが、満足していません。

function addPrecise(f1, f2){
    var floatRegex = /[^\d\-]/;
    var f1p =  floatRegex.exec(f1.toString()) ? f1.toString().split(floatRegex.exec(f1.toString()))[1].length : 0;
    var f2p =  floatRegex.exec(f2.toString()) ? f2.toString().split(floatRegex.exec(f2.toString()))[1].length : 0;
    var precision = Math.max(f1p,f2p);
    return parseFloat((parseFloat(f1) + parseFloat(f2)).toFixed(precision));
}

(他のロケールではピリオドではなくコンマである可能性があるため、「浮動小数点」を見つけるために正規表現を使用していることは注目に値します。また、Int を取得した可能性も考慮しています (ポイントなし) ) その場合、精度は 0 です。)

これを行うためのよりクリーン/シンプル/より良い方法はありますか?

編集:また、10 進数の桁数を抽出する信頼できる方法を見つけることも問題の一部であることを指摘したいと思います。私はそこに私の方法について確信が持てません。

4

1 に答える 1

1

この問題の適切な解決策は次のとおりです。

  1. 小数点の後に必要な桁数 (たとえばd ) を決定します。
  2. ユーザーからの入力を読み取り、10 dでスケーリングされた整数に変換します。
  3. 整数を使用してすべての演算を行います。
  4. ユーザーの値を表示する場合は、値を 10 dで割って表示します。

詳細:

  1. すべての作業がユーザー入力データの完全な単位である場合、小数点の後に必要な桁数dは、ユーザーから受け入れられる桁数と同じです。(たとえば、ステップ サイズの分数で何らかの演算を行う場合は、さらに多くの桁数が必要になる可能性があります。)
  2. ユーザーが入力を入力すると、スケーリングされた整数に変換される必要があります。ユーザーは文字列 (浮動小数点数ではありません。ユーザーが入力したときは単なる文字列です) を入力することに注意してください。文字列は数値 (数値を表す文字) でなければなりません。この入力を処理する 1 つの方法は、ライブラリ ルーチンを呼び出してこの数値を浮動小数点数に変換し、次に 10 dを掛けることです。、次に浮動小数点の結果を最も近い整数に丸めます (浮動小数点の丸め誤差を補正するため)。妥当なサイズの数値の場合、これは常に目的の結果を正確に生成します。浮動小数点の丸め誤差は問題になりません。(大きすぎるユーザー入力は拒否する必要があります。) この入力を処理する別の方法は、数値をスケーリングされた整数に直接変換する独自のコードを記述し、浮動小数点を完全に回避することです。
  3. 加算、乗算、および減算のみが使用され (たとえば、ステップ サイズにステップ数を掛けて前の値に加算する)、整数範囲を超えない限り、すべての演算は正確です。丸め誤差はありません。除算を使用する場合は、このアプローチを再検討する必要があります。
  4. 入力の読み取りと同様に、出力の表示は、浮動小数点およびライブラリ ルーチンを使用するか、独自のコードを記述して直接変換することによって実行できます。浮動小数点を使用するには、整数を浮動小数点に変換し、10 dで割り、ライブラリ ルーチンを使用して、小数点以下d桁を超えないようにフォーマットします。(ライブラリ ルーチンでデフォルトの書式変換を使用すると、 d桁を超える数が表示される場合があります。d桁のみが表示され、dがかなり小さい数値である場合、書式設定中に発生する浮動小数点の丸めエラーは表示されません。)

上記のすべてを浮動小数点のみを使用して実装することは可能ですが、合理的な範囲内で算術演算が完全に整数 (または浮動小数点形式で正確に表現できるその他の値) を使用するように注意する必要があります。

于 2013-08-14T13:21:45.777 に答える