我必须将尾随零添加到十进制值。不仅用于显示(因此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;
在我目前发现的所有情况下都可以使用...但是看起来也不是很值得信赖。我也可以实现零的特殊情况。
我认为
Format
和Parse
可以工作。我不太喜欢它看起来不太快,我也不明白为什么我必须将十进制数放入字符串中才能进行操作。我开始相信,对于这样一个简单的任务,没有干净的解决方案。
最佳答案
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),并且另一个解析器可以轻松地将1M
和1.0M
都映射到{sign: 0, value: 1, point: 0}
。
一起添加1M
和0.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位数字的数字。同样,该值必须在点前面和点后面的数字之间“分割”,因此非常大的数字将限制可用精度,可能会降低它的大小,以表示点前面的数字。