Ste*_*ger 4 c# precision decimal digits
我必须将尾随零添加到十进制值.不仅用于显示(因此Format不是选项),而是用于实际的底层数据,因为小数精度在我们的应用程序中很重要.
我试过了:
decimal value = 1M
decimal withPrecision = value + 0.000M;
Run Code Online (Sandbox Code Playgroud)
在许多情况下哪种方法效果很好......奇怪的是并非总体而言.我调试了一个情况,其中withPrecision中的值仍然是1M,没有看到运行时的值和立即窗口中相同的硬编码值有任何差异.我还使用了decimal.GetBits来找到差异 - 没有.
我试过(这里提出调整小数精度,.net):
decimal value = 1M
decimal withPrecision = value * 1.000M;
Run Code Online (Sandbox Code Playgroud)
效果很好 - 除了案例值为零.然后结果为0M,没有任何尾随零.我也不相信解决方案,在其他情况下也可能不起作用.
目前我在:
decimal value = 1M
decimal withPrecision = (value * 1.000M) + 0.000M;
Run Code Online (Sandbox Code Playgroud)
这在我目前发现的所有情况下都有效......但是看起来也不值得信赖.我还可以为零实现一个例外情况.
我认为Format并且Parse会工作.我不喜欢它.它看起来不是很快,我不明白为什么我必须将小数字放入一个字符串只是为了操纵它.
我开始相信这样一个简单的任务没有干净的解决方案.
A 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.
因此,a的内部表示decimal不会影响其操作的精度 - 只要有必要,就会移动小数点位置(并调整值).*
但是,如果由于某种原因你的小数绝对必须有一个点位置(并且从你到目前为止发布的,我看到没有令人信服的理由 - 格式化纯粹是一个显示问题),那么最简单的方法是使用decimal(int, int, int, bool, byte)构造函数(或者交替decimal(int[])).这允许您传入值(作为3个整数),符号(作为布尔值)和点位置(作为字节).如果传递高于0的点位置,则1.000M必须自己乘以该值:必须构造为new decimal(1000, 0, 0, false, 3),而不是new decimal(1, 0, 0, false, 3)(因为这会给你0.001M).
*点位置限制为[0-28],因此a decimal不能代表点后面超过28位的数字.此外,该值必须在点前面和点后面的数字之间"分开",因此非常大的数字会对可用精度施加限制,可能会将其缩小以支持在点前面表示数字.
可能不是您希望的答案,但看起来您必须使用 ToString() 进行格式化。我建议您阅读此 MSDN 链接中的“备注”部分。
备注中最后一段指出:
缩放因子还保留十进制数中的所有尾随零。尾随零不会影响算术或比较运算中十进制数的值。但是,如果应用适当的格式字符串,ToString 方法可能会显示尾随零。