使用不同的精度对数字进行四舍五入

3

使用C#,我需要一种优雅的方法将一个精度为1/8的数字四舍五入到精度为1/2,并遵循以下规则:

Round(0) = 0
Round(0.125) = 0
Round(0.25) = 0
Round(0.375) = 0.5
Round(0.5) = 0.5
Round(0.625) = 0.5
Round(0.75) = 0.5
Round(0.875) = 1
Round(1) = 1

当然我并不仅限于介于0和1之间的数字。有没有一种不需要过多条件语句的好方法呢?


乘以8,将结果四舍五入为0位小数,然后再除以8。 - Bob Vale
3个回答

1
以下代码片段展示了您想要的内容。它使用乘以2的技巧(这样我们就可以将其四舍五入为整数),并减去一个微小的量。我们减去0.001M,因为我们希望0.25四舍五入为0,0.75四舍五入为0.5。通常,在乘以二后进行舍入时,它们会被舍入。减去小量确保我们将0.499和1.499舍入为0和1,然后在除以二时得到正确的结果。提供的两种中点舍入技术,向零和向偶数,都不能满足我们的要求。
public decimal MyRound(decimal input)
{
    return Math.Round(input*2-0.001M, MidpointRounding.AwayFromZero)/2;
}

void Main()
{
    var testvalues = new decimal[]{0M,0.125M,0.25M,0.375M,0.5M,0.625M,0.75M,0.875M,1M};
    foreach (var value in testvalues)
    {
        Console.WriteLine(String.Format("{0} rounds to {1}",value, MyRound(value)));
    }
}


Output: 
0 rounds to 0
0.125 rounds to 0
0.25 rounds to 0
0.375 rounds to 0.5
0.5 rounds to 0.5
0.625 rounds to 0.5
0.75 rounds to 0.5
0.875 rounds to 1
1 rounds to 1

我应该指出,我使用十进制只是因为我脑海中认为这就是你在使用的(我觉得是因为我的大脑里有“小数位”。这种技术同样适用于双精度浮点数...


1
public double Round(double input)
{
    var rounded = Math.Round(input*2-0.0001)/2;
    return rounded;
}

0
如果溢出不是问题,那么你可以先乘以8,然后四舍五入到最近的1/8;再除以8,得到原始比例。这适用于任何有理分数。
如果溢出是一个问题,你可以利用8是2的幂次方这一事实,并操作位。让我们将位从左(最低有效位)编号为0到右(最高有效位)编号为n-1,其中n将是16或32或64,具体取决于整数大小。使用这个术语,首先存储第2位(4位)。然后将您的数字向右移3位,如果设置了4位,则添加1。这种技术可用于任何精确的2的幂次方分数。
更新:如下面所述,我最初误读了问题。但上面描述的技术仍然有效,尽管细节略有不同。
步骤:
1. 乘以8并转换为整数类型。 2. 先向右移动2位,然后向左移动2位,并通过4位进行四舍五入。 3. 转换回原始浮点类型。
或者,深入研究浮点类型的二进制表示,并直接操作尾数的位。

我认为你误读了。他的数字已经是1/8的倍数了。他想将它们四舍五入为1/2的倍数。 - Chris
@Chris: 是的,我做到了。如果一些细节有所不同,技术方法仍然是相同的。 - Pieter Geerkens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接