8

我在使用 C# 中舍入十进制值时遇到问题Math.Round(a, 2);

当我将 1.275 舍入小数点后 2 位时,结果为 1.27。当我对 1.375 做同样的事情时,结果是 1.38。

为什么不将 1.275 舍入到 1.28?

谢谢

4

7 回答 7

8

我无法重现您的问题:

Math.Round(1.275m, 2) => 1.28m
Math.Round(1.375m, 2) => 1.38m

我怀疑您声称使用decimal值的说法是错误的,double而是使用值。double不能精确地表示许多十进制值,所以当你写1.275的时候,它实际上是 1.27499...1.375 是少数可表示的一次之一,所以它实际上是1.375.

如果您的代码关心精确的十进制表示,例如当您处理金钱时,您必须使用decimal而不是二进制浮点,例如doubleor float


但即使您使用十进制表示,对于许多用户来说,舍入行为也会出乎意料:

Math.Round(1.265m, 2) => 1.26m
Math.Round(1.275m, 2) => 1.28m

默认Math.Round使用MidpointRounding.ToEven,也称为银行家回合。这避免了从总是四舍五入的情况下累积偏差.5

您可以使用Round采用舍入模式的重载,并将其设置AwayFromZero为获得您期望的行为。

Math.Round(1.275m, 2, MidpointRounding.AwayFromZero) => 1.28m
于 2012-07-31T13:19:16.830 回答
7

MSDN对这种行为有这样的说法:

来电者须知

由于将十进制值表示为浮点数或对浮点值执行算术运算可能导致精度损失,因此在某些情况下 Round(Double, Int32) 方法可能不会将中点值四舍五入到最接近的偶数数字小数位的值。这在以下示例中进行了说明,其中 2.135 舍入为 2.13 而不是 2.14。发生这种情况是因为该方法在内部将值乘以 10,并且这种情况下的乘法运算会损失精度。

public class Example
{
   public static void Main()
   {
      double[] values = { 2.125, 2.135, 2.145, 3.125, 3.135, 3.145 };
      foreach (double value in values)
         Console.WriteLine("{0} --> {1}", value, Math.Round(value, 2));

   }
}
// The example displays the following output:
//       2.125 --> 2.12
//       2.135 --> 2.13
//       2.145 --> 2.14
//       3.125 --> 3.12
//       3.135 --> 3.14
//       3.145 --> 3.14
于 2012-07-31T13:27:46.010 回答
4

如果您有一个Decimal值,它将正确舍1.275入为1.28.

如果您有一个Double值,它的行为将不一样,因为该值1.275无法准确表示。如果您使用该double1.275,它实际上会比精确值略小1.275,例如1.2749999999999999.

在四舍五入该值时,它不会恰好介于1.27和之间,1.28而是稍微接近1.27,因此将向下舍入而不是向上舍入。

于 2012-07-31T13:28:18.307 回答
2

这是一个可怕的 hack,但请尝试使用 Format。它莫名其妙地使用了我们都习惯的四舍五入。

Val(Format(2.25, "0.0")) returns 2.3

(或者)

仅供参考:从 .Net 2.0 版开始,可以使用参数 MidpointRounding 定义“0.5 案例”的舍入方式。它可以是 ToEven 或 AwayFromZero。所以“标准”舍入是这样的:

Math.Round(2.25, 1, MidpointRounding.AwayFromZero);

这将返回值“2.3”。

于 2012-07-31T13:23:15.843 回答
1

这是因为您的四舍五入是双精度数,而不是小数:

Console.WriteLine(Math.Round(1.275M, 2)); // outputs 1.28
Console.WriteLine(Math.Round(1.375M, 2)); // outputs 1.38

十进制和双精度是非常不同的

于 2012-07-31T13:28:46.907 回答
1
Format(1.275, "0.00")) 

正如本博客评论中所建议的那样:http ://weblogs.asp.net/sfurman/archive/2003/03/07/3537.aspx

您使用哪个版本的 .Net 框架?如果在1.1以上,可以使用midpointrounding,设置为AwayFromZero

Math.Round(1.275, 2, MidpointRounding.AwayFromZero);

http://msdn.microsoft.com/en-us/library/9s0xa85y%28v=vs.110%29.aspx

于 2012-07-31T13:20:25.207 回答
0

根据文档的预期行为。

例如,如果小数等于 1,则 2.15 和 2.15000 都会四舍五入为 2.2,因为 0.05 和 .05000 都介于 0.1 和 .2 之间,而 0.1 是奇数。同样,如果小数等于 1,则 2.05 和 2.05000 都舍入为 2.0,因为 .05 和 .05000 都在 .0 和 .1 之间,而 .0 是偶数。此方法的行为遵循 IEEE 标准 754 第 4 节。这种四舍五入有时称为四舍五入或银行家四舍五入。它可以最大限度地减少因在单个方向上持续舍入中点值而导致的舍入误差。要控制 Round(Decimal, Int32) 方法使用的舍入类型,请调用 Decimal.Round(Decimal, Int32, MidpointRounding) 重载。

来自Math.Round(decimal, int)。尝试

Decimal.Round(a, 2, MidpointRounding.AwayFromZero);
于 2012-07-31T13:55:02.297 回答