53

私は、2 倍を使用するか 10 進数を使用するかの決定と常に戦っている金融アプリケーションを作成しています。

私の数学はすべて、小数点以下 5 桁までで、100,000 以下の数値で機能します。とにかく丸め誤差なしでこれらすべてを double として表すことができると感じていますが、確信が持てませんでした。

10 進数から 2 進数に切り替えて明らかに速度を向上させますが、結局のところ、ToString メソッドを使用して価格を取引所に送信し、常に値を出力するようにする必要があります。予想。(89.99000000001 の代わりに 89.99)

質問:

  1. 単純なテストが示すように、速度の利点は本当に大きいのでしょうか? (~100回)
  2. ToString からの出力が私が望むものであることを保証する方法はありますか? これは、私の番号が常に表現可能であるという事実によって保証されますか?

更新: アプリを実行する前に ~ 100 億の価格更新を処理する必要があり、明らかな保護上の理由から現在 10 進数で実装していますが、電源を入れるだけで ~3 時間かかります。 . ダブルスで安全に行う方法はありますか?

4

7 に答える 7

84
  1. 浮動小数点演算は、ハードウェアで直接サポートされているため、ほとんどの場合、大幅に高速になります。これまでのところ、10 進演算をサポートする広く使用されているハードウェアはほとんどありません (ただし、これは変更されています。コメントを参照してください)。
  2. 金融アプリケーションでは常に10 進数を使用する必要があります。金融アプリケーションで浮動小数点を使用することから生じる恐ろしい話の数は無限にあります。Google 検索でそのような例を多数見つけることができるはずです。
  3. 10 進演算は浮動小数点演算よりも大幅に遅くなる可能性がありますが、10 進データの処理にかなりの時間を費やさない限り、プログラムへの影響は無視できる可能性があります。いつものように、違いを心配する前に適切なプロファイリングを行ってください。
于 2008-11-30T23:46:38.520 に答える
24

ここには 2 つの分離可能な問題があります。1 つは double が必要なすべてのビットを保持するのに十分な精度を持っているかどうか、もう 1 つは数値を正確に表現できるかどうかです。

正確な表現に関しては、1/10 のような正確な 10 進数には正確な 2 進法がないため、注意が必要です。ただし、小数点以下 5 桁の精度しか必要ないことがわかっている場合は、数値に 10^5 を掛けた演算を行うスケーリング演算を使用できます。たとえば、23.7205 を正確に表したい場合は、2372050 と表します。

十分な精度があるかどうか見てみましょう。倍精度では 53 ビットの精度が得られます。これは、10 進数で 15 桁以上の精度に相当します。したがって、これにより、小数点の後に 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));
}

おそらくいくつかの荒い点がありますが、それはあなたが始めるのに十分なはずです.

加算のオーバーヘッドがなく、乗算または除算のコストが 2 倍になります。

C99 にアクセスできる場合は、int64_t64 ビット整数型を使用してスケーリングされた整数演算を試すこともできます。どちらが速いかは、ハードウェア プラットフォームによって異なります。

于 2008-12-01T01:24:22.677 に答える
18

財務計算には常に Decimal を使用してください。

于 2008-11-30T23:59:08.947 に答える
13
  1. はい; ソフトウェア演算は、ハードウェアよりも 100 倍遅いです。または、少なくとも、それははるかに遅く、100 の係数は、大きさのオーダーを与えるか取るか、ほぼ正しいです。すべての 80386 に 80387 浮動小数点コプロセッサが搭載されているとは想定できなかった昔は、バイナリ浮動小数点のソフトウェア シミュレーションもありましたが、これは遅かったです。
  2. いいえ; 純粋な 2 進浮動小数点がすべての 10 進数を正確に表すことができると考える場合、あなたは空想の世界に住んでいます。2 進数は 2 分の 1、4 分の 1、8 分の 1 などを組み合わせることができますが、正確な 0.01 の 10 進数には 5 分の 1 の因数が 2 つと 4 分の 1 の因数が 1 つ必要なので (1/100 = (1/4)*(1/5)*(1 /5)) また、5 分の 1 は 2 進数で正確に表現できないため、すべての 10 進数値を 2 進数値で正確に表現することはできません (0.01 は正確に表現できない反例ですが、10 進数の巨大なクラスを表すためです。正確に表すことはできません)。

そのため、ToString() を呼び出す前に丸めを処理できるかどうか、または結果が文字列に変換されるときに結果の丸めを処理する他のメカニズムを見つける必要があるかどうかを決定する必要があります。または、10 進演算は正確なままであり、ハードウェアで新しい IEEE 754 10 進演算をサポートするマシンがリリースされると、より高速になるため、引き続き使用できます。

必須の相互参照:すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと. これは、考えられる多くの URL の 1 つです。

10 進演算と新しい IEEE 754:2008 標準に関する情報は、このSpeleotroveサイトにあります。

于 2008-12-01T00:59:06.877 に答える
8

long を使用して 10 の累乗を掛けるだけです。完了したら、同じ 10 の累乗で割ります。

于 2009-05-03T15:20:04.440 に答える
6

財務計算には常に小数を使用する必要があります。数字の大きさは重要ではありません。

私が説明する最も簡単な方法は、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 !が出力されます。

この種の問題を回避したい場合は、小数を使用することをお勧めします。

于 2008-12-01T01:13:03.370 に答える
1

この質問に対する私の回答を参照してください。

long を使用し、追跡する必要がある最小量を保存し、それに応じて値を表示します。

于 2008-12-17T00:31:58.280 に答える