将数字四舍五入到最近倍数的通用C#方法?(不是重复的,有特定的角度和建议的答案)
我有一个C#扩展方法,如下所示:将数字四舍五入到最近倍数的通用C#方法?(不是重复的,有特定的角度和建议的答案),c#,numerical-methods,C#,Numerical Methods,我有一个C#扩展方法,如下所示: public static double RoundOff(this double rawNumber, double roundToNearest) { double rawMultiples = rawNumber / roundToNearest; double roundedMultiples = Math.Round(rawMultiples); double roundedNumber = roundedMult
public static double RoundOff(this double rawNumber, double roundToNearest)
{
double rawMultiples = rawNumber / roundToNearest;
double roundedMultiples = Math.Round(rawMultiples);
double roundedNumber = roundedMultiples * roundToNearest;
return roundedNumber;
}
我不想为所有不同的数字类型(int、decimal等)编写多次
有没有一种方法可以这样做
public static double RoundOff<T>(this T rawNumber, T roundToNearest)
where T : [SOME CONSTRAINT]
{
T rawMultiples = rawNumber / roundToNearest;
T roundedMultiples = Math.Round(rawMultiples);
T roundedNumber = roundedMultiples * roundToNearest;
return roundedNumber;
}
公共静态双舍入(此T rawNumber,T RONDTONEARest)
其中T:[一些约束]
{
T rawMultiples=rawNumber/roundToNearest;
T roundedMultiples=数学圆(整数倍);
T roundedNumber=roundedMultiples*roundToNearest;
返回舍入数;
}
如果能够更普遍地做到这一点,那将非常有用。要维护的代码更少,而且只需一个扩展方法就可以提供更多的功能
如果不能做到,是不是因为C#不能以这种方式扩展到工作?或者有一天它会被扩展到允许“所有数字类型”通用约束吗
欢迎任何想法
更新
回答关于与另一个问题相似性的问题。是的,它在主题方面是相似的,但不同,因为我追求的是一个特定问题的特定解决方案。我已经在下面添加了我自己的尝试性回答以澄清。如果有人仍然认为我没有抓住要点,欢迎挑战。显然不可能像其他评论员所说的那样,对泛型做你想做的事情,但由于所有数字都可以转换为双倍,你至少可以减少逻辑重复:
public static double RoundOff(this long rawNumber, double roundToNearest)
{
return RoundOff((double) rawNumber, roundToNearest);
}
public static double RoundOff(this double rawNumber, double roundToNearest)
{
T rawMultiples = rawNumber / roundToNearest;
T roundedMultiples = Math.Round(rawMultiples);
T roundedNumber = roundedMultiples * roundToNearest;
return roundedNumber;
}
如果您不使用扩展方法进行管理,那么您可以直接对任何数字调用此方法,因为C#将自动将所有类型转换为double
int i = 5;
RoundOff(i, 0.5);
我承认这个问题与其他问题有一些相似之处,但我的问题是关于解决一个非常具体的问题的非常具体的问题 我想在这里分享我自己的解决方案。从好的方面来说,它是完全通用的。在负数方面,由于使用小数,速度较慢,但如果需要,可以调整为更快的双倍数
public static T RoundOff<T>(this T rawNumber, T roundToNearest)
where T : IComparable<T>
{
if (typeof(T).IsNumericType())
{
decimal decimalRoundToNearest = Convert.ToDecimal(roundToNearest);
decimal rawMultiples = Convert.ToDecimal(rawNumber) / Convert.ToDecimal(roundToNearest);
decimal decimalRoundedMultiples = Math.Round(rawMultiples);
decimal decimalRoundedNumber = decimalRoundedMultiples * decimalRoundToNearest;
return (T)Convert.ChangeType(decimalRoundedNumber, typeof(T));
// alternative
// TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
// return (T)converter.ConvertFrom(decimalRoundedNumber);
}
else
{
throw new Exception("Type " + typeof(T) + " is not numeric");
}
}
它并非没有缺点,但它确实符合我的要求
一个自我批评:因为我们正在舍入,小数的额外精度可能是不必要的——但直觉上,使用高精度类型似乎更好。我可能在这一点上是错的,也许一些更有知识的人可以提供一些见解
因此,我希望这能帮助某人,或激起愤怒的反应,如雪崩般,如何才能做得更好 不存在“数值类型”通用约束。你必须为你想要支持的每一种类型创建重载。你甚至不能声明一个类型参数约束说“这个类型必须支持这些数学运算符”。有些人通过重新编译编译代码来绕过这个问题。可能的副本可能会考虑使用一个T4模板,它可以用特定类型名称替换这个方法,然后使用它来支持<代码>数学类型。无论如何-因此没有必要做更多的事情(int和
long
应该直接调用十进制
一)。而且您的代码对int
无论如何都不起作用,因为/
进行整数除法(换句话说,您不能以通用方式在数字类型中使用代码,因为它对某些类型不起作用)。但是,您可能会对long
失去精度。不确定您的意思是什么,Max long在Max double?double的精度只有52/53位。朗有64岁。这意味着两个相邻的大多头很可能被转换成相同的双倍值。可能没什么大不了的,因为它被四舍五入:)此外,还有一个除法无论如何都不能返回多头。但你可能是对的,在一些特殊情况下,它可能会导致一个错误,当然这是一个有用的想法,但我仍然觉得必须有一个“一刀切”的解决方案。我自己的尝试实现了这一点,尽管有一些自我意识问题。添加了一些有用的参考资料,有人在听吗?有人对提议的答案有想法吗?
public static bool IsNumericType(this object o)
{
// https://stackoverflow.com/questions/1749966/c-sharp-how-to-determine-whether-a-type-is-a-number
switch (Type.GetTypeCode(o.GetType()))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}