在C#中向下舍入至小数点后两位

48

我该如何计算两个小数并将结果向下舍入至小数点后两位?

例如,如果方程式为 41.75 x 0.1,则结果将为 4.175。如果我在 C# 中使用 decimal 进行计算,它会自动四舍五入到 4.18。但我希望将其向下取整为 4.17。

我尝试使用 Math.Floor,但它只会将结果舍入到 4.00。以下是示例:

Math.Floor (41.75 * 0.1);

你尝试过使用 Math.Round 吗? - nhahtdh
2
如果您想进行四舍五入,可以使用 Math.Round 的重载版本来控制如何处理中间值。如果您希望始终向下取整,考虑将数字乘以 100,然后向下取整,最后再除以 100。 - John
你想对4.176及以上进行标准舍入吗? - Mark Hall
我刚刚在LINQPad中尝试了一下,当我将41.75乘以0.1时,得到的结果是4.175。我尝试过使用Decimals和Doubles。 - Francis Gagnon
抱歉,应该是41.75 * 0.1。 - startupsmith
简短的答案是: Math.Round(41.75 * 0.1, 2, MidpointRounding.ToNegativeInfinity) 这将给你所需的精度下取整,第二个参数是精度,第三个参数是舍入策略。 - mahdi yousefi
9个回答

71

Math.Round(...)函数有一个枚举值,决定使用哪种舍入策略。不幸的是,两种定义好的模式都不完全适合您的情况。

这两种中间值舍入模式为:

  1. AwayFromZero - 当一个数字恰好在两个数字的中间时,它会被舍入到离0更远的那个数字。(也就是四舍五入)
  2. ToEven - 当一个数字恰好在两个数字的中间时,它会被舍入到最接近的偶数。(如果是.16将会取舍到.16, 如果是.17将会取舍到.18)

您想要使用的是使用一些乘法的Floor函数。

var output = Math.Floor((41.75 * 0.1) * 100) / 100;

output 变量现在应该包含 4.17。

事实上,您也可以编写一个函数来接受变量长度:

public decimal RoundDown(decimal i, double decimalPlaces)
{
   var power = Convert.ToDecimal(Math.Pow(10, decimalPlaces));
   return Math.Floor(i * power) / power;
}

2
实际上,应该使用Math.Round方法(Decimal,Int32,MidpointRounding)重载来解决问题(请参见https://dev59.com/IGYr5IYBdhLWcg3wn7kc)。 - Mat M
i * power是一个错误。你可能指的是double。 - sandeep talabathula
你不能用一个小数去乘以一个浮点数。 - Ruan
MidpointRounding重载可以解决.5向下舍入而不是向上的问题(如果有一个名为“TowardZero”的策略),但我认为提问者举了一个不好的例子。他们的问题表明他们希望所有数字都舍入到2位小数以下。因此,4.179999999将变成4.17。如果您只想要中点向下舍入,那么应该使用该重载,但如果您想要所有数字向下舍入,您需要使用上述技术或其他答案中的类似技术。 - Brandon Barkley
1
这已经将近8年了。这仍然是最好的答案吗? - softarn
注意!根据设备的不同,这可能导致准确性问题。当尝试将此函数应用于保留两位小数的值10.40时,在使用Xamarin的Android设备上得到的结果为10.39。 - Jonathan Queipo

19
public double RoundDown(double number, int decimalPlaces)
{
     return Math.Floor(number * Math.Pow(10, decimalPlaces)) / Math.Pow(10, decimalPlaces);
}

1
注意!根据设备的不同,这可能会导致精度问题。当我在使用Xamarin的Android设备上尝试将此函数应用于保留两位小数的值10.40时,结果为10.39。 - Jonathan Queipo

18

.NET Core 3.0开始和即将推出的.NET Framework 5.0,以下是有效的。

Math.Round(41.75 * 0.1, 2, MidpointRounding.ToZero)

1
我曾犹豫过使用这个特性,因为我阅读的文档中描述了“两个数字之间的中间数”,但是根据您对负数的要求,这确实可以正确回答问题。您也可以考虑使用ToNegativeInfinity函数。 - SteveC

9

C# 中没有原生支持精度向下取整和向上取整的功能。

但是,您可以通过将数字乘以倍数、向下取整,然后再除以同样的倍数来模拟这个功能。

例如:

decimal y = 4.314M;
decimal x = Math.Floor(y * 100) / 100;  // To two decimal places (use 1000 for 3 etc)
Console.WriteLine(x);  // 4.31

这不是最理想的解决方案,但如果数字较小,则应该可以工作。


1
如果您想将任何双精度数值舍入到特定的小数位,无论是否为中间值,都可以使用以下代码:

    public double RoundDownDouble(double number, int decimaPlaces)
    {
        var tmp = Math.Pow(10, decimaPlaces);
        return Math.Truncate(number * tmp) / tmp;
    }

1
另一个解决方案是将四舍五入改为向零舍入。 应该像这样:
    static decimal DecimalTowardZero(decimal value, int decimals)
    {
        // rounding away from zero
        var rounded = decimal.Round(value, decimals, MidpointRounding.AwayFromZero);

        // if the absolute rounded result is greater 
        // than the absolute source number we need to correct result
        if (Math.Abs(rounded) > Math.Abs(value))
        {
            return rounded - new decimal(1, 0, 0, value < 0, (byte)decimals);
        }
        else
        {
            return rounded;
        }
    }

0

简单地说,Math.Round()解决了这个问题,并且通过传递precision参数和MidpointRounding参数来适应情况。

简短的答案是:
Math.Round(41.75 * 0.1, 2, MidpointRounding.ToNegativeInfinity)
其中第二个参数是精度,第三个参数是舍入策略。

如果你想要了解Math.Round的工作原理,你可以在这里阅读完整的解释: 如何在C#中将数字四舍五入到两位小数?


0

这是我的浮点数向下取整。

    public static class MyMath
{
    public static double RoundDown(double number, int decimalPlaces)
    {
        string pr = number.ToString();
        string[] parts = pr.Split('.');
        char[] decparts = parts[1].ToCharArray();
        parts[1] = "";
        for (int i = 0; i < decimalPlaces; i++)
        {
            parts[1] += decparts[i];
        }
        pr = string.Join(".", parts);
        return Convert.ToDouble(pr);
    }
}

0
我发现最好的方法是使用字符串;否则,Math的二进制变数往往会出错。等待.Net 5.0使这个事实过时。没有小数位是一个特殊情况:你可以使用Math.Floor。否则,我们将数字ToString为比所需位数多一个小数位,然后解析它而不包括其最后一位数字以获得答案:
/// <summary>
/// Truncates a Double to the given number of decimals without rounding
/// </summary>
/// <param name="D">The Double</param>
/// <param name="Precision">(optional) The number of Decimals</param>
/// <returns>The truncated number</returns>
public static double RoundDown(this double D, int Precision = 0)
{
  if (Precision <= 0) return Math.Floor(D);
  string S = D.ToString("0." + new string('0', Precision + 1));
  return double.Parse(S.Substring(0, S.Length - 1));
}

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