首页 文章

为什么Math.Round(2.5)返回2而不是3?

提问于
浏览
355

在C#中, Math.Round(2.5) 的结果为2 .

应该是3,不是吗?为什么它在C#中代替2?

15 回答

  • -2

    简单的方法是:

    Math.Ceiling(decimal.Parse(yourNumber + ""));
    
  • 23

    首先,这不会决定如何实施 Math.Round .

    其次,不 - 如果你读the docs,你'll see that the default rounding is 1062997 (banker'舍入):

    返回值类型:System.Double最接近a的整数 . 如果a的小数分量在两个整数之间,其中一个是偶数而另一个是奇数,则返回偶数 . 请注意,此方法返回Double而不是整数类型 . 备注此方法的行为遵循IEEE标准754第4节 . 这种舍入有时称为舍入到最近,或者是银行家的舍入 . 它最大限度地减少了在单一方向上始终舍入中点值所导致的舍入误差 .

    您可以使用带有MidpointRounding值的an overload指定 Math.Round 应如何舍入中点 . 有一个 MidpointRounding 的重载对应于每个没有一个的重载:

    是否选择此默认值是另一回事 . ( MidpointRounding 仅在.NET 2.0中引入 . 在此之前我'm not sure there was any easy way of implementing the desired behaviour without doing it yourself.) In particular, history has shown that it'不是预期的行为 - 在大多数情况下,这是API设计中的一个主要原因 . 我可以看到为什么Banker 's Rounding is useful... but it'仍然是许多人的惊喜 .

    您可能有兴趣查看最近的Java等效枚举(RoundingMode),它提供了更多选项 . (它不只是处理中点 . )

  • 0

    那个's called rounding to even (or banker'舍入),这是一个有效的舍入策略,用于最小化累计误差 (MidpointRounding.ToEven) . 理论上说,如果你总是在同一方向上对0.5的数字进行舍入,那么错误将会更快地产生(圆形到偶数应该最小化)(a) .

    请按照以下链接获取MSDN描述:

    • Math.Floor,向下舍入负无穷大 .

    • Math.Ceiling,向正无穷大方向前进 .

    • Math.Truncate,向上或向下舍入为零 .

    • Math.Round,舍入到最接近的整数或指定的小数位数 . 如果行为在两种可能性之间完全等距,则可以指定行为,例如舍入以使最终数字为偶数(“ Round(2.5,MidpointRounding.ToEven) " becoming 2) or so that it's further away from zero (" Round(2.5,MidpointRounding.AwayFromZero) ”变为3) .

    以下图表和表格可能会有所帮助:

    -3        -2        -1         0         1         2         3
     +--|------+---------+----|----+--|------+----|----+-------|-+
        a                     b       c           d            e
    
                           a=-2.7  b=-0.5  c=0.3  d=1.5  e=2.8
                           ======  ======  =====  =====  =====
    Floor                    -3      -1      0      1      2
    Ceiling                  -2       0      1      2      3
    Truncate                 -2       0      0      1      2
    Round(ToEven)            -3       0      0      2      3
    Round(AwayFromZero)      -3      -1      0      2      3
    

    请注意, Round 比它看起来更强大,只是因为它可以舍入到特定的小数位数 . 所有其他的总是小数点零 . 例如:

    n = 3.145;
    a = System.Math.Round (n, 2, MidpointRounding.ToEven);       // 3.14
    b = System.Math.Round (n, 2, MidpointRounding.AwayFromZero); // 3.15
    

    使用其他函数,您必须使用乘法/除法技巧来实现相同的效果:

    c = System.Math.Truncate (n * 100) / 100;                    // 3.14
    d = System.Math.Ceiling (n * 100) / 100;                     // 3.15
    

    (a)当然,这个理论取决于你的数据在偶数半部分(0.5,2.5,4.5,...)和奇数半部分(1.5,3.5,......)具有相当均匀的值 .

    如果所有_1063028都是平均值(例如),则错误将像您总是向上舍入一样快地累积 .

  • 3

    MSDN, Math.Round(double a)返回:

    最接近a的整数 . 如果a的小数分量在两个整数之间,其中一个是偶数而另一个是奇数,则返回偶数 .

    ......等于2.5,介于2和3之间,向下舍入到偶数(2) . 这称为Banker's Rounding(或舍入到偶数),是常用的舍入标准 .

    相同的MSDN文章:

    此方法的行为遵循IEEE标准754第4节 . 这种舍入有时称为舍入到最近,或者是银行家的舍入 . 它最大限度地减少了在单一方向上始终舍入中点值所导致的舍入误差 .

    您可以通过调用采用 MidpointRounding 模式的Math.Round重载来指定不同的舍入行为 .

  • 2

    你应该检查MSDN的Math.Round

    此方法的行为遵循IEEE标准754第4节 . 这种舍入有时称为舍入到最近,或者是银行家的舍入 .

    您可以使用重载指定 Math.Round 的行为:

    Math.Round(2.5, 0, MidpointRounding.AwayFromZero); // gives 3
    
    Math.Round(2.5, 0, MidpointRounding.ToEven); // gives 2
    
  • 29

    这是我必须解决的方式:

    Public Function Round(number As Double, dec As Integer) As Double
        Dim decimalPowerOfTen = Math.Pow(10, dec)
        If CInt(number * decimalPowerOfTen) = Math.Round(number * decimalPowerOfTen, 2) Then
            Return Math.Round(number, 2, MidpointRounding.AwayFromZero)
        Else
            Return CInt(number * decimalPowerOfTen + 0.5) / 100
        End If
    End Function
    

    尝试使用1.905和2位小数将得到1.91,但是 Math.Round(1.905,2,MidpointRounding.AwayFromZero) 给出1.90!对于程序员可能遇到的大多数基本问题,Math.Round方法绝对不一致且无法使用 . 我必须检查 (int) 1.905 * decimalPowerOfTen = Math.Round(number * decimalPowerOfTen, 2) 因为我不想围绕应该向下舍入的内容 .

  • 14

    这很丑陋,但始终产生正确的算术舍入 .

    public double ArithRound(double number,int places){
    
      string numberFormat = "###.";
    
      numberFormat = numberFormat.PadRight(numberFormat.Length + places, '#');
    
      return double.Parse(number.ToString(numberFormat));
    
    }
    
  • 186

    四舍五入的性质

    考虑将包含分数的数字四舍五入到整数的任务 . 在这种情况下舍入的过程是确定哪个整数最能代表您正在舍入的数字 .

    通常,或“算术”舍入,很明显2.1,2.2,2.3和2.4舍入到2.0;和2.6,2.7,2.8和2.9到3.0 .

    离开2.5,它不接近2.0而不是3.0 . 您可以在2.0和3.0之间进行选择,两者都同样有效 .

    对于负数,-2.1,-2.2,-2.3和-2.4,将变为-2.0;在算术舍入下,-2.6,2.7,2.8和2.9将变为-3.0 .

    对于-2.5,需要在-2.0和-3.0之间进行选择 .

    Other forms of rounding

    'Rounding up'取任意小数位数,并使其成为下一个'整数' . 因此,不仅2.5和2.6轮到3.0,但2.1和2.2也是如此 .

    四舍五入将正数和负数从零移开 . 例如 . 2.5至3.0和-2.5至-3.0 .

    '舍入'通过砍掉不需要的数字来截断数字 . 这具有将数字移向零的效果 . 例如 . 2.5到2.0和-2.5到-2.0

    在“银行家的舍入”中 - 以其最常见的形式 - 要舍入的.5向上或向下舍入,以便舍入的结果始终为偶数 . 因此2.5轮到2.0,3.5到4.0,4.5到4.0,5.5到6.0,依此类推 .

    '替代舍入'在舍入和舍入之间交替任何.5的过程 .

    '随机舍入'在完全随机的基础上上下调整.5 .

    Symmetry and asymmetry

    如果舍入函数将所有数字舍入为零或将所有数字舍入为零,则称舍入函数为“对称” .

    如果将正数向零和向负数除以零,则函数是“非对称的” . 例如 . 2.5到2.0;和-2.5到-3.0 .

    非对称性是将正数从零和负数向零舍入的函数 . 例如 . 2.5至3.0;和-2.5到-2.0 .

    Most of time people think of symmetric rounding, where -2.5 will be rounded towards -3.0 and 3.5 will be rounded towards 4.0. (在C# Round(AwayFromZero) 中)

  • 0

    默认的 MidpointRounding.ToEven ,或者银行家的四舍五入(2.5变成2,4.5变成4等等)在写会计报告之前就已经惹我生气了,所以我先写一些我发现的文字,然后再从中查看这篇文章 .

    这些银行家是谁(即使是英国银行家)也是如此?

    来自维基百科

    银行家四舍五入这个词的起源仍然比较模糊 . 如果这种舍入方法曾经是银行业的标准,那么证据证明极难找到 . 相反,欧盟委员会报告“欧元的引入和货币金额的四舍五入”第2节表明,以前没有标准的方法来进行银行业务的四舍五入;并指明应将“中途”金额四舍五入 .

    这似乎是一种非常奇怪的四舍五入的方式,特别是对于银行业务,除非银行当然用来接收大量的偶数存款 . 存款240万英镑,但我们称之为200万英镑先生 .

    IEEE标准754可以追溯到1985年,它提供了两种舍入方式,但是银行家是标准推荐的方式 . 这个wikipedia article有一个很长的列表,列出了语言如何实现舍入(如果以下任何一个错误,请纠正我),而且大多数人都不会这样做,但是你在学校教授的四舍五入:

    来自math.h的

    • C/C++ round()离零(不是银行家的舍入)

    • Java Math.Round从零开始舍入(它将结果置于底层,加0.5,转换为整数) . BigDecimal中有另一种选择

    • Perl 使用与C类似的方式

    • Javascript与Java的Math.Round相同 .

  • 0

    来自MSDN:

    默认情况下,Math.Round使用MidpointRounding.ToEven . 大多数人不熟悉“四舍五入”作为替代方案,“从零开始四舍五入”更常见于学校 . .NET默认为“舍入到均匀”,因为它在统计上更优越,因为它不具有“从零舍入”的倾向,而是比向下舍入更频繁地舍入(假设舍入的数字往往是正数) . )

    http://msdn.microsoft.com/en-us/library/system.math.round.aspx

  • 515

    由于Silverlight不支持MidpointRounding选项,因此您必须自己编写 . 就像是:

    public double RoundCorrect(double d, int decimals)
    {
        double multiplier = Math.Pow(10, decimals);
    
        if (d < 0)
            multiplier *= -1;
    
        return Math.Floor((d * multiplier) + 0.5) / multiplier;
    
    }
    

    有关如何使用此作为扩展名的示例,请参阅帖子:.NET and Silverlight Rounding

  • -1

    我有这个问题,我的SQL服务器向上舍入0.5比1,而我的C#应用程序没有 . 所以你会看到两个不同的结果 .

    这是一个int / long的实现 . 这就是Java的结果 .

    int roundedNumber = (int)Math.Floor(d + 0.5);
    

    它可能是你能想到的最有效的方法 .

    如果你想保持它是一个双倍并使用小数精度,那么它实际上只是根据小数位数使用10的指数 .

    public double getRounding(double number, int decimalPoints)
    {
        double decimalPowerOfTen = Math.Pow(10, decimalPoints);
        return Math.Floor(number * decimalPowerOfTen + 0.5)/ decimalPowerOfTen;
    }
    

    您可以输入小数点的负十进制数,也可以输入单词 .

    getRounding(239, -2) = 200
    
  • 34

    这篇文章有您正在寻找的答案:

    http://weblogs.asp.net/sfurman/archive/2003/03/07/3537.aspx

    基本上这就是它所说的:

    回报 Value

    数字最接近的值,精度等于数字 . 如果值在两个数字之间,其中一个是偶数而另一个是奇数,则返回偶数 . 如果值的精度小于数字,则返回值不变 .

    此方法的行为遵循IEEE标准754第4节 . 这种舍入有时称为舍入到最近,或者是银行家的舍入 . 如果数字为零,则这种舍入有时称为向零舍入 .

  • 0

    Silverlight不支持MidpointRounding选项 . 这是Silverlight的扩展方法,它添加了MidpointRounding枚举:

    public enum MidpointRounding
    {
        ToEven,
        AwayFromZero
    }
    
    public static class DecimalExtensions
    {
        public static decimal Round(this decimal d, MidpointRounding mode)
        {
            return d.Round(0, mode);
        }
    
        /// <summary>
        /// Rounds using arithmetic (5 rounds up) symmetrical (up is away from zero) rounding
        /// </summary>
        /// <param name="d">A Decimal number to be rounded.</param>
        /// <param name="decimals">The number of significant fractional digits (precision) in the return value.</param>
        /// <returns>The number nearest d with precision equal to decimals. If d is halfway between two numbers, then the nearest whole number away from zero is returned.</returns>
        public static decimal Round(this decimal d, int decimals, MidpointRounding mode)
        {
            if ( mode == MidpointRounding.ToEven )
            {
                return decimal.Round(d, decimals);
            }
            else
            {
                decimal factor = Convert.ToDecimal(Math.Pow(10, decimals));
                int sign = Math.Sign(d);
                return Decimal.Truncate(d * factor + 0.5m * sign) / factor;
            }
        }
    }
    

    资料来源:http://anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/

  • 40

    使用自定义舍入

    public int Round(double value)
    {
        double decimalpoints = Math.Abs(value - Math.Floor(value));
        if (decimalpoints > 0.5)
            return (int)Math.Round(value);
        else
            return (int)Math.Floor(value);
    }
    

相关问题