c#实现的T-SQL round函数

本文关键字:round 函数 T-SQL 实现 | 更新日期: 2023-09-27 18:06:01

我试图在c#中重现T-SQL Round函数在使用截断函数时的行为。

这是我试图在c#中重现的SQL行为:

SELECT ROUND(150.757,2,0) -- 150.76
SELECT ROUND(150.757,2,1) -- 150.75
SELECT ROUND(150.747,2,0) -- 150.75
SELECT ROUND(150.747,2,1) -- 150.74

System.Math中,我尝试使用了两种方法。

第一个,Math.Truncate只截断到整个部分,所以它对我没有帮助。

另一种方法是Math.Round

这个方法有两个有趣的重载。

Math.Round(decimal,int)
Math.Round(decimal,int,System.MidpointRounding)

MidpointRounding枚举选项为:

System.MidpointRounding.AwayFromZero
// When a number is halfway between two others, 
// it is rounded toward the nearest number that is away from zero.
System.MidpointRounding.ToEven
// When a number is halfway between two others,
// it is rounded toward the nearest even number.

使用与SQL相同的数据执行Math.Round的两个过载,我得到了以下结果:

Math.Round(150.757, 2, MidpointRounding.AwayFromZero) // 150.76
Math.Round(150.757, 2, MidpointRounding.ToEven) // 150.76
Math.Round(150.747, 2, MidpointRounding.AwayFromZero) // 150.75
Math.Round(150.747, 2, MidpointRounding.ToEven) // 150.75
如果没有midpointrouning解决我的问题,在c#中重现T-SQL函数的最佳方法是什么?

更新:

在实现Paul的答案后,我注意到T-SQL ROUND函数的一个额外的奇怪行为:

SELECT ROUND(150.747,-2,1) // 100
SELECT ROUND(150.747,-2) // 200

我对Paul的回答进行了编辑,以支持这种边缘情况。

c#实现的T-SQL round函数

我想有人会想出一个更好的方法,但这肯定是一个可能的方法!

using System;
static class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(150.757.TruncateWithDecimalPlaces(2));
        Console.WriteLine(150.747.TruncateWithDecimalPlaces(2));
        Console.Read();
    }
    public static double TruncateWithDecimalPlaces(this double input, int decimalPlaces)
    {
        double factor = Math.Pow(10, decimalPlaces);
        return Math.Truncate(input*factor)/factor;
    }
}
输出:

150.75
150.74

一个更完整的实现应该是这样的:

public static double Round(double input, int decimalPlaces, int roundType = 0)
{
    double factor = Math.Pow(10, decimalPlaces);
    if (roundType == 0)
    {
        if (decimalPlaces >= 0)
        {
            return Math.Round(input, decimalPlaces);
        }
        return Math.Round(input * factor) / factor;
    }
    return Math.Truncate(input * factor) / factor;
}

我对Paul的回答做了一些详细阐述,以便他的方法提供与TSQL的round相同的行为(顺便说一下,我没有将我的版本作为扩展方法):

    using System;
    namespace TestTSql
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine(TSqlRound(150.757, 2, false));    // 150.76
                Console.WriteLine(TSqlRound(150.757, 2, true));     // 150.75
                Console.WriteLine(TSqlRound(150.747, 2, false));    // 150.75
                Console.WriteLine(TSqlRound(150.747, 2, true));     // 150.74
                Console.ReadKey();
            }
            public static double TSqlRound(double input, int length, bool truncate = false)
            {
                if (truncate)
                {
                    double factor = Math.Pow(10, length);
                    return Math.Truncate(input * factor) / factor;
                }
                else return Math.Round(input, length);
            }
        }
    }