c# xx.5 舍入

c# rounding for xx.5

为我的应用程序编写扩展方法并指定精度是个好主意还是有任何其他好主意或其他实现预期的方法 结果?

由于 Convert.ToInt32 的截断行为,我正在做类似 下面 的事情来实现预期结果

Note: Application requirement is to have percentages as Integer and not decimals eg 50.50 is 51 and not 50.5 , TotalScore is an aggregation of other decimals (scores) , for accurate of percentage I wanted any xx.5 to be rounded towards tens

    public decimal TotalScore { get; set; }

    public int TotalCount { get; set; }

    [DataMember(Name = "currentScore")]
    public int? CurrentScore
    {
        get
        {
            if (TotalCount > 0)
            {
                //eg 0.8149863 * 100 = 81.50 ~ 82
                //Convert.ToInt32 use Math.Truncate , so better to round it first
                //default MidpointRounding.Toeven SO : 2.5 ~ 2 and 3.5 ~ 4
                return Convert.ToInt32((Math.Round(Math.Round(TotalScore * 100, 2, MidpointRounding.AwayFromZero), MidpointRounding.AwayFromZero)) / TotalCount);
            }
            else
            {
                return null;
            }
        }
        set
        {
            //Due to the fact WCF will fail with ReadOnly properties.
        }
    }

示例:

'0.8149863 * 100 = 81.50 ~ 82' '0.2021111 * 100 = 20.21 ~ 20' '0.5889681 * 100 = 58.89 ~ 59'

Note: The behavior for Math.Round is as expected when closer to '0' or '10' , but above double rounding is done specially for 'xx.5'(and works for other cases) Convert.ToInt32 uses truncate and makes no expense in getting accurate results

我非常需要上述行为,所以决定写一个扩展 below ,以便在计算小数百分比和期望 [=37 中的整数值时调用扩展=]

    /// <summary>
    /// 
    /// </summary>
    /// <param name="value"></param>
    /// <param name="count"></param>
    /// <param name="decimals">Number of decimal places </param>
    /// <returns></returns>
    public static int ToIntPercentageWithPrecision(this decimal value , int count , int decimals )
    {
        return Convert.ToInt32((Math.Round(Math.Round(value * 100, decimals, MidpointRounding.AwayFromZero), MidpointRounding.AwayFromZero)) / count);
    }

但是上面的解决方案不可读并且看起来很混乱。需要一个清晰、可读且准确的解决方案。

如何使用这样的扩展方法:

public static class RoundingExtentionMethod
{
    public static int ToIntegerPercentage(this decimal d)
    {
        return Convert.ToInt32(Math.Ceiling(Math.Round (d * 100, 2, MidpointRounding.AwayFromZero)));
    }
}

然后你可以打电话给

var result = (0.8149863M * 100).ToIntegerPercentage ();

您的扩展方法中的表达式:

 return Convert.ToInt32((Math.Round(Math.Round(value * 100, decimals, MidpointRounding.AwayFromZero), MidpointRounding.AwayFromZero)) / count);

应该给你和刚才做的完全一样的事情:

 return Convert.ToInt32(Math.Round(value * 100, MidpointRounding.AwayFromZero) / count);

我不知道为什么你在该函数中甚至有 "decimals" 参数,因为用户输入的任何小数都会被你的外舍入截断。你真的不需要为此扩展,只需说

Math.Round(value * 100, MidpointRounding.AwayFromZero)

无论您想将 .8149863 之类的分数转换为 81%。将 .8149863 四舍五入为 82% 在技术上是不正确的。它接近81%。您进行两次四舍五入的技巧确实将其四舍五入为 82,但这并不是真正接近的百分比。

基本上,您要对小数值为 0.495 或更高的任何值进行四舍五入。因此,您可以通过向该值添加 0.505 (1 - 0.495) 来简化舍入,然后仅转换为 int (相当于截断或取底值)。

public int? CurrentScore
{
    get
    {
        if (TotalCount > 0)
        {
            return (int)((TotalScore * 100) + 0.505m);
        }
        else
        {
            return null;
        }
    }
    set
    {
        //Due to the fact WCF will fail with ReadOnly properties.
    }
}