76

VB.NET と SQL Server で従来の会計システムを書き直しています。書き換えを行うために、.NET/SQL プログラマーの新しいチームを招集しました。システムのほとんどは、フロートを使用した金額ですでに完成しています。私がプログラミングした従来のシステム言語には浮動小数点数がなかったので、おそらく 10 進数を使用していたでしょう。

あなたのおすすめは何ですか?

金額に float または decimal データ型を使用する必要がありますか?

どちらの長所と短所は何ですか?

デイリー スクラム指摘された欠点の1 つは、小数点以下 2 桁を超える結果を返す金額を計算するときは注意が必要だということです。金額を小数点以下2桁に四捨五入する必要があるようです。

もう 1 つの短所は、すべての表示と印刷された金額に、小数点以下 2 桁を示すフォーマット ステートメントが必要なことです。これが行われておらず、金額が正しく見えないことが何度かありました。(つまり、10.2 または 10.2546)

プロは、浮動小数のみのアプローチがディスク上で8バイトを占めることです.10進数は9バイト(10進数の12,2)を消費します。

4

24 に答える 24

110

金額にはFloatまたはDecimalデータ型を使用する必要がありますか?

答えは簡単です。決して浮かない。絶対に

フロートはIEEE754に準拠しており、常にバイナリであり、新しい標準IEEE754Rで定義された10進形式のみでした。分数の2進数部分の多くは、正確な10進数表現と等しくなることはありません。

任意の2進数はm/2^nmn正の整数)として記述でき、任意の10進数は。として記述できますm/(2^n*5^n)。2進数には素数がないためfactor 5、すべての2進数は小数で正確に表すことができますが、その逆はできません。

0.3 = 3/(2^1 * 5^1) = 0.3

0.3 = [0.25/0.5] [0.25/0.375] [0.25/3.125] [0.2825/3.125]

          1/4         1/8         1/16          1/32

したがって、指定された10進数よりも大きいまたは小さい数値になります。いつも。

なぜそれが重要なのですか?丸め。

通常の丸めとは、0..4ダウン、5..9アップを意味します。したがって、結果が....または...のどちらであるかは重要です。5セントを意味することはご存知かもしれませんが、コンピューターはそれを認識せず、...を切り捨て(間違っている)および...を切り上げます(右) )。0.0499999999990.05000000000.49990.5000

浮動小数点計算の結果には常に小さな誤差項が含まれていることを考えると、決定は純粋な運です。2進数で10進数を四捨五入して処理したい場合は、絶望的になります。

納得できませんか?あなたはあなたのアカウントシステムですべてが完全に大丈夫だと主張しますか?資産と負債は等しいですか?次に、各エントリの指定されたフォーマット済みの数値をそれぞれ取得し、それらを解析して、独立した10進法で合計します。

それをフォーマットされた合計と比較してください。おっと、何かおかしいですね。

その計算には、「10億分の1ペニー」が発生したことを記録できるように、非常に正確で忠実であることが必要でした(OracleのFLOATを使用しました)。

このエラーには役立ちません。なぜなら、すべての人が自動的にコンピュータの合計が正しいと想定し、実際には誰も独立してチェックすることはないからです。

于 2008-09-15T20:35:25.350 に答える
46

この写真は答えます:

photo1、CO

これは別の状況です。ノーザンプトンの男性は、ゼロドルとゼロセントを支払わなければ家が押収されるという手紙を受け取りました。

photo2、CO

于 2010-10-23T00:04:15.977 に答える
22

まず、What Every Computer Scientist Should Know About Floating Point Arithmeticを読む必要があります。次に、何らかのタイプの固定小数点/任意精度の数値パッケージ (Java BigNum または Python decimal モジュールなど) の使用を実際に検討する必要があります。そうでなければ、あなたは傷の世界に陥るでしょう. 次に、ネイティブの SQL 10 進数型を使用するだけで十分かどうかを判断します。

