C# decimal乘法结果出现尾部多余0的原因及去除方法
现象原因
C# 的 decimal 类型的128位存储结构中,除了符号位和有效数字尾数,还单独存储了小数位数元数据,会保留参与运算数值的精度信息。
两个 decimal 执行乘法运算时,结果的小数位数默认取两个因子的小数位数之和:例如 0.4M 的小数位数是1,1.05M 的小数位数是2,相乘后结果的小数位数固定为3位,哪怕最后一位是0也会作为精度信息保留,因此打印时会输出 0.420 而非 0.42。
注:
0.420和0.42的数值完全相等,用==判断会返回true,仅在字符串输出、序列化等读取精度元数据的场景会体现差异。
解决方案
方案1:直接获取无末尾0的decimal类型结果
该方案会修改decimal本身的精度元数据,移除末尾无效0。
- 若使用 .NET Core 3.0 / .NET 5 及以上版本,可直接调用原生的
decimal.Normalize()方法:
decimal a = 0.4M; decimal b = 1.05M; decimal res1 = (a * b).Normalize(); Console.WriteLine(res1); // 输出 0.42 decimal c = 0.06M; decimal d = 1.15M; decimal res2 = (c * d).Normalize(); Console.WriteLine(res2); // 输出 0.069
- 若使用 .NET Framework 或更低版本的.NET,可自行实现精度裁剪逻辑:
public static decimal NormalizeDecimal(decimal value) { // 除以1不会改变数值,会触发decimal自动裁剪末尾无效0 return value / 1.0000000000000000000000000000M; }
方案2:仅输出时不显示末尾0
如果不需要修改decimal的存储结构,仅在打印时隐藏末尾无效0,可使用 G29 格式化字符串,该方案适配所有.NET版本:
decimal a = 0.4M; decimal b = 1.05M; Console.WriteLine((a * b).ToString("G29")); // 输出 0.42
内容的提问来源于stack exchange,提问作者eddex
相关产品推荐
相关产品推荐

