小数列にお金を保存する-精度とスケールは?
-
03-07-2019 - |
質問
データベースに金額の値を格納するために小数列を使用していますが、今日はどの精度とスケールを使用するのか疑問に思いました。
固定幅のchar列の方が効率的であると思われるため、10進数列についても同じことが当てはまると考えていました。それですか?
そして、どの精度とスケールを使用すべきですか?私は24/8の精度を考えていました。やりすぎではありませんか?
これは私がやることにしたことです:
- 変換テーブル(該当する場合)をトランザクションテーブル自体にfloatとして保存します
- 通貨を口座テーブルに保存する
- 取引額は
DECIMAL(19,4)
になります
- コンバージョン率を使用するすべての計算はアプリケーションによって処理されるため、丸めの問題を管理します
参照用であるため、コンバージョン率の浮動小数点数が問題になるとは思いません。とにかく小数にキャストします。
貴重なご意見をありがとうございました。
解決
万能型を探しているなら、 DECIMAL(19、4)
が一般的な選択肢であることをお勧めします(簡単なGoogleがこれを裏付けています)。これは古いVBA / Access / Jet Currencyデータ型に由来し、言語の最初の固定小数点10進数型であると思います。 Decimal
は、VB6 / VBA6 / Jet 4.0では「バージョン1.0」スタイル(つまり、完全には実装されていません)でのみ提供されていました。
固定小数点の10進数値の storage の経験則では、丸めを許可するために実際に必要な小数点以下の桁を少なくとも1つ格納します。フロントエンドの古い Currency
タイプをバックエンドの DECIMAL(19、4)
タイプにマッピングする理由の1つは、 Currency
DECIMAL(p、s)
は切り捨てにより丸められますが、銀行家は本質的に丸めを示しました。
DECIMAL
のストレージに余分な小数点があるため、ベンダーのデフォルトを使用するのではなく、カスタムの丸めアルゴリズムを実装できます(そして、銀行家の丸めは、控えめに言っても、デザイナーが.5で終わる値はゼロから切り捨てます)。
はい、 DECIMAL(24、8)
は私にはやり過ぎのように聞こえます。ほとんどの通貨は、小数点以下4桁または5桁で表示されます。 8(またはそれ以上)の小数スケールが必要な状況を知っていますが、これは「通常の」金額(小数4桁など)が比例しており、小数精度を意味しますそれに応じて減らす必要があります(このような状況では浮動小数点型も考慮してください)。そして、最近では24の小数精度を要求するほど多くのお金がありません:)
ただし、万能のアプローチではなく、いくつかの研究が適切である場合があります。適用可能な会計規則については、設計者またはドメインの専門家に問い合わせてください。GAAP、EUなど。小数点以下5桁に丸めるための明示的な規則があるEU州内移転を漠然と思い出すため、 DECIMAL(p、6)
を保存します。会計士は通常、小数点以下4桁を好むようです。
PS SQL Serverの MONEY
データ型は、移植性などの考慮事項の中でも特に、丸めの際に重大な問題があるため、避けてください。アーロンバートランドのブログ。
Microsoftと言語設計者は、ハードウェア設計者が選択したため、銀行家の丸めを選択しました[引用?]。たとえば、米国電気電子技術者協会(IEEE)標準に定められています。そして、数学者がそれを好むので、ハードウェア設計者はそれを選びました。 ウィキペディアをご覧ください。言い換えると、1906年版の「確率とエラーの理論」では、この「コンピューターのルール」(「コンピューター」は計算を実行する人間を意味します)と呼ばれています。
他のヒント
最近、複数の通貨で値を処理し、それらの間で変換する必要があるシステムを実装し、いくつかの困難な方法を見つけました。
お金に浮動小数点数を使用しない
浮動小数点演算は不正確さをもたらしますが、それは何かを台無しにするまで気付かないかもしれません。すべての値は整数または固定小数点型として保存する必要があります。固定小数点型を使用する場合は、その型が内部で何を行うかを正確に理解してください(つまり、内部で整数または浮動小数点を使用します)タイプ)。
計算または変換を行う必要がある場合:
- 値を浮動小数点に変換する
- 新しい値を計算
- 数値を四捨五入し、整数に戻す
ステップ3で浮動小数点数を整数に戻す場合、単にキャストするのではなく、数学関数を使用して最初に丸めます。これは通常 round
になりますが、特別な場合には floor
または ceil
になります。違いを知り、慎重に選択してください。
数値のタイプを値と一緒に保存します
これは、1つの通貨のみを処理する場合にはそれほど重要ではないかもしれませんが、複数の通貨を処理する上で重要でした。 USD、GBP、JPY、EURなどの通貨に3文字のコードを使用しました。
状況によっては、以下を保存することも役立ちます。
- 数値が税の前か後か(および税率はどうだったか)
- 数値が変換の結果であるかどうか(および変換元)
扱っている数字の精度の限界を知る
実際の値については、通貨の最小単位と同じくらい正確にする必要があります。これは、セント、ペニー、円、フェンなどより小さい値がないことを意味します。理由もなく、それよりも高い精度で値を保存しないでください。
内部的に、より小さな値を扱うことを選択できます。この場合、それは異なる種類の通貨値です。どちらがどれであるかをコードが把握しており、それらが混同しないようにしてください。ここでも浮動小数点値を使用しないでください。
これらのルールをすべて追加して、次のルールを決定しました。実行中のコードでは、通貨は最小単位の整数を使用して保存されます。
class Currency {
String code; // eg "USD"
int value; // eg 2500
boolean converted;
}
class Price {
Currency grossValue;
Currency netValue;
Tax taxRate;
}
データベースでは、値は次の形式の文字列として保存されます。
USD:2500
25.00ドルの値を保存します。通貨を処理するコードがデータベースレイヤー自体にある必要がないため、すべての値を最初にメモリに変換できるため、これを行うことができました。他の状況が他のソリューションに役立つことは間違いありません。
そして、以前に明確にしなかった場合、フロートを使用しないでください
MySQLでお金を処理する場合、お金の値の精度がわかっている場合はDECIMAL(13,2)を使用し、すぐに十分な近似値が必要な場合はDOUBLEを使用します。 したがって、アプリケーションが最大1兆ドル(またはユーロまたはポンド)までの金額を処理する必要がある場合、これは機能するはずです:
DECIMAL(13, 2)
または、 GAAP に準拠する必要がある場合は、次を使用します。
DECIMAL(13, 4)
小数点以下4桁は、世界最小の通貨サブユニットを格納する精度を提供します。マイクロペイメント(ナノペイメント?!)の精度が必要な場合は、さらに下げることができます。
DBMS固有のマネータイプよりも DECIMAL
の方が好きです。そのようなロジックをアプリケーションIMOに保持する方が安全です。同じ行に沿った別のアプローチは、単純に[long]整数を使用し、アプリケーションレベルで人間の可読性(¤ =通貨記号)のために¤ unit.subunitにフォーマットすることです。
SQL Serverのmoneyデータ型の小数点以下は4桁です。
SQL Server 2000 Books Onlineから:
通貨データは、正または負の金額を表します。 Microsoftで® SQL Server™ 2000年、金銭データはmoneyおよびsmallmoneyデータタイプを使用して保存されます。通貨データは、小数点以下4桁の精度で保存できます。 moneyデータ型を使用して、-922,337,203,685,477.5808から+922,337,203,685,477.5807の範囲の値を格納します(値を格納するには8バイトが必要です)。 smallmoneyデータ型を使用して、-214,748.3648から214,748.3647の範囲の値を格納します(値を格納するには4バイトが必要です)。小数点以下の桁数を増やす必要がある場合は、代わりに小数点データ型を使用してください。
場合によっては1セント未満に移動する必要があり、非常に大きな悪魔を使用する国際通貨があります。たとえば、トランザクションごとに0.088セントを顧客に請求できます。 Oracleデータベースでは、列はNUMBER(20,4)として定義されています
DBで何らかの種類の算術演算(請求レートの乗算など)を行う場合は、おそらく、同じ理由で、ここにいる人々が提案しているよりもはるかに高い精度が必要になります。アプリケーションコードで倍精度浮動小数点値未満のものを使用することは決してありません。
IBM Informix Dynamic Serverを使用している場合、MONEタイプはDECIMALまたはNUMERICタイプのマイナーバリアントです。常に固定小数点型です(一方、DECIMALは浮動小数点型にすることができます)。 1から32までのスケール、および0から32までの精度を指定できます(デフォルトはスケール16、精度2)。したがって、保存する必要があるものに応じて、DECIMAL(16,2)を使用することがあります-依然として米国連邦赤字を保持するのに十分な大きさで、最も近いセントまで-または、より小さい範囲、または小数点以下の桁を使用します。
私は、あなたまたはあなたのクライアントの要件の大部分について、使用する精度とスケールを決定すべきだと思います。たとえば、私が取り組んでいるeコマースWebサイトでは、GBPのみでお金を扱うため、Decimal(6、2)に保つ必要があります。
ここでは遅い回答ですが、使用しました
DECIMAL(13,2)
99,999,999,999.99まで許可する必要があると思います。