すべての通貨(ドル、ユーロ、ポンドとは異なる通貨も含む)で機能する単一のデータ表現はありますか?


12

ある通貨で金額を表すために使用するライブラリに関する多くの質問を見つけることができます。そして、なぜ通貨をIEEE 754浮動小数点数として保存すべきではないのかという古くからの問題についてです。しかし、私はこれ以上何も見つけられないようです。確かに、実際の使用での通貨についてもっと知る必要があります。物理的な使用で表現するために知っておく必要があるものに特に興味があります(たとえば、ドルでは、0.01未満の精度はなく、整数のセントとして表現できます)。

しかし、あなたが知っている唯一の通貨が西洋の人気通貨(ドル、ユーロ、ポンドなど)である場合、プログラムがどれほど汎用性があるかを推測するのは困難です。純粋にプログラム的な観点で関連する知識は他に何ですか?私は変換のトピックについて心配していません。

特に、ある通貨で値を保存して印刷できるようにするには、何を知る必要がありますか?


2
すべてのプログラマーが通貨額を操作する業界で働くわけではありません。
whatsisname

4
はいもちろん。しかし、それはほとんど何についてでも言える。この質問が役に立つと思うのは、通貨を扱っている人だと思います。
キャット

5
NYCの銀行やその他の金融サービス会社で多くの開発作業を行ってきました。そして、あなたの質問に対する「閉じた形式」の答えがないことをほぼ保証できます。「どれくらいの数学を知る必要があるのか​​」と尋ねることもできます。たとえば、1990年代に株価は8分の1と256分の1から10進数になり、多くの再プログラミングが必要になりました。それが起こると誰が推測できたでしょうか?アプリケーションがサポートしているビジネスと、それらのビジネスニーズをサポートするためにデータ(この場合は通貨)を最適に表現する方法を理解する必要があります。
ジョンフォーコシュ

4
私の0.02:価格は一つです。通貨は別です。
マチャド

3
ああ、すべての通貨に共通の分母があるはずだと思いました。しかし、そうではないかもしれません。ペニースターリングは現在1ポンドの1⁄100ですが、1ポンドの1⁄240でした。したがって、1/240の部門があるだけでなく、切り替え日があり、場合によってはまだ切り替えられていない古いペンスの為替レートがあります。en.wikipedia.org/wiki/Penny_sterling カウリーシェルを始めないでください! en.wikipedia.org/wiki/Shell_moneyまたはお金が現実になるには信念が必要であるという事実:en.wikipedia.org/wiki/Money StackExchangeにうまく適合しない場合でも素晴らしい質問です!
グレンペターソン

回答:


24

たとえば、ドルでは、0.01ドル未満の精度はありません。

まあ、本当に? ここに画像の説明を入力してください

IEEE 754浮動小数点数として通貨を保存しない理由の古い問題。

ここに画像の説明を入力してください

IEEE 754 浮動小数点数にインチを自由に格納してください。彼らはあなたが期待する方法を正確に保存します。

ルーラーを1インチの小数に分割する目盛りを使用して保存できるIEEE 754浮動小数点数の金額を自由に保存してください。

どうして?なぜなら、IEEE 754を使用するとき、それが保存方法だからです。

インチについてのことは、それらが半分に分割されていることです。ほとんどの種類の通貨に関することは、通貨が10分の1に分割されていることです(一部の通貨はそうではありませんが、集中し続けましょう)。

ほとんどのプログラミング言語では、IEEE 754浮動小数点数への入出力は10進数で表現されることを除いて、この違いはそれほど複雑ではありません。それらは小数で保存されないため、これは非常に奇妙です。

このため、コンピュータに保存するように要求したときに、ビットがどのように奇妙なことをする見ることができません0.1。あなたはそれに対して数学をするときだけ奇妙さを見る、そしてそれは奇妙なエラーを持っている。

以下からのジョシュブロッホの効果的なJavaの

System.out.println(1.03 - .42);

生産する 0.6100000000000001

これについて最も言っているのは1、右側に座っている方法ではありません。それを得るために使用しなければならなかったのは奇妙な数字です。最も一般的な例0.1を使用するのではなく、問題を示し、それを隠す丸めを回避する例を使用する必要があります。

