2012-07-31 113 views
8

我同时使用Math.Round(a, 2);舍入小数值

当我四舍五入1.275通过2小数点在C#四舍五入的十进制值面临的问题,结果是1.27。 当我为1.375做同样的事情时,结果是1.38。

为什么它不是1.275到1.28?

感谢

+2

对不起,还没有找到截图;-)但是我找到了这个博客:http://weblogs.asp.net/sfurman/archive/2003/03/07/3537。aspx – 2012-07-31 13:18:22

+4

你实际上是在使用'decimal'的值还是使用'double'? – CodesInChaos 2012-07-31 13:24:37

+4

当你说你围绕“小数”值的时候,这有点令人困惑; 'Math.Round(1.275m,2)= 1.28',而如果你使用'double'超载,你在写作时会得到'Math.Round(1.275,2)= 1.27'。问题很可能是由于浮点表示的不准确。 – 2012-07-31 13:25:31

回答

8

我无法重现你的问题:

Math.Round(1.275m, 2) => 1.28m 
Math.Round(1.375m, 2) => 1.38m 

我怀疑你的要求,你使用decimal值是假的,那你用double值来代替。 double不能精确地表示许多十进制值,所以当你写1.275时,它实际上是1.27499 ... 1.375是少数几个可表示的元素之一,所以它实际上是1.375

如果你的代码在乎准确的十进制表示,例如,当你在金钱而工作,你必须使用decimal不是二进制浮点如doublefloat


但是,即使你使用十进制表示,四舍五入出现意外的行为对于很多用户:

Math.Round(1.265m, 2) => 1.26m 
Math.Round(1.275m, 2) => 1.28m 

默认情况下Math.Round使用MidpointRounding.ToEven,也被称为Banker's round。这样可以避免积累总是在.5四舍五入的偏见。

您可以使用Round的过载采用舍入模式,并将其设置为AwayFromZero以获得您期望的行为。

Math.Round(1.275m, 2, MidpointRounding.AwayFromZero) => 1.28m 
+3

如果1.275四舍五入到1.28,这将是解释,但它不。 – Guffa 2012-07-31 13:20:33

+0

'1.275m'与'1.275'不一样。 OP要求“1.275”。 – ken2k 2012-07-31 13:28:31

+0

“问题”是可重复的,只是不要将其转换为十进制 – Icarus 2012-07-31 13:30:41

2

这是一个可怕的黑客,而是尝试使用格式。它莫名其妙地使用我们都习惯的四舍五入。

Val(Format(2.25, "0.0")) returns 2.3 

(OR)

只为信息:从.NET版本2.0其可以定义“0.5案件”与参数MidpointRounding四舍五入的方式。它可以是ToEven或AwayFromZero。因此,“标准”舍入将如下所示:

Math.Round(2.25, 1, MidpointRounding.AwayFromZero); 

这将返回值“2.3”。

7

MSDN有这对于这种行为说:

注呼叫者

由于精度损失可能导致从 表示十进制值作为浮点数或执行 的对浮点值进行算术运算,在某些情况下,圆形(Double,Int32)方法可能不会出现以将中点值舍入为 数字中最接近的偶数值decimal decimal posi灰。这是在以下示例中说明的 ,其中2.135四舍五入为2.13 而不是2.14。这是因为内部方法将 值乘以10 数字,并且在这种情况下 的乘法运算遭受精度损失。

public class Example 
{ 
    public static void Main() 
    { 
     double[] values = { 2.125, 2.135, 2.145, 3.125, 3.135, 3.145 }; 
     foreach (double value in values) 
     Console.WriteLine("{0} --> {1}", value, Math.Round(value, 2)); 

    } 
} 
// The example displays the following output: 
//  2.125 --> 2.12 
//  2.135 --> 2.13 
//  2.145 --> 2.14 
//  3.125 --> 3.12 
//  3.135 --> 3.14 
//  3.145 --> 3.14 
+1

如果该方法返回不正确的结果,因为它在内部执行某些不准确的操作,则实现不正确。更有可能的是,MSDN文档是错误的,Math.Round返回一个意外的结果,因为调用者没有意识到他们传递的值并不是他们想象的。例如,在这里提出的问题中,调用者没有通过1.275,而是通过了略低于1.275的值。 **在调用Math.Round之前发生错误**,而不是**在**中。 – 2012-07-31 16:59:02

4

如果你有Decimal值,使其能正确一轮1.2751.28

如果您有Double值,它将不会表现相同,因为值1.275无法完全表示。如果您使用double的值1.275,它实际上会比精确值1.275略小,如1.2749999999999999

四舍五入时,该值在1.271.28之间并不会很快,但会略微接近1.27,因此它会向下舍入而不是向上。

1

这是因为你的四舍五入双,而不是一个小数:

Console.WriteLine(Math.Round(1.275M, 2)); // outputs 1.28 
Console.WriteLine(Math.Round(1.375M, 2)); // outputs 1.38 

小数和双打有很大的不同每个文档

+1

什么与downvote和没有评论? – 2012-07-31 15:22:38

0

预期的行为。

例如,如果小数等于1,2.15和2.15000都 圆形至2.2,因为0.05和0.05000是0.1和 0.2中途两者之间,并且0.1为奇数。同样,如果小数等于1,则2.05和 2.05000都舍入为2.0,因为.05和.05000都在.0和.1之间,并且.0为偶数。这种方法的行为遵循IEEE标准754第4部分。这种取整有时称为舍入到最近或舍入四舍五入。它通过在单个方向上始终舍入中点值来最小化舍入误差。要控制Round(Decimal,Int32)方法所使用的舍入类型 ,请调用 Decimal.Round(Decimal,Int32,MidpointRounding)重载。

Math.Round(decimal, int)。尝试

Decimal.Round(a, 2, MidpointRounding.AwayFromZero);