1

csharp ドライバーを使用して浮動小数点数を MongoDB に保存すると、正確に保存されません。私の番号が 1504.57 の場合、データベースの番号は同じになると思いますが、何らかの理由で 1504.56994628906 になります (MongoDB の Double 型を使用)。どうしたの?データを正確に保つには?

私のオブジェクトはすべてのフィールドをオブジェクト型として保持し、型に応じてオンザフライでキャストします。次に例を示します。

 this.Values[i] = float.Parse(this.Values[i].ToString());

多分それがこの奇妙な行動の理由ですか?しかし、 this.Values[i] をキャストした後はかなり正確で、データベースでのみ損なわれます。ありがとう

アップデート。データをカプセル化するクラス: public class TransferredData { [BsonElement("_id")] [ScriptIgnore] public ObjectId Id { get; 設定; }

    public class Data
    {
        public List<Object> Values { get; set; }
        public DateTypes DataType { get; set; }
        public void CastToType()
        {
            for (int i = 0; i < this.Values.Count; i++ )
            {
                if (this.DataType == DateTypes.Date)
                {
                    DateTime dt = DateTime.Parse(this.Values[i].ToString());
                    this.Values[i] = dt.ToUniversalTime().Date;
                }
                else if (this.DataType == DateTypes.Other)
                {
                    this.Values[i] = this.Values[i].ToString();
                }
                else if (this.DataType == DateTypes.Reading)
                {
                    this.Values[i] = float.Parse(this.Values[i].ToString());
                }
            }
        }
    }

}

実際の型がわからないため、オブジェクト型を使用します。したがって、upsert を実行する直前に、このクラスにデータを入力してから、Cast メソッドを呼び出します。

Then I save it into db:
data = new TransferredData();
...
data.Values[1] = "1504.57"; // Because the input is always string
data.CastToType(); // Here data.Values[1] = 1504.57 - cool
TransferredDataCollection.Save<TransferredData>(data, SafeMode.True);

この後、データベースを調べると... 1504.56994628906 です

4

3 に答える 3

3

IEEE 754 浮動小数点形式は、すべての数値を正確に表すことはできません。そのため、問題を回避することはできず、意図したとおりに機能します。

使用する浮動小数点形式で入力を正確に表現できることを保証できない一方で、input=output であるという絶対的な保証が必要な場合は、浮動小数点形式を使用しないでください。

ほとんどの人は、非常に悪い考えであると普遍的に認められているフロートに金銭的な値を格納しようとすると、これらの問題に遭遇します。金銭的な値を保存する必要がある場合は、整数値 (通常はセント) として保存します。

于 2012-12-06T09:21:30.947 に答える
0

これは、倍精度浮動小数点#としての1504.57の表現と関係があると思います。

おそらく、いくつかのオプションがあります。1つは余分な桁を四捨五入する方法で、もう1つは、数値が通貨番号の場合、ドルではなくセントを格納する方法です。

于 2012-12-06T05:59:36.997 に答える
0

浮動小数点数は、10進数から2進数に変換したり、その逆に変換したりすると、興味深い丸め誤差を示すことが多いという上記のコメントをすべてエコーします。

特定のケースでは、丸め誤差は、C#ドライバーではなく、C#言語自体によって発生しています。MongoDBは単精度浮動小数点数をネイティブにサポートしていないため、C#浮動小数点値はデータベースに送信される前にC#ドライバーによってdoubleに変換されます。丸め誤差が発生するのは、この変換中です。

これは、floatをdoubleにキャストすると、丸め誤差がどのように発生するかを示すC#コードの小さなスニペットです。

var f = (float)1504.57;
var d = (double)f;

Console.WriteLine(f);
Console.WriteLine(d);

他の人が推奨しているように、100%の精度が必要な場合は、floatまたはdouble以外のデータ型を使用する必要があります。

于 2012-12-06T15:20:12.480 に答える