古怪的可空十进制精度行为

本文关键字:精度 十进制 | 更新日期: 2023-09-27 17:48:56

我在数据存储中有一些列使用12十进制精度。

我想将其四舍五入到4位,以便通过文本提要发送,而该提要的消费者需要x精度。

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

if (obj.myValue.HasValue)
    obj.myValue = System.Math.Round(obj.MyValue.Value, 4)
上面的例子

可以进行舍入,但是在一些情况下,不删除后面的0。使用obj.myValue.ToString()(依此类推,适用于所有字段)自动生成的最终结果

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

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

134.402100000000

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

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

,有些行仍然以末尾的0结尾。

看起来好像属性被初始化为x位小数,和最终的ToString。

考虑到我没有直接访问这段代码,但可以注入任何c#在该属性上执行,还有其他的事情我可以尝试吗?(我还尝试硬编码所有行到一个值,这工作得很好w/out额外的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(测试是否truncate会删除0)

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

和. .截断适用于所有行,但是0仍然保留在那些具有先前!不同的是,这次只有0。在截断之前是8900000000等等。这太疯狂了!

古怪的可空十进制精度行为

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

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

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

*注:这里的"显示"是指"输出到文本",而不一定是"显示给用户"

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