【问题标题】:bizzare nullable decimal precision behavior奇怪的可为空的十进制精度行为
【发布时间】:2011-04-06 17:42:39
【问题描述】:

我在数据存储中有一些列使用 12 位小数精度。

为了通过文本提要发送它,我想将它四舍五入到 4 个位置,并且该提要的消费者需要 x 精度。

我使用的是自定义构建的工作流引擎,在任何执行点都无法直接访问代码,但可以使用条件在任何字段上注入代码,例如:

if (obj.myValue.HasValue)
    obj.myValue = System.Math.Round(obj.MyValue.Value, 4)

上面的例子可以进行四舍五入,但在某些 情况下不会删除尾随的 0。使用 obj.myValue.ToString() 自动生成的最终结果(等等,所有字段)

这似乎只发生在可为空的十进制字段上。

我不确定有什么不同,但在大约 10% 的行中,输出保留了尾随 0。实际值被四舍五入,但0s保留:

134.402100000000

我也尝试过这样做(只是为了确保并删除小数的初始精度)

if (obj.myValue.HasValue)
    obj.myValue = decimal.Parse(obj.MyValue.Value.ToString("#.####"))

同样,一些行保留附加的尾随 0。

看起来该属性已初始化为 x 位小数,以及最终的 ToString。

考虑到我没有直接访问此代码的权限,但可以注入任何要在该属性上执行的 c#,还有其他我可以尝试的方法吗? (我还尝试将所有行硬编码为一个值,并且没有额外的 0 可以正常工作)

另外有趣的是我无法在我的测试中重现这种行为..

        decimal d1 = 160236194.3900000000000001M;
        Console.WriteLine(d1);
        d1 = Math.Round(d1, 4);
        Console.WriteLine(d1);

160236194.3900000000000001
160236194.3900
Press any key to continue . . .

编辑

感谢 e.James 尝试了另一种方法(测试截断是否会删除 0)

if (obj.myValue.HasValue)
    obj.myValue = decimal.Truncate(obj.MyValue.Value)

并且.. 截断适用于所有行,但 0 仍然保留在之前的行上!不同的是,这一次它只有 0s.. 在截断之前是 .8900000000 等等。这太疯狂了!

【问题讨论】:

  • 非二进制表示的浮点数应该是这里某处的主要常见问题解答条目

标签: c# .net decimal precision


【解决方案1】:

有些十进制数不能用二进制格式完美表示。您的 obj.myValue 属性是一个十进制数。对于某些小数,它根本无法存储除(例如)1234.4021000000000001 之外的任何内容,它在有限位数的情况下尽可能接近。

我认为 Domenic 的回答是正确的。让十进制数在存储中保持不四舍五入,并且只显示*它们四舍五入。

如果您绝对必须在存储中对数字进行四舍五入,则必须使用整数格式,然后在显示之前将其除以 1000。 1234.4021 将存储为 12344021。

*注意:“显示”是指“输出到文本”,不一定是“显示给用户”

【讨论】:

  • 是的,这里似乎是这种情况.. 但是我怎样才能将 000000001 舍入到小数点后 4 位?截断或转换为 int 是唯一的方法吗?
  • 我认为截断是最好的方法。 00000001 已经尽可能地四舍五入,所以用它做任何数学运算都无济于事。
  • 有趣的是我无法在我的测试中重现这一点.. Math.Round 似乎总是有效..
  • Math.Round 返回什么类型的值?会不会是双精度浮点数,而obj.myValue 是单精度浮点数?
  • 另外,你如何测试 Math.Round()? (Math.Round(1234.40211111, 4) == 1234.4021) 仍将评估为真,因为 both 将存储为 1234.4021000000001
【解决方案2】:

为什么不让显示逻辑处理,呃,显示逻辑?也就是说,只有当您将decimal 显示为string 时,您才应该关心显示的尾随0s 的数量,在这种情况下您应该使用theDecimal.ToString("#.####")

【讨论】:

  • 我有没有提到会显示数据?不。它是作为提要生成的。根据我的帖子,我已经尝试过这种方法
  • 如果它没有被显示,那你为什么担心尾随 0?它们纯粹是展示神器。
  • 因为它是基于文件的提要,并且该提要的消费者很关心。不,我不能告诉他们停止关心。
  • 所以你在文件中显示它?那么,当你将它写入文件时,你就可以进行字符串转换......
  • 正如 e.James 所暗示的,当我们将“显示逻辑”与程序的其余部分分开时,显示并不意味着 UI。
猜你喜欢
  • 2013-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多