浮動小数点数と倍精度数は、現在ほとんど廃止されている高速x87 浮動小数点コプロセッサを公開するために存在します。計算の精度を気にする場合、および/またはそれらの制限を完全に補正しない場合は、それらを使用しないでください。

于 2008-09-15T08:04:29.070 に答える
10

追加の警告として、SQL Server と .NET Framework は丸めに異なる既定のアルゴリズムを使用します。Math.Round() の MidPointRounding パラメータを確認してください。.NET フレームワークは既定で銀行家の丸めを使用し、SQL Server は対称アルゴリズムの丸めを使用します。こちらのウィキペディアの記事をご覧ください。

于 2008-09-15T13:21:45.983 に答える
7

会計士に聞いてください!float を使用すると、彼らは眉をひそめます。David Singer が言ったように、精度を気にしない場合にのみfloat を使用してください。お金に関してはいつも反対しますが。

会計ソフトではフロートは認められません。小数点以下 4 桁の decimal を使用します。

于 2008-09-15T05:22:12.970 に答える
6

浮動小数点には予期しない無理数があります。

たとえば、1/3 を 10 進数として格納することはできません。0.3333333333... (など) になります。

浮動小数点数は、実際にはバイナリ値と 2 の累乗の指数として格納されます。

したがって、1.5 は 3 x 2 から -1 (または 3/2) として格納されます。

これらの基数 2 の指数を使用すると、奇数の無理数が作成されます。たとえば、次のようになります。

1.1 を float に変換してから再度変換すると、結果は 1.0999999999989 のようになります。

これは、1.1 の 2 進数表現が実際には 154811237190861 x 2^-47 であり、double よりも大きいためです。

この問題については私のブログで詳しく説明していますが、基本的には、ストレージについては小数の方が適しています。

Microsoft SQL サーバーでは、moneyデータ型があります。これは通常、財務ストレージに最適です。小数点以下4桁まで正確です。

計算の場合、もっと問題があります。不正確さはごくわずかですが、べき乗関数に入れるとすぐに重要になります。

ただし、小数はどのような種類の数学にもあまり適していません。たとえば、小数の累乗はネイティブでサポートされていません。

于 2008-09-15T09:59:38.997 に答える
6

ここで少し背景を....

すべての実数を正確に処理できる数体系はありません。すべてに制限があり、これには標準の IEEE 浮動小数点と符号付き 10 進数の両方が含まれます。IEEE 浮動小数点は、使用されるビットごとにより正確ですが、ここでは問題ではありません。

財務数値は、何世紀にもわたる紙とペンの実践に基づいており、関連する慣習があります。それらはかなり正確ですが、さらに重要なことは、再現可能であることです。さまざまな数値とレートを扱う 2 人の会計士が、同じ数値を出す必要があります。不一致の余地は、詐欺の余地です。

したがって、財務計算では、算数が得意な公認会計士と同じ答えを出すものが正解です。これは 10 進演算であり、IEEE 浮動小数点ではありません。

于 2009-02-09T16:42:15.453 に答える
5

SQLServerの10進型を使用します。

お金フロートを使用しないでください。

お金は小数点以下4桁を使用し、小数点を使用するよりも高速です、丸めに関する明らかな問題とそれほど明白ではない問題があります(この接続の問題を参照してください)。

于 2008-11-03T01:00:38.323 に答える
5

全体をセントで格納する64ビット整数を使用することをお勧めします。

于 2008-11-03T01:08:31.567 に答える
4

浮動小数点数は正確な表現ではありません。たとえば、非常に大きな値と非常に小さな値を追加する場合など、精度の問題が発生する可能性があります。そのため、精度の問題は十分にまれである可能性がありますが、通貨には小数型が推奨されます。

明確にするために、10 進数の 12,2 型はこれらの 14 桁を正確に格納しますが、float は内部的にバイナリ表現を使用するため格納しません。たとえば、0.01 は浮動小数点数で正確に表すことはできません。最も近い表現は、実際には 0.0099999998 です。

于 2008-09-15T04:58:44.367 に答える
4