たとえば、なぜこれが機能するのですか?

System.out.println(.01 - .02);

生産する -0.01

幸運になったからです。

私は時々「幸運」になるので、診断が難しい問題は嫌いです。

IEEE 754では、0.1を正確に格納することはできません。しかし、0.1を保存するように要求してから印刷するように要求すると、0.1が表示され、すべてが正常であると思われます。大丈夫ではありませんが、0.1に戻すのに丸めているため、それを見ることができません。

一部の人々は、これらの不一致を丸め誤差と呼ぶことにより、他の人々と一体を混同しています。いいえ、これらは丸め誤差ではありません。丸めは、本来の目的を果たし、小数ではないものを小数に変換して、画面に印刷できるようにすることです。

ただし、これにより、数値の表示方法と保存方法の不一致が隠されます。丸めが発生してもエラーは発生しませんでした。正確に保存できないシステムに数値を入力することを決定し、保存されていないときに正確に保存されていると仮定したときに発生しました。

πが計算機に正確に保存されることを期待する人はいません。そのため、問題は精度についてでさえありません。予想される精度についてです。コンピューター0.1は、電卓と同じように10分の1を表示するため、電卓と同じように完全に1/10を保存することが期待されます。彼らはしません。コンピュータは高価なので、これは驚くべきことです。

不一致を示しましょう:

ここに画像の説明を入力してください

1/2と0.5が完全に揃っていることに注意してください。しかし、0.1はちょうど揃っていません。2で除算し続ければ、確実に近づくことができますが、決して正確にヒットすることはありません。そして、2で除算するたびにますます多くのビットが必要になります。したがって、2で除算するシステムで0.1を表すには、無限のビット数が必要です。私のハードディスクはそれほど大きくありません。

したがって、IEEE 754はビットが足りなくなると試行を停止します。家族の写真を撮るためにハードドライブにスペースが必要なので、これは素晴らしいことです。いやいや。家族の写真。:P

とにかく、入力するものと表示されるものは小数(右側)ですが、格納するのは2 進数(左側)です。時々、それらはまったく同じです。時々そうではありません。単にそうではないのに同じであるように見えることもあります。それが丸めです。

特に、ある通貨で値を保存して印刷できるようにするには、何を知る必要がありますか?

あなたが私の小数ベースのお金を処理している場合は、フロートまたはダブルを使用しないでください。

10分の1ペニーのようなものが関与しないと確信している場合は、ペニーを保管するだけです。そうでない場合は、この通貨の最小単位が何であるかを把握し、それを使用します。できない場合は、BigDecimalのようなものを使用します。

私の純資産はおそらく64ビット整数に常にうまく収まりますが、BigIntegerのようなものはそれより大きいプロジェクトでうまく機能します。ネイティブ型よりも遅いだけです。

保存方法を理解することは、問題の半分にすぎません。また、それを表示できる必要があります。優れた設計は、これら2つのことを分離します。ここでフロートを使用する際の本当の問題は、これらの2つのことが一緒になってしまうことです。

ここに画像の説明を入力してください


6
IEEE 754がお金のために機能しない理由について、私は本当に別の説明を探していませんでした。OPで、これは他の場所でよく説明されていると述べました。同様に、「物理的使用法」という用語を使用した理由があります。つまり、ガソリン価格、証券取引所の価値などは任意の精度を持っているかもしれませんが、物理的なお金(および膨大な数のユーザートランザクション)は数百の場所を超えてはいけません物理的なお金)。私が疑問に思った情報の1つは、小数点以下の桁数が増えた通貨が存在するかどうかでした。
キャット

3
浮動小数点の「奇妙さ」は、ハーフネス対1/10だけに限定されません。名前の「浮動小数点」の側面も予期しない結果を引き起こすことがあります。
whatsisname

