4

私はレールを少しいじっていて、奇妙なものを見つけました。金額の値を格納するために、アクティブ レコードが BigDecimal に変換する典型的な 10 進数データ型を使用します。私はこれが正確であると考え、浮動小数点演算の奇妙な振る舞いを避けることを考えました。しかし、99.99 を db に保存するとすべて正常に動作しますが、アクティブ レコードによってレコードが読み込まれると、精度が失われ、99.9899999999 のような値に変換されます。これは浮動小数点の問題のようです。

私はいくつかのテストを行い、この b = BigDecimal.new("99.99") のような BigDecimal を作成すると「クリーンな」変数になることがわかりましたが、この方法でビルドすると b = BigDecimal.new(99.99) は「クリーンでない」バージョンになります避けたいこと。

データベースからレコードをロードするときに、ActiveRecord が中間フロートを使用して BigDecimal を再構築すると思います。これは私が望んでいることではありません。回避できるかどうかを知りたいです。

Ruby バージョン 1.9.3p0 Rails 3.2.9 Sqlite 3.7.9

4

2 に答える 2

5

問題は、SQLite を使用していて、SQLite がnumeric(m,n)データ型をネイティブにサポートしていないことです。細かいマニュアルから:

1.0 ストレージ クラスとデータ型

SQLite データベースに格納された (またはデータベース エンジンによって操作された) 各値には、次のストレージ クラスのいずれかがあります。

  • ヌル。値は NULL 値です。
  • 整数。値は符号付き整数で、値の大きさに応じて 1、2、3、4、6、または 8 バイトで格納されます。
  • 本物。値は浮動小数点値で、8 バイトの IEEE 浮動小数点数として格納されます。
  • 文章。値はテキスト文字列で、データベースのエンコーディング (UTF-8、UTF-16BE、または UTF-16LE) を使用して保存されます。
  • BLOB。値はデータの塊であり、入力されたとおりに保存されます。

そのページをさらに読んで、SQLite の型システムがどのように機能するかを確認してください。

あなたの 99.99 はBigDecimal.new('99.99')あなたの Ruby コードにあるかもしれませんが、それはほぼ確実に SQLite 内のREAL99.99(つまり、8 バイトの IEEE 浮動小数点値) であり、その近くにあります。

したがって、開発環境でより優れたデータベースに切り替えてください。特に、展開しようとしているデータベースの上に開発します。

于 2012-12-12T00:11:07.590 に答える
2

金額に浮動小数点を使用しないでください

はい、まさに、SQLite が BigDecimal 値を台無しにしています。

基本的な問題は、FP 形式ではほとんどの小数を正しく格納できないことです。

次の 4 つの選択肢があると思います。

  1. わずかにずれている値に気付かないように、たとえば小数点以下 2 桁まですべてを四捨五入します。
  2. TEXT または BLOB ストレージ クラスを使用して、BigDecimal 値を SQLite に格納します。
  3. ある種の 10 進文字列をサポートする別のデータベースを使用してください。
  4. すべてを整数値にスケーリングし、INTEGER ストレージ クラスを使用します。

問題は、FP 分数が x/2 nの形式の有理数であることです。しかし、小数の金額には x/(2 n * 5 m ) の分数があります。表現は互換性がありません。たとえば、0.01 ... 0.99 では、0.25、0.50、および 0.75 のみが正確なバイナリ表現を持ちます。

于 2012-12-12T01:29:43.263 に答える