お金のために Float を使用する唯一の理由は、正確な答えを気にしない場合です。

于 2008-09-15T05:00:04.067 に答える
4

私が開発を手伝った銀行システムでは、システムの「利息発生」部分を担当しました。毎日、私のコードは、その日に残高に発生した (獲得した) 利息を計算しました。

その計算には、「10 億分の 1 のペニー」が発生していることを記録できるように、非常に高い精度と忠実度が必要でした (Oracle の FLOAT を使用しました)。

利息を「資本化」する (つまり、利息を口座に戻す) 場合、金額はペニーに丸められました。勘定残高のデータ型は、小数点以下 2 桁でした。(実際には、多くの小数点以下の桁数で機能する多通貨システムであるため、より複雑でしたが、常にその通貨の「ペニー」に丸めました)。はい-損失と利益の「分数」がありますが、コンピューターの数値が現実化されたとき(お金が支払われたか支払われたか)、それは常に実際のお金の価値でした。

これは、会計士、監査人、テスターを満足させました。

ですから、お客様に確認してください。彼らは、銀行/会計の規則と慣行を教えてくれます。

于 2008-09-15T10:42:26.897 に答える
3

会計システムで知っておくべきもう 1 つのことは、誰もテーブルに直接アクセスできないということです。これは、アカウンティング システムへのすべてのアクセスがストアド プロシージャを介して行われなければならないことを意味します。

これは、 SQL インジェクション攻撃だけでなく、詐欺を防ぐためです。詐欺を犯そうとする内部ユーザーは、データベース テーブルのデータを直接変更することはできません。これは、システムの重要な内部統制です。

不満を持った従業員がデータベースのバックエンドにアクセスして、チェックの書き込みを開始することを本当に望んでいますか? または、承認権限がない場合、承認されていないベンダーに経費を承認したことを隠しますか? 組織全体で、財務データベースのデータに直接アクセスできるのは、データベース管理者 (DBA) とそのバックアップの 2 人だけです。多くの DBA がいる場合、このアクセス権を持つのは 2 人だけにしてください。

これについて言及したのは、プログラマーが会計システムで float を使用していた場合、おそらく彼らは内部統制の概念にまったく慣れておらず、プログラミング作業でそれらを考慮していなかったからです。

于 2009-02-09T16:55:22.927 に答える
3

小数を使用するよりも、単純な古い整数 (または何らかの bigint) を使用する方がさらに優れています。このようにして、常に可能な限り最高の精度を得ることができますが、精度を指定することができます。たとえば、数字100は を意味する1.00場合があり、次のようにフォーマットされます。

int cents = num % 100;
int dollars = (num - cents) / 100;
printf("%d.%02d", dollars, cents);

精度を上げたい場合は、100 を 10 ^ n のように大きな値に変更できます。ここで、n は小数点以下の桁数です。

于 2008-09-16T09:58:31.783 に答える
2

金銭的な値を格納するために SQL の money 型を使用していました。最近、私は多くのオンライン決済システムを使用する必要がありましたが、その中には通貨の値を格納するために整数を使用しているものがあることに気付きました。私の現在および新しいプロジェクトでは、整数の使用を開始しましたが、このソリューションにかなり満足しています。

于 2009-02-09T14:09:47.690 に答える
2

.NET の Money 型のようなものはいつでも記述できます。

A Money type for the CLR という記事をご覧ください。私の意見では、著者は素晴らしい仕事をしました。

于 2008-09-21T06:12:24.020 に答える
2

100 個の分数 n/100 (n は 0 <= n かつ n < 100 の自然数) のうち、浮動小数点数として表現できるのは 4 つだけです。この C プログラムの出力を見てください。

#include <stdio.h>

