我正在尝试使用截断函数在C#中重现T-SQL Round function的行为。
这是我试图在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
鉴于MidpointRounding没有解决我的问题,在C#中重现T-SQL函数的最佳方法是什么?
更新
在实现Paul的回答后,我注意到T-SQL ROUND函数有一个奇怪的行为:
SELECT ROUND(150.747,-2,1) // 100
SELECT ROUND(150.747,-2) // 200
我编辑了Paul的答案,包括支持这个边缘案例。
答案 0 :(得分:5)
我想有人会想出一个更好的方法,但这肯定是一种可能的方式!
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;
}
答案 1 :(得分:2)
我已经详细阐述了Paul的答案,以便他的方法提供与TSQL轮次相同的行为(顺便说一下,我没有让我的版本成为扩展方法):
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);
}
}
}