我必须将尾随零添加到十进制值。不仅用于显示(因此Format不是一个选项),而且还用于显示实际的基础数据,因为十进制精度在我们的应用程序中很重要。

我试过了:

decimal value = 1M
decimal withPrecision = value + 0.000M;

在许多情况下效果很好...奇怪的是,并非全部。我调试了withPrecision中的值仍然为1M的情况,方法是在运行时看不到该值的任何差异,并且在即时窗口中看不到相同的硬编码值。我还使用了decimal.GetBits来查找差异-没有差异。

我尝试过(如此处Adjusting decimal precision, .net所建议):
decimal value = 1M
decimal withPrecision = value * 1.000M;

效果很好-除了大小写为零的情况。那么结果是0M,没有任何尾随零。我也不信任该解决方案,在其他情况下也可能不起作用。

目前,我在:
decimal value = 1M
decimal withPrecision = (value * 1.000M) + 0.000M;

在我目前发现的所有情况下都可以使用...但是看起来也不是很值得信赖。我也可以实现零的特殊情况。

我认为FormatParse可以工作。我不太喜欢它看起来不太快,我也不明白为什么我必须将十进制数放入字符串中才能进行操作。

我开始相信,对于这样一个简单的任务,没有干净的解决方案。

最佳答案

decimal占用128位(16字节),其中1位用于符号,96位(12字节)用于实际值,5位用于存储小数点的位置。

当C#编译器看到1M时,它将其解析为{sign: 0, value: 1, point: 0},而1.0M则解析为{sign: 0, value: 10, point: 1}。但是,两者都表示相同的值(1M == 1.0M返回true),并且另一个解析器可以轻松地将1M1.0M都映射到{sign: 0, value: 1, point: 0}

一起添加1M0.1M会发生什么? 1M{sign: 0, value: 1, point: 0}0.1M{sign: 0, value: 1, point: 1},因此我们有两个精度不同的数字。但这没问题:我们可以通过将1M添加到其点并将其值乘以1:10来移动{sign: 0, value: 10, point: 1}中的点。现在两个数字都具有相同的点位置,我们可以通过简单地将它们的值相加来将它们加在一起,从而得到{sign: 0, value: 11, point: 1},它对应于1.1M

因此,decimal的内部表示形式不会影响其操作的精度-只要有必要,小数点位置就会移动(并调整值)。*

但是,如果由于某种原因您的小数绝对必须具有某个点的位置(从您到目前为止发布的内容来看,我没有令人信服的理由-格式化纯粹是显示问题),那么最简单的方法是使用decimal(int, int, int, bool, byte)构造函数(或decimal(int[]))。这使您可以传入值(作为3个整数),符号(作为 bool 值)和点位置(作为字节)。如果传递的点位置高于0,则必须自己乘以该值:1.000M必须构造为new decimal(1000, 0, 0, false, 3),而不是new decimal(1, 0, 0, false, 3)(因为这会给你0.001M)。

*点的位置限制为[0-28],因此decimal不能表示点后面多于28位数字的数字。同样,该值必须在点前面和点后面的数字之间“分割”,因此非常大的数字将限制可用精度,可能会降低它的大小,以表示点前面的数字。

10-04 11:08