6
10進数化前の英国の通貨はポンド、シリング、ペンス(£sd)で、£1 == 20s、1s = 12dでしたので£1 = 240dで1d = 0.0046666666666 .. ユーロに参加する前に、イタリアリラは2346.4(2001年)を超えて米ドルに達したため、給与や住宅価格などが単精度浮動小数点数の上限に達し、経済指標が倍の上限に達したことがあります。
スティーブバーンズ

2
私はただ、通貨は一つのことであり、価格は別のことだと主張/指摘します。価格は0.01ドル以上の精度を持つことができますが、その精度で効果的に支払うことはできません。
マチャド

1
また、家族の写真。Pft。:)
マチャド

10

ある通貨で金額を表すために使用するライブラリに関する多くの質問を見つけることができます。

私が説明するように、あなたの言語の標準ライブラリが特定のデータ型に欠けていない限り、「ライブラリ」は不要です。

確かに、実際の使用での通貨についてもっと知る必要があります。物理的な使用で表現するために知っておく必要があるものに特に興味があります(たとえば、ドルでは、0.01未満の精度はなく、整数のセントとして表現できます)。

簡単に言えば、浮動小数点ではなく固定小数点が必要です。たとえば、JavaのBigDecimalクラスを使用して通貨額を格納できます。他の現代言語には、C#Pythonなどの類似のタイプが組み込まれています。実装方法は異なりますが、通常、数値は整数として格納され、小数点の位置は別のデータメンバーとして格納されます。これにより、IEEE浮動小数点数で奇数の剰余(たとえば0.0000001)を与える算術を実行する場合でも、正確な精度が得られます。

特に、ある通貨で値を保存して印刷できるようにするには、何を知る必要がありますか?

重要な点がいくつかあります。

  1. 浮動小数点ではなく実際の10進数型を使用します。

  2. 通貨額には、値(5.63)と通貨コードまたはタイプ(USD、CAD、GBP、EURなど)の2つの要素があることを理解してください。通貨コードを無視できる場合もあれば、重要な場合もあります。複数の通貨を使用できる金融システムまたは小売/電子商取引システムで作業している場合はどうなりますか?CADで顧客からお金を取ろうとしているが、顧客がMXNで支払いたい場合はどうなりますか?これらの値を混合できるようにするには、通貨コードと通貨額を備えた「お金」タイプが必要です(為替レートもありますが、接線に行き過ぎたくないです)。同時に、私の個人的な財務ソフトウェアは、すべてが米ドルであるため、これを心配する必要はありません(通貨混在させることができますが、私はする必要はありません)。

  3. 通貨は実際には最小の物理単位を持っているかもしれませんが(CADとUSDはセントを持っていますが、JPYはちょうど...円です)、もっと小さくすることは可能です。CandiedOrangeの回答は、燃料価格を10分の1セントで示しています。私の固定資産税は、1ドルあたりのミル、または10分の1セント(USDドルの1/1000)として評価されます。0.01ドルに制限しないでください。ほとんどの場合、これらの値を表示できますが、型はより小さくする必要があります(上記で参照した10進数型は可能です)。

  4. 中間計算では、確かに1セントよりも高い精度が必要です。私は、内部値が内部で0.00000001に丸められた小売/電子商取引システムに取り組んできました。通常、無限精度は10進数型(またはSQL)ではサポートされていないため制限が必要です。たとえば、JavaのBigDecimalを使用して1/3を除算すると、値を正確に表すことができないため、RoundingModeまたはMathContextを指定せずに例外がスローされます。

    とにかく、これは特定の場合に重要です。ショッピングカートに6個のアイテムがあるユーザーがいて、彼がチェックアウトする場合を考えてみましょう。システムは税を計算する必要があり、アイテムごとに計算されるのは、アイテムが異なる方法で課税される可能性があるためです。各アイテムで税金を丸めると、取引/カートレベルでペニー丸めエラーが発生する場合があります。これを修正する1つの方法は、アイテムごとに小数点以下の桁に税金を格納し、トランザクション全体の合計を取得し、各アイテムを戻って合計税が正しくなるように丸めることです(1つのアイテムが切り上げられ、別のアイテムが切り捨てられる場合があります)。

