.net 为什么Math.Round(2.5)返回2而不是3?
在C#中,.net 为什么Math.Round(2.5)返回2而不是3?,.net,rounding,.net,Rounding,在C#中,Math.Round(2.5)的结果是2 应该是3,不是吗?为什么在C#?中是2,这被称为舍入到偶数(或银行家舍入),这是一种有效的舍入策略,可以最大限度地减少总和中的累积错误(middpointrounding.ToEven)。理论是,如果你总是在同一个方向上取整0.5个数字,那么误差会更快地累积(取整到偶数应该是为了最小化这一点)(a) 有关以下各项的MSDN说明,请访问以下链接: ,向负无穷大方向舍入 ,它向正无穷大进位 ,向上或向下舍入到零 ,它舍入到最接近的整数或指定的小数
Math.Round(2.5)
的结果是2
应该是3,不是吗?为什么在C#?中是2,这被称为舍入到偶数(或银行家舍入),这是一种有效的舍入策略,可以最大限度地减少总和中的累积错误
(middpointrounding.ToEven)
。理论是,如果你总是在同一个方向上取整0.5个数字,那么误差会更快地累积(取整到偶数应该是为了最小化这一点)(a)
有关以下各项的MSDN说明,请访问以下链接:
- ,向负无穷大方向舍入
- ,它向正无穷大进位
- ,向上或向下舍入到零
- ,它舍入到最接近的整数或指定的小数位数。如果两种可能性之间的距离正好相等,则可以指定该行为,例如舍入使最后一个数字为偶数(
“变为2”)或使其远离零(舍入(2.5,中点舍入.ToEven)
“变为3”)舍入(2.5,中点舍入.AwayFromZero)
-3 -2 -1 0 1 2 3
+--|------+---------+----|----+--|------+----|----+-------|-+
a b c d e
a=-2.7 b=-0.5 c=0.3 d=1.5 e=2.8
====== ====== ===== ===== =====
Floor -3 -1 0 1 2
Ceiling -2 0 1 2 3
Truncate -2 0 0 1 2
Round(ToEven) -3 0 0 2 3
Round(AwayFromZero) -3 -1 0 2 3
请注意,Round
比它看起来强大得多,因为它可以舍入到特定的小数位数。所有其他的整数总是小数点零。例如:
n = 3.145;
a = System.Math.Round (n, 2, MidpointRounding.ToEven); // 3.14
b = System.Math.Round (n, 2, MidpointRounding.AwayFromZero); // 3.15
对于其他函数,您必须使用乘法/除法技巧来实现相同的效果:
c = System.Math.Truncate (n * 100) / 100; // 3.14
d = System.Math.Ceiling (n * 100) / 100; // 3.15
(a) 当然,该理论取决于这样一个事实,即数据在偶数部分(0.5、2.5、4.5等)和奇数部分(1.5、3.5等)之间的值分布相当均匀 如果所有“一半值”都是偶数(例如),则错误累积的速度将与您总是四舍五入一样快。来自MSDN: 默认情况下,Math.Round使用 中点四舍五入。大多数人 不熟悉“舍入到” 甚至“作为替代方案”,四舍五入 “远离零”更常见 在学校教书。净额默认为 按原样“四舍五入到相等” 统计上优越,因为它 不赞成 “从零开始四舍五入”到四舍五入 比它更频繁一些 向下(假设数字为 四舍五入往往是积极的。)
这篇文章有你想要的答案: 基本上是这样说的: 返回值 精度等于数字的最接近值的数字。如果值介于两个数字之间,其中一个是偶数,另一个是奇数,则返回偶数。如果值的精度小于位数,则返回的值将保持不变 该方法的行为遵循IEEE标准754第4节。这种四舍五入有时被称为四舍五入到最近值,或银行家四舍五入。如果数字为零,这种舍入有时称为向零舍入。舍入的本质 考虑将包含分数的数字四舍五入为整数的任务。在这种情况下,舍入的过程是确定哪个整数最能代表要舍入的数字
public double ArithRound(double number,int places){
string numberFormat = "###.";
numberFormat = numberFormat.PadRight(numberFormat.Length + places, '#');
return double.Parse(number.ToString(numberFormat));
}
通常,或“算术”四舍五入,很明显2.1、2.2、2.3和2.4四舍五入为2.0;及2.6,2.7,2.8及2.9至3.0
剩下的是2.5,与3.0相比,2.5更接近2.0。由您在2.0和3.0之间进行选择,两者都同样有效
对于负数,-2.1,-2.2,-2.3和-2.4,将变为-2.0;和-2.6、2.7、2.8和2.9在算术舍入下将变为-3.0
public double ArithRound(double number,int places){
string numberFormat = "###.";
numberFormat = numberFormat.PadRight(numberFormat.Length + places, '#');
return double.Parse(number.ToString(numberFormat));
}
对于-2.5,需要在-2.0和-3.0之间进行选择
其他形式的舍入
“四舍五入”取任何带小数点的数字,并使其成为下一个“整数”。因此,不仅2.5和2.6轮到3.0,2.1和2.2轮也是如此
向上舍入使正数和负数都远离零。例如2.5到3.0和-2.5到-3.0
“向下舍入”通过切掉不需要的数字来截断数字。这会使数字向零移动。例如2.5到2.0和-2.5到-2.0
在最常见的“银行家四舍五入”形式中,要四舍五入的.5可以向上或向下四舍五入,因此四舍五入的结果始终是偶数。因此,2.5轮到2.0轮,3.5轮到4.0轮,4.5轮到4.0轮,5.5轮到6.0轮,依此类推
“交替舍入”在向下舍入和向上舍入之间交替任何.5的过程
“随机舍入”是在完全随机的基础上向上或向下舍入.5
对称和不对称
如果舍入函数将所有数字舍入到零或将所有数字舍入到零,则称舍入函数为“对称”
如果正数向零舍入,负数向零舍入,则函数是“不对称的”。。例2.5至2.0;和-2.5至-3.0
同样不对称的是一个函数,它将正数从零舍入,负数向零舍入。例2.5至3.0;和-2.5至-2.0
大多数情况下,人们会想到对称舍入,其中-2.5将被舍入到-3.0,3.5将被舍入到4.0。(在C
舍入(AwayFromZero)
)首先,这无论如何都不是一个C#bug,它将是一个.NET bug。C#是一种语言,它不决定如何实现Math.Round
第二,否-如果您阅读,您将看到默认舍入为“舍入到偶数”(银行家舍入):
返回值类型:System.Double
最接近a的整数。如果 a的分数分量是一半 在两个整数之间,其中一个是 偶数和另一个奇数,然后是偶数 返回数字。请注意 方法返回一个
Double
,而不是
整型
备注此方法的行为遵循IEEE标准754, 第4节。这种四舍五入的方法是不正确的 有时称为四舍五入到最近, 或银行家四舍五入。
public double RoundCorrect(double d, int decimals)
{
double multiplier = Math.Pow(10, decimals);
if (d < 0)
multiplier *= -1;
return Math.Floor((d * multiplier) + 0.5) / multiplier;
}
int roundedNumber = (int)Math.Floor(d + 0.5);
public double getRounding(double number, int decimalPoints)
{
double decimalPowerOfTen = Math.Pow(10, decimalPoints);
return Math.Floor(number * decimalPowerOfTen + 0.5)/ decimalPowerOfTen;
}
getRounding(239, -2) = 200
Public Function Round(number As Double, dec As Integer) As Double
Dim decimalPowerOfTen = Math.Pow(10, dec)
If CInt(number * decimalPowerOfTen) = Math.Round(number * decimalPowerOfTen, 2) Then
Return Math.Round(number, 2, MidpointRounding.AwayFromZero)
Else
Return CInt(number * decimalPowerOfTen + 0.5) / 100
End If
End Function
public enum MidpointRounding
{
ToEven,
AwayFromZero
}
public static class DecimalExtensions
{
public static decimal Round(this decimal d, MidpointRounding mode)
{
return d.Round(0, mode);
}
/// <summary>
/// Rounds using arithmetic (5 rounds up) symmetrical (up is away from zero) rounding
/// </summary>
/// <param name="d">A Decimal number to be rounded.</param>
/// <param name="decimals">The number of significant fractional digits (precision) in the return value.</param>
/// <returns>The number nearest d with precision equal to decimals. If d is halfway between two numbers, then the nearest whole number away from zero is returned.</returns>
public static decimal Round(this decimal d, int decimals, MidpointRounding mode)
{
if ( mode == MidpointRounding.ToEven )
{
return decimal.Round(d, decimals);
}
else
{
decimal factor = Convert.ToDecimal(Math.Pow(10, decimals));
int sign = Math.Sign(d);
return Decimal.Truncate(d * factor + 0.5m * sign) / factor;
}
}
}
public int Round(double value)
{
double decimalpoints = Math.Abs(value - Math.Floor(value));
if (decimalpoints > 0.5)
return (int)Math.Round(value);
else
return (int)Math.Floor(value);
}
Math.Ceiling(decimal.Parse(yourNumber + ""));