【C#】浮点数精度避坑

1. 问题描述

关于数字精度问题,很多同学都肯定不陌生了,最经典的就是JS中的0.1+0.2


01+0.2 != 0.3

2. 具体表现

C#中也存在同样数字精度问题。

例如:
float的精度只能保存7位有效数字(参考C#中float的取值范围和精度分析)
下面这段代码将得到1.01

float number = float.Parse("1.0099999");
Console.WriteLine(number.ToString());  // 1.01

同样的问题double也存在

如果说上面2个情况平时不容易碰到的话,可以看看下面的例子

0.015四舍五入得到0.01

同样的代码,类型换成doubledecimal就没有问题了

原因是Math.Round无法传入float类型的参数,float会隐式转换成double,但是在转换过程中会丢失精度

(double)0.015F; //0.01499999...

3. 关于四舍五入

Math.Round的默认行为并不是四舍五入

官方文档描述为:舍入到最接近的数字的策略,当数字在两个数字之间的中间时,它将舍入到最接近的偶数。

具体可参考:枚举 System.MidpointRounding.ToEven

具体表现是:


如果要使用我们常规理解上的四舍五入,需要使用参数 MidpointRounding.AwayFromZero

4. 建议

  1. 实际编码中尽量使用 decimal,避免使用float
  2. floatdoublefloatdecimaldoubledecimal,使用字符串作为中介,尽可能的保留精度;
    如:double.Parse(float.ToString("g9"))

    "g17"(double) 或"g9"(float)能尽可能的保留精度,详见标准数字格式字符串,“G”或“g”小结

  3. 以上部分缺陷在.net5后续版本的.NET中有所改善。

你可能感兴趣的:(【C#】浮点数精度避坑)