CodeGym /课程 /C# SELF /浮点类型的四舍五入

浮点类型的四舍五入

C# SELF
第 6 级, 课程 4
可用

1. 入门

现实生活中,钱很少会精确到一亿亿分之一欧元,房间长度也没人量到百分之一毫米。在编程里也是这样:用double或float算出来的结果经常“太小数”了。

来个经典问题:

double result = 10.0 / 3.0;
Console.WriteLine(result); // 3.3333333333333335
浮点数相除——结果带“尾巴”

那如果我们想只显示两位小数(别吓到用户)怎么办?这就得用四舍五入了。

2. C#里的主要四舍五入方法

C#有好几种办法能把浮点数四舍五入。这里就有意思了:四舍五入其实有很多种!咱们来看看主流的几种方式,搞清楚它们的区别。

1) Math.Round函数——经典四舍五入

最常用的就是Math.Round方法。它能把数字四舍五入到最近的整数(或者你想要的小数位数)。


Math.Round(数字[, 小数位数[, MidpointRounding]])
Math.Round语法
  • 数字 —— 你要四舍五入的数。
  • 小数位数 —— 保留几位小数(默认0,就是取整)。
  • MidpointRounding —— 四舍五入“中间值”的方式(马上讲)。

例子:

double x = 2.71828;

Console.WriteLine(Math.Round(x));         // 3
Console.WriteLine(Math.Round(x, 2));      // 2.72
Console.WriteLine(Math.Round(x, 3));      // 2.718

可视化:

输入值 Math.Round(x) Math.Round(x, 2)
2.3 2 2.3
2.5 2 2.5
2.7 3 2.7
2.71828 3 2.72

返回类型:
本讲所有函数返回的都是double,所以你要是直接赋值给int变量会报错:

double result = 10.0 / 5.0;     // 结果2.0
int x = Math.Round(x);          // 错误! 不能直接把double赋给int变量

如果你想把double赋给int变量,得手动强制类型转换:

double result = 10.0 / 5.0;     // 结果2.0
int x = (int) Math.Round(x);    // 这样就没问题了!

2) 向上或向下取整

C#不仅有“经典”四舍五入,还能强制只往上或只往下取整。

向下取整(Math.Floor)

Math.Floor方法就是直接“砍掉”小数部分(往负无穷方向)。也就是永远向下!

Console.WriteLine(Math.Floor(2.99));   // 2
Console.WriteLine(Math.Floor(-2.99));  // -3

向上取整(Math.Ceiling)

Math.Ceiling方法和Floor正好相反:它永远往上(正无穷方向)取整。

Console.WriteLine(Math.Ceiling(2.01));   // 3
Console.WriteLine(Math.Ceiling(-2.01));  // -2

对比表:

函数 2.3 -2.3
Math.Round 2 -2
Math.Floor 2 -3
Math.Ceiling 3 -2

3) Truncate:只砍掉小数部分

Math.Truncate方法就像“佛系外科医生”。它只把小数部分去掉,完全不管数学意义上的四舍五入。如果x是正数,结果和Floor一样;如果是负数,和Ceiling一样。

Console.WriteLine(Math.Truncate(2.99));   // 2
Console.WriteLine(Math.Truncate(-2.99));  // -2

3. Math.Round怎么处理“中间值”?(MidpointRounding)

想象一下:你有2.5。要四舍五入——往哪边?正好在2和3中间。数学上有两种常见做法:

  • 总是往上取整(“到最近的大数”)
  • 取最近的偶数(Banker's rounding)

C#默认用第二种——取最近的偶数(“banker's rounding”,也叫“向偶数取整”)。

Console.WriteLine(Math.Round(2.5)); // 2
Console.WriteLine(Math.Round(3.5)); // 4

为啥?因为两个一样远的整数里,偶数“赢”。这样做是为了大量四舍五入时不会总是偏大或偏小。比如银行算钱的时候很重要(所以叫banker's rounding)。

如果你想每次都往上,可以手动指定模式:

// 总是“远离0”取整
Console.WriteLine(Math.Round(2.5, 0, MidpointRounding.AwayFromZero)); // 3
Console.WriteLine(Math.Round(-2.5, 0, MidpointRounding.AwayFromZero)); // -3

MidpointRounding模式表:

输入值 Round(默认) AwayFromZero ToZero / ToEven
2.5 2 3 2
3.5 4 4 4
-2.5 -2 -3 -2

4. 四舍五入到指定小数位:别忘了“8”和“3”!

有时候你不是要取整,而是要保留两位小数(比如显示金额或百分比)。

double price = 149.9999;
double roundedPrice = Math.Round(price, 2);
Console.WriteLine(roundedPrice); // 150

那如果我们只是想“砍掉”多余的小数,不想四舍五入呢?比如把123.4567变成123.45。

可以用个小技巧:

double num = 123.4567;
double result = Math.Floor(num * 100) / 100;
Console.WriteLine(result); // 123.45

我们手动“移动”小数点,砍掉小数,再移回来。

5. 输出格式化 vs 真正四舍五入

注意!

输出格式化({x:F2})其实不一定是“真正的”四舍五入,只是“外表”看起来那样。内存里还是原来的“长尾巴”double。你要是真的想把值四舍五入并保存下来,得用Math.Round。

有时候这个区别很关键:

double value = 2.555;
Console.WriteLine($"{value:F2}"); // 2.56
Console.WriteLine(Math.Round(value, 2)); // 2.56

double stored = Math.Round(value, 2);
Console.WriteLine(stored); // 2.56

// 但如果只是格式化输出,不四舍五入...
Console.WriteLine($"{value:F2}"); // 2.56,但内存里还是2.555

6. 常见错误和小细节

  • 别用double做精确的财务计算! .NET里有专门的decimal类型——它不会“飘”小数点(详细以后讲)。
  • 讨厌的“悬挂8”:因为二进制存储,有些数肉眼看着不“合理”地四舍五入。比如0.1 + 0.2其实不是0.3。
  • 别把Math.Floor和Math.Round搞混! Floor永远向下,Round按数学规则来。
  • 误差积累失控:如果你在计算过程中频繁四舍五入(比如循环里),最后的结果可能会“跑偏”。一般最好只对最终结果四舍五入,不要每一步都处理。

7. 总结表:每种方法的效果

输入值 Math.Round(x) Math.Floor(x) Math.Ceiling(x) Math.Truncate(x)
3.2 3 3 4 3
3.5 4 3 4 3
-3.2 -3 -4 -3 -3
-3.5 -4 -4 -3 -3

8. 有趣的事实

  • NASA有次因为坐标四舍五入不严谨、单位换算(公制/英制)搞错,直接把探测器弄丢了。教训:四舍五入要认真!
  • 银行早就用“banker's rounding”了,不然以前大家都往上取整,客户每次转账都亏点小钱。
  • C#里还有Math.Sign方法,能返回数字的正负号——有时候四舍五入前用它自己决定往哪边“砍”挺方便。
2
任务
C# SELF, 第 6 级, 课程 4
已锁定
按指定小数位数进行四舍五入
按指定小数位数进行四舍五入
2
任务
C# SELF, 第 6 级, 课程 4
已锁定
不同取整方法的应用
不同取整方法的应用
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION