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());
                }
            }
        }
    }

}

我使用 Object 类型,因为我不知道它可能是哪种实际类型。所以,就在做 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 浮点格式不能准确地表示每个数字。因此,您的问题无法避免并按预期工作。

如果您需要绝对保证输入 = 输出,而您不能保证输入可以由使用的浮点格式准确表示,那么您永远不应该使用浮点格式。

大多数人在尝试将货币值存储在浮点数中时都会遇到这些问题,这被普遍认为是一个非常糟糕的主意。如果您需要存储货币值,请将其保存为整数值,通常为美分。

于 2012-12-06T09:21:30.947 回答
0

我想这与 1504.57 作为双精度浮点 # 的表示有关。

也许有几个选项,一个是四舍五入多余的数字,另一个是存储美分而不是美元,如果数字是货币#。

于 2012-12-06T05:59:36.997 回答
0

我会回应上述所有评论,即浮点数在从十进制转换为二进制并返回时通常会出现有趣的舍入错误。

在您的特定情况下,舍入错误是由 C# 语言本身引入的,而不是由 C# 驱动程序引入的。MongoDB 本身不支持单精度浮点数,因此 C# 驱动程序将 C# 浮点值转换为双精度值,然后再发送到数据库。正是在此转换过程中发生舍入错误。

这是一小段 C# 代码,演示了将浮点数转换为双精度数如何引入舍入错误:

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

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

正如其他人所建议的那样,如果您必须具有 100% 的精度,则应该使用浮点或双精度以外的其他数据类型。

于 2012-12-06T15:20:12.480 回答