質問

私は金融アプリケーションを書いており、ダブルを使用するか、デシマルを使用するかの決定と絶えず戦います。

すべての数学は、小数点以下5桁以下の数値で機能し、最大100,000以下です。とにかく丸め誤差なしでこれらすべてを倍精度浮動小数点数として表すことができると感じていますが、確かではありません。

私は先に進み、明らかな速度の利点のために小数から2倍に切り替えますが、一日の終わりにはToStringメソッドを使用して取引所に価格を送信し、常に出力することを確認する必要があります私が期待する数。 (89.99000000001の代わりに89.99)

質問:

  1. 速度の利点は、素朴なテストが示すほどの大きさですか? (〜100回)
  2. ToStringからの出力を希望どおりにすることを保証する方法はありますか?これは、私の番号が常に表現可能であるという事実によって保証されていますか?

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

役に立ちましたか?

解決

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

他のヒント

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

正確な表現に関しては、1/10のような正確な小数部分には正確なバイナリ対応物がないため、注意が必要です。ただし、小数点以下5桁の精度しか必要でないことがわかっている場合は、10 ^ 5を掛けた数値を演算するスケーリング算術演算を使用できます。たとえば、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セントの丸め誤差を永遠に追いかけます。

  1. はい;ソフトウェアの計算は実際にはハードウェアの100倍遅いまたは、少なくとも、はるかに遅く、1桁の大きさを与えたり受けたりする100の係数はほぼ正しいです。すべての80386に80387浮動小数点コプロセッサーがあると想定できなかった悪い昔に戻り、バイナリ浮動小数点のソフトウェアシミュレーションもありましたが、それは遅かったです。
  2. いいえ。純粋な2進浮動小数点がすべての10進数を正確に表すことができると考えている場合は、想像上の土地に住んでいます。 2進数は半分、4分の1、8などを組み合わせることができますが、0.01の正確な10進数には5分の1と4分の1の2つの係数が必要なので(1/100 =(1/4)*(1/5)*(1 / 5))と5分の1が2進数で正確な表現を持たないため、すべての10進数値を2進数値で正確に表現することはできません(0.01は正確に表現できない反例ですが、10進数の巨大なクラスを表すためです)正確に表すことはできません)。

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

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

この Speleotrove サイトでの10進数演算と新しいIEEE 754:2008標準に関する情報。

>

longを使用し、10の累乗で乗算します。完了したら、同じ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 が出力されるようになりました!

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

この質問への回答を参照してください。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top