私は、小数点を使用するのではなく、倍を使用するという決断と常に戦う金融アプリケーションを作成しています。
私の数学はすべて、小数点以下5桁以下の数値で機能し、最大100,000以下です。これらはすべて、丸め誤差なしにダブルとして表現できると感じていますが、確信が持てませんでした。
私は先に進み、明らかな速度の利点のために小数から倍に切り替えますが、1日の終わりに、ToStringメソッドを使用して価格を取引所に送信し、常に数値を出力することを確認する必要があります。期待する。 (89.99000000001ではなく89.99)
質問:
更新:アプリを実行する前に約100億件の価格更新を処理する必要があります。保護上の理由から、現時点では10進数で実装していますが、オンにするだけで最大3時間かかります。 。ダブルスでそれを行う安全な方法はありますか?
ここには2つの分離可能な問題があります。 1つは、必要なすべてのビットを保持するのに十分な精度がdoubleにあるかどうかであり、もう1つは、数値を正確に表現できる場所です。
正確な表現については、1/10のような正確な小数部には正確な2進数の対応物がないため、注意が必要です。ただし、小数点以下5桁の精度しか必要ないことがわかっている場合は、10- ^ 5を掛けた数値を演算するscaled演算を使用できます。したがって、たとえば、23.7205を正確に表す場合は、2372050として表します。
十分な精度があるかどうかを見てみましょう。倍精度では53ビットの精度が得られます。これは15桁以上の10進数の精度に相当します。したがって、これにより、小数点の後ろに5桁、小数点の前に10桁を使用できます。これは、アプリケーションにとって十分なようです。
私はこのCコードを.hファイルに入れます:
typedef double scaled_int;
#define SCALE_FACTOR 1.0e5 /* number of digits needed after decimal point */
static inline scaled_int adds(scaled_int x, scaled_int y) { return x + y; }
static inline scaled_int muls(scaled_int x, scaled_int y) { return x * y / SCALE_FACTOR; }
static inline scaled_int scaled_of_int(int x) { return (scaled_int) x * SCALE_FACTOR; }
static inline int intpart_of_scaled(scaled_int x) { return floor(x / SCALE_FACTOR); }
static inline int fraction_of_scaled(scaled_int x) { return x - SCALE_FACTOR * intpart_of_scaled(x); }
void fprint_scaled(FILE *out, scaled_int x) {
fprintf(out, "%d.%05d", intpart_of_scaled(x), fraction_of_scaled(x));
}
おそらくいくつかの荒い箇所がありますが、それであなたは始めるのに十分でしょう。
加算のオーバーヘッドはなく、乗算または除算の倍のコスト。
C99にアクセスできる場合は、int64_t
64ビット整数型を使用して、スケーリングされた整数演算を試すこともできます。どちらが速いかは、ハードウェアプラットフォームによって異なります。
財務計算には常にDecimalを使用してください。そうしないと、1セントの丸め誤差を永遠に追跡することになります。
したがって、ToString()を呼び出す前に丸めを処理できるかどうか、または結果が文字列に変換されるときに結果の丸めを処理する他のメカニズムを見つける必要があるかどうかを決定する必要があります。または、10進数演算は引き続き正確であるため、引き続き使用できます。ハードウェアで新しいIEEE 754 10進数演算をサポートするマシンがリリースされると、より高速になります。
必須の相互参照: すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと 。これは、考えられる多くのURLの1つです。
10進数演算と新しいIEEE 754:2008標準に関する情報は、この Speleotrove サイトにあります。
Longを使用し、10の累乗を乗算します。完了したら、同じ10の累乗で除算します。
小数は常に財務計算に使用する必要があります。数字のサイズは重要ではありません。
説明する最も簡単な方法は、いくつかのC#コードを使用することです。
double one = 3.05;
double two = 0.05;
System.Console.WriteLine((one + two) == 3.1);
このコードは、3.1が3.1と等しい場合でもFalseを出力します...
同じことですが、10進数を使用します。
decimal one = 3.05m;
decimal two = 0.05m;
System.Console.WriteLine((one + two) == 3.1m);
これで出力されますTrue!
この種の問題を回避したい場合は、小数を使用することをお勧めします。
この質問 に対する私の回答を紹介します。
長い値を使用し、追跡する必要がある最小量を保存して、それに応じて値を表示します。