int main()
{
    printf("Mapping 100 numbers between 0 and 1 ");
    printf("to their hexadecimal exponential form (HEF).\n");
    printf("Most of them do not equal their HEFs. That means ");
    printf("that their representations as floats ");
    printf("differ from their actual values.\n");
    double f = 0.01;
    int i;
    for (i = 0; i < 100; i++) {
        printf("%1.2f -> %a\n",f*i,f*i);
    }
    printf("Printing 128 'float-compatible' numbers ");
    printf("together with their HEFs for comparison.\n");
    f = 0x1p-7; // ==0.0071825
    for (i = 0; i < 0x80; i++) {
        printf("%1.7f -> %a\n",f*i,f*i);
    }
    return 0;
}
于 2010-10-21T20:19:27.063 に答える
1

通貨値には、何らかの形式の固定小数点表現を使用することをお勧めします。また、銀行家の丸め(「半分から偶数への丸め」とも呼ばれます)を調査することもできます。通常の「切り上げ」方式に存在するバイアスを回避します。

于 2008-09-15T13:19:10.670 に答える
1

金額を格納するために money-data 型を使用することを検討しましたか?

10 進数がもう 1 バイトを占めるという短所については、気にしないでください。100 万行の場合、あと 1 MB しか使用されず、最近のストレージは非常に安価です。

于 2008-09-15T04:59:07.877 に答える
1

何をするにしても、丸め誤差に注意する必要があります。表示よりも高い精度で計算します。

于 2008-09-15T04:59:18.640 に答える
0

常に小数を使用します。浮動小数点は、丸めの問題により不正確な値を提供します。

于 2008-09-15T12:50:46.510 に答える
0

これは、いつ float と decimal を使用するかを説明する優れた記事です。Float は近似値を格納し、Decimal は正確な値を格納します。

要約すると、お金のような正確な値には 10 進数を使用し、科学的測定値などの近似値には浮動小数点数を使用する必要があります。

float と decimal の両方が精度を失う可能性があることを示す興味深い例を次に示します。整数ではない数値を加算してから同じ数値 float を減算すると精度が失われますが、10 進数はそうではありません。

    DECLARE @Float1 float, @Float2 float, @Float3 float, @Float4 float; 
    SET @Float1 = 54; 
    SET @Float2 = 3.1; 
    SET @Float3 = 0 + @Float1 + @Float2; 
    SELECT @Float3 - @Float1 - @Float2 AS "Should be 0";

Should be 0 
---------------------- 
1.13797860024079E-15

非整数を掛けて同じ数で除算すると、小数は精度を失いますが、浮動小数点はそうではありません。

DECLARE @Fixed1 decimal(8,4), @Fixed2 decimal(8,4), @Fixed3 decimal(8,4); 
SET @Fixed1 = 54; 
SET @Fixed2 = 0.03; 
SET @Fixed3 = 1 * @Fixed1 / @Fixed2; 
SELECT @Fixed3 / @Fixed1 * @Fixed2 AS "Should be 1";

Should be 1 
--------------------------------------- 
0.99999999999999900
于 2010-10-23T01:58:43.530 に答える
0

浮動小数点数は、基数の負の倍数の合計である数値のみを表すことができます。もちろん、2 進浮動小数点の場合は 2 です。

2 進浮動小数点で正確に表現できる小数は、0、0.25、0.5、および 0.75 の 4 つだけです。0.3333... が 10 進数の 1/3 の近似値であるのと同じように、他のすべては近似値です。

浮動小数点は、結果のスケールが重要な計算に適しています。小数点以下の桁数まで正確にしようとしている場合、これは悪い選択です。

于 2008-09-15T12:55:35.377 に答える
0

会計士は丸め方を管理したいと思うでしょう。float を使用すると、通常は型ステートメントを使用して常に丸められることになりますが、これは望ましいFORMAT()方法ではありません (代わりにfloor/を使用してください)。ceiling

float または real の代わりに使用する必要がある通貨データ型 ( money、 ) があります。smallmoney10 進数 (12,2) を格納すると、丸めが省略されますが、中間ステップでも丸めが省略されます。これは、金融アプリケーションではまったく必要ありません。

于 2008-09-15T12:48:31.413 に答える