我有一个类似的概率列表

0.0442857142857143
0.664642857142857
0.291071428571429


我想将它们转换为最接近的百分比,以使百分比之和总计为100

所以像这样

0.0442857142857143 - 4 %
0.664642857142857  -  67 %
0.291071428571429  -  29 %


我不能依靠Math.Round总是给我提供总计为1的结果。什么是最好的方法?

最佳答案

有趣的答案集合。

这里的问题是,在四舍五入操作中出现累积错误。在某些情况下,累积的误差会抵消-一些值向上取整,而其他值向下取整,从而抵消了总误差。在其他情况下(例如您在此处遇到的情况),舍入误差均为负,得出的累积总误差为(大约)-1。

通常情况下,解决此问题的唯一方法是跟踪总累积误差,并在误差变得足够大时加/减。这很繁琐,但是唯一正确的正确方法是:

static int[] ToIntPercents(double[] values)
{
    int[] results = new int[values.Length];
    double error = 0;
    for (int i = 0; i < values.Length; i++)
    {
        double val = values[i] * 100;
        int percent = (int)Math.Round(val + error);
        error += val - percent;
        if (Math.Abs(error) >= 0.5)
        {
            int sign = Math.Sign(error);
            percent += sign;
            error -= sign;
        }
        results[i] = percent;
    }

    return results;
}


对于任何大小约为+1.0000(或足够接近)的数组,此代码都会产生合理的结果。数组可以包含负值和正值,只要总和足够接近+1.0000,就不会引起严重错误。

该代码会累积舍入误差,当总误差超过-0.5 < error < +0.5的可接受范围时,它将调整输出。使用此方法,您的数字的输出数组为:[4, 67, 29]。您可以将可接受的错误范围更改为0 <= error < 1,给出输出[4, 66, 30],但是当数组包含负数时,这会导致奇怪的结果。如果这是您的喜好,请将方法中间的if语句更改为:

if (error < 0 || error >= 1)

关于c# - 四舍五入小数并在C#中转换为%,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20137562/

10-09 16:38