これらすべてから理解する重要なことは、適切な人にとっては、小銭の丸めと同じくらい重要なことが非常に重要になる可能性があることです(たとえば、顧客のために政府の売上税を支払わなければならなかった私の過去の顧客の一部)。ただし、これらはすべて解決された問題です。上記の点を念頭に置いて、自分で実験をしてください。そうすることで学習できます。


2では、為替レートは少なくとも独自の数字を得るのに十分だと思います。レートは時間とともに変化することを考慮する必要がありますが、これにはいくつかの異なる処理方法があります。
イズカタ

2
+1。また、通貨は時間とともに変化します。ブラジルでは、80年代と90年代に繰り返し通貨の変更が行われ、ゼロに切り替わって、必要に応じて制御不能なインフレにより通貨の名前が変更されました。これは、通貨のあらゆる側面が時間とともに変化する可能性があることを意味します。
マチャド

@Iskataは確かに、通貨を変更するシステムに取り組んできました。関連性があるため、このトピックに触れたいと思いました。ただし、それは質問の焦点では​​なく、通貨交換のトピックに関するこの限り、別の答えを入力する可能性があります。

私が説明するように、あなたの言語の標準ライブラリが特定のデータ型に欠けていない限り、「「ライブラリ」は不要です。」通貨には、半分、4分の1、10分の1、8分の1などを含めることができます。つまり、少なくとも10進数表現が必要です。しかし、全体の1/3の部分を持つ通貨が存在しないことを完全に確信していますか?
ダニエル

4

多くの開発者が通貨の単一のデータ表現に直面する場所の1つは、iOSアプリケーションのアプリ内購入です。顧客は世界中のほぼすべての国の店舗に接続できます。そして、そのような状況では、倍精度の数値、および通貨コードで構成される購入価格が与えられます。

数値が大きくなる可能性があることに注意する必要があります。たとえば、10ドルに相当する通貨が100,000単位を超える通貨があります。そして、現在のところ、ジンバブエドルのような通貨が存在しないことを幸運に思っています。ジンバブエドルでは、100兆紙幣を手に入れることができます!

通貨を表示するには、いくつかのライブラリが必要になります-自分で完全に入手する機会はありません。表示は、通貨コードとユーザーのロケールの2つのことに依存します。アメリカのロケールとカナダのロケールで米ドルとカナダドルがどのように表示されるかを考えてみましょう。アメリカでは$ vs CAN $、カナダではUS $ vs. $があります。それがOSに組み込まれているか、優れたライブラリがあることを願っています。

計算の場合、計算は丸めステップで終了します。その丸めを合法的に実行する方法を見つける必要があるでしょう。それはプログラミングの問題ではなく、法的問題です。たとえば、英国でVATを計算する場合、アイテムごとまたはアイテムの行ごとに税金を計算し、1セントに切り捨てる必要があります。何に丸めるかは通貨によって異なります。しかし、ルールは明らかに国によって異なります。英国で法的に正しい計算が日本で法的に正しいとは期待できません。


0

特に、ある通貨で値を保存して印刷できるようにするには、何を知る必要がありますか?

  • 「値を保存する」:固定小数点数データ型と通貨型。これらはかなり明白だと思います。非固定小数点数への格納には、丸めが含まれ、値が変更される場合があります。通貨の計算は別の問題になります。
  • 「それらを印刷する」:ユーザーロケール。運が良ければ、通貨記号、千単位の区切り記号、小数点記号、精度など、すべてを行うための標準ライブラリを入手できます。

ロケールに関連する問題の例:

  • 米国のロケールでは100 USDは100.00ドルで、他のロケールでは小数点を小数点としてUS $ 100.00になります。
  • 一部の国では、番号をグループ化するのに1000ではなく無数を使用しています。たとえば、10,000.00ではなく1,0000.00になります
  • 実際的な理由から、人々は小さな通貨のすべての数字を印刷するわけではありません。たとえば、1,000,000,000.00ドルの代わりに、10億ドルを印刷するだけです。

別の潜在的な問題は、通貨を固定小数点数で正しく保存しても、印刷に使用されるライブラリは浮動小数点のみをサポートするため、浮動小数点数に変換する必要がある場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.