内置.Net算法,将值四舍五入到最接近的10个区间
本文关键字:最接近 10个 区间 四舍五入 Net 算法 内置 | 更新日期: 2023-09-27 17:48:50
如何在C#中将任何值四舍五入到10的区间?例如,如果我有11,我希望它返回10;如果我有136,我希望其返回140。
我可以很容易地用手
return ((int)(number / 10)) * 10;
但我正在寻找一种内置算法来完成这项工作,比如Math.Round()。我不想手工完成的原因是,我不想在我的项目中编写相同或相似的代码,即使是像上面这样简单的代码。
类库中没有内置函数可以执行此操作。最接近的是System.Math.Round(),它仅用于将Decimal和Double类型的数字四舍五入到最接近的整数值。但是,如果您使用的是.NET3.5,则可以将语句封装在扩展方法中,这将使您能够更干净地使用该函数。
public static class ExtensionMethods
{
public static int RoundOff (this int i)
{
return ((int)Math.Round(i / 10.0)) * 10;
}
}
int roundedNumber = 236.RoundOff(); // returns 240
int roundedNumber2 = 11.RoundOff(); // returns 10
如果您是针对.NET框架的旧版本进行编程,只需从RoundOff函数中删除"this",然后调用这样的函数:
int roundedNumber = ExtensionMethods.RoundOff(236); // returns 240
int roundedNumber2 = ExtensionMethods.RoundOff(11); // returns 10
使用Math.Ciling始终向上取整。
int number = 236;
number = (int)(Math.Ceiling(number / 10.0d) * 10);
模数(%)得到余数,所以你得到:
// number = 236 + 10 - 6
将其放入扩展方法
public static int roundupbyten(this int i){
// return i + (10 - i % 10); <-- logic error. Oops!
return (int)(Math.Ceiling(i / 10.0d)*10); // fixed
}
// call like so:
int number = 236.roundupbyten();
以上编辑:我应该用我的第一直觉去使用数学天花板
在计算UPC校验位数时,我在博客上写过这方面的内容。
这可能有点太晚了,但我想有一天这可能会有很好的帮助。。。
我试过这个:
public int RoundOff(int number, int interval){
int remainder = number % interval;
number += (remainder < interval / 2) ? -remainder : (interval - remainder);
return number;
}
使用:
int number = 11;
int roundednumber = RoundOff(number, 10);
通过这种方式,您可以选择间隔的一半是向上取整还是向下取整。=)
将浮点值四舍五入为整数类似于(int)(x+0.5),而不是简单地强制转换x-如果你想要10的倍数,你可以很容易地调整它。
如果你只想做整数运算,并将其四舍五入到十,请尝试(x+10/2)/10*10。
编辑:我注意到这个回复不符合原作者的要求,也是一种有偏见的四舍五入形式,我不喜欢这样做。然而,另一个公认的回复已经说明了Math.round(),这是一个更好的解决方案。
老问题,但这里有一种方法可以完成所问的内容,而且我扩展了它,可以将任何数字四舍五入到您想要的sig图的数量。
private double Rounding(double d, int digits)
{
int neg = 1;
if (d < 0)
{
d = d * (-1);
neg = -1;
}
int n = 0;
if (d > 1)
{
while (d > 1)
{
d = d / 10;
n++;
}
d = Math.Round(d * Math.Pow(10, digits));
d = d * Math.Pow(10, n - digits);
}
else
{
while (d < 0.1)
{
d = d * 10;
n++;
}
d = Math.Round(d * Math.Pow(10, digits));
d = d / Math.Pow(10, n + digits);
}
return d*neg;
}
private void testing()
{
double a = Rounding(1230435.34553,3);
double b = Rounding(0.004567023523,4);
double c = Rounding(-89032.5325,2);
double d = Rounding(-0.123409,4);
double e = Rounding(0.503522,1);
Console.Write(a.ToString() + "'n" + b.ToString() + "'n" +
c.ToString() + "'n" + d.ToString() + "'n" + e.ToString() + "'n");
}
我不喜欢引入Math
库,也不喜欢使用浮点,所以我的建议是只做下面的整数运算,四舍五入到下一个1K。如果不想重复,请将其封装在方法或lambda片段中。
int MyRoundedUp1024Int = ((lSomeInteger + 1023) / 1024) * 1024;
我还没有用这种方法与其他方法进行性能测试,但我敢打赌,这是最快的方法,也许可以节省比特的移位和旋转版本。
以下是我如何在不从整型转换为浮点值的情况下四舍五入到任意因子的最接近倍数。这适用于从int.MinValue + 1
到int.MaxValue
的任何int
我使用了舍入半离零方程Round(x) = sgn(x)*Floor(Abs(x) + 0.5)
,事实上Floor(z) = z - (z%1)
,以及我想要的输出方程F(value, factor) = Round(value/factor)*factor
来导出一个不需要精确小数除法的方程。
public static int RoundToNearestMultipleOfFactor(this int value, int factor)
{
if (factor == 0)
{
throw new ArgumentOutOfRangeException(nameof(factor), factor, "Cannot be zero");
}
var halfAbsFactor = Math.Abs(factor) >> 1;
return value + Math.Sign(value) * (halfAbsFactor - (Math.Abs(value) % factor + halfAbsFactor % factor) % factor);
}
以下是整个扩展方法类,其中包含int
和long
的方法,以及仅向零或远离零取整的方法。
/// <summary>
/// Extension methods for rounding integral numeric types
/// </summary>
public static class IntegralRoundingExtensions
{
/// <summary>
/// Rounds to the nearest multiple of a <paramref name="factor"/> using <see cref="MidpointRounding.AwayFromZero"/> for midpoints.
/// <para>
/// Performs the operation Round(value / factor) * factor without converting to a floating type.
/// </para>
/// </summary>
/// <param name="value">The value to round.</param>
/// <param name="factor">The factor to round to a multiple of. Must not be zero. Sign does not matter.</param>
/// <remarks>
/// Uses math derived from the <see href="https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero">Round half away from zero equation</see>: y = sgn(x)*Floor(Abs(x) + 0.5) and floor equation: Floor(z) = z - (z % 1)
/// </remarks>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="factor"/> is zero</exception>
/// <seealso cref="MidpointRounding"/>
public static long RoundToNearestMultipleOfFactor(this long value, long factor)
{
if (factor == 0)
{
throw new ArgumentOutOfRangeException(nameof(factor), factor, "Cannot be zero");
}
var halfAbsFactor = Math.Abs(factor) >> 1;
// return value + Math.Sign(value) * (halfAbsFactor - ((Math.Abs(value) + halfAbsFactor) % factor));
//fix overflow
return value + Math.Sign(value) * (halfAbsFactor - (Math.Abs(value) % factor + halfAbsFactor % factor) % factor);
}
/// <summary>
/// Round to the nearest multiple of <paramref name="factor"/> with magnitude less than or equal to <paramref name="value"/>.
/// </summary>
/// <param name="value">The value to round.</param>
/// <param name="factor">The factor to round to a multiple of. Must not be zero. Sign does not matter.</param>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="factor"/> is zero</exception>
public static long RoundToMultipleOfFactorTowardZero(this long value, long factor)
{
if (factor == 0)
{
throw new ArgumentOutOfRangeException(nameof(factor), factor, "Cannot be zero");
}
var remainder = value % factor; // negative iff value is negative
if (remainder == 0)
{
return value;
}
return value - remainder;
}
/// <summary>
/// Round to the nearest multiple of <paramref name="factor"/> with magnitude greater than or equal to <paramref name="value"/>.
/// </summary>
/// <param name="value">The value to round.</param>
/// <param name="factor">The factor to round to a multiple of. Must not be zero. Sign does not matter.</param>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="factor"/> is zero</exception>
public static long RoundToMultipleOfFactorAwayFromZero(this long value, long factor)
{
if (factor == 0)
{
throw new ArgumentOutOfRangeException(nameof(factor), factor, "Cannot be zero");
}
var remainder = value % factor; // negative iff value is negative
if (remainder == 0)
{
return value;
}
return value - remainder + Math.Sign(value) * Math.Abs(factor);
}
/// <summary>
/// Rounds to the nearest multiple of a <paramref name="factor"/> using <see cref="MidpointRounding.AwayFromZero"/> for midpoints.
/// <para>
/// Performs the operation Round(value / factor) * factor without converting to a floating type.
/// </para>
/// </summary>
/// <param name="value">The value to round.</param>
/// <param name="factor">The factor to round to a multiple of. Must not be zero. Sign does not matter.</param>
/// <remarks>
/// Uses math derived from the <see href="https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero">Round half away from zero equation</see>: y = sgn(x)*Floor(Abs(x) + 0.5) and floor equation: Floor(z) = z - (z % 1)
/// </remarks>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="factor"/> is zero</exception>
/// <seealso cref="MidpointRounding"/>
public static int RoundToNearestMultipleOfFactor(this int value, int factor)
{
if (factor == 0)
{
throw new ArgumentOutOfRangeException(nameof(factor), factor, "Cannot be zero");
}
var halfAbsFactor = Math.Abs(factor) >> 1;
// return value + Math.Sign(value) * (halfAbsFactor - ((Math.Abs(value) + halfAbsFactor) % factor));
//fix overflow
return value + Math.Sign(value) * (halfAbsFactor - (Math.Abs(value) % factor + halfAbsFactor % factor) % factor);
}
/// <summary>
/// Round to the nearest multiple of <paramref name="factor"/> with magnitude less than or equal to <paramref name="value"/>.
/// </summary>
/// <param name="value">The value to round.</param>
/// <param name="factor">The factor to round to a multiple of. Must not be zero. Sign does not matter.</param>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="factor"/> is zero</exception>
public static int RoundToMultipleOfFactorTowardZero(this int value, int factor)
{
if (factor == 0)
{
throw new ArgumentOutOfRangeException(nameof(factor), factor, "Cannot be zero");
}
var remainder = value % factor; // negative iff value is negative
if (remainder == 0)
{
return value;
}
return value - remainder;
}
/// <summary>
/// Round to the nearest multiple of <paramref name="factor"/> with magnitude greater than or equal to <paramref name="value"/>.
/// </summary>
/// <param name="value">The value to round.</param>
/// <param name="factor">The factor to round to a multiple of. Must not be zero. Sign does not matter.</param>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="factor"/> is zero</exception>
public static int RoundToMultipleOfFactorAwayFromZero(this int value, int factor)
{
if (factor == 0)
{
throw new ArgumentOutOfRangeException(nameof(factor), factor, "Cannot be zero");
}
var remainder = value % factor; // negative iff value is negative
if (remainder == 0)
{
return value;
}
return value - remainder + Math.Sign(value) * Math.Abs(factor);
}
}
据我所知,没有一个本地内置的c#库可以将整数四舍五入到最接近的十位。
如果您使用的是c#8或更高版本,您可以创建一些小的switch表达式实用程序方法,这些方法可以做很多很酷的有用的事情。如果您使用的是旧版本,则可以使用if/else
和switch case
块:
public static int RoundIntToTens(int anInt)
=> (anInt, (anInt < 0 ? 0 - anInt : anInt) % 10) switch
{
// If int needs to be "round down" and is negative or positive
(>= 0, < 5) or (< 0, < 5) => anInt - anInt % 10,
// If int needs to be "round up" and is NOT negative (but might be 0)
(>= 0, >= 5) => anInt + (10 - anInt % 10),
// If int needs to be "round up" and is negative
(< 0, >= 5) => anInt - (10 + anInt % 10)
};
你必须在使用它的地方导入它,但任何库都是这样,除非有办法将类添加到全局名称空间。