奇异的可空小数精度行为

时间:2011-04-06 17:42:39

标签: c# .net decimal precision

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

我想将其四舍五入到4个位置,以便通过文本Feed发送它,并且该Feed的使用者需要x精度。

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

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

以上示例适用于舍入,但在 SOME 情况下不会删除尾随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#,还有其他我可以尝试的东西吗? (我也尝试将所有行硬编码为一个值,并且在没有额外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等。这很狂野!

2 个答案:

答案 0 :(得分:3)

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

我认为Domenic对他的回答有正确的想法。让十进制数字在存储中保持不整齐,只显示*它们四舍五入。

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

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

答案 1 :(得分:2)

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