首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >.NET Math.Round(<double>、<int>、MidpointRounding.AwayFromZero)无法正常工作

.NET Math.Round(<double>、<int>、MidpointRounding.AwayFromZero)无法正常工作
EN

Stack Overflow用户
提问于 2012-12-27 21:38:24
回答 2查看 1.6K关注 0票数 6

我正在使用Visual Studio Professional 2012。我创建了一个新的C# ConsoleApplication,目标是.NET Framework4.5,代码如下:

代码语言:javascript
运行
复制
    static void Main(string[] args)
    {
        double x = 2.44445;
        double y = Math.Round(x, 4, MidpointRounding.AwayFromZero);
        Console.WriteLine(y);
        Console.ReadKey();
    }

预期结果应该是2.4445,但实际返回2.4444。//和以前的框架版本结果一样,我尝试了VCE2010。

我知道这样的问题通常源于存储双精度数据类型的方式(即将有限小数转换为无限二进制分数)。但我没想到这会发生在只有5位小数的情况下,比如2.44445

我担心这样的事情会不会发生在更短的小数点上。我还想学习一种更安全的在C#中舍入(使用远离零约定)的方法。谢谢。

EN

回答 2

Stack Overflow用户

发布于 2012-12-27 21:45:10

这确实是由于浮点数的脆弱精度造成的。0.5可以完美地存储在IEEE浮点中,但0.45、0.445等不能。例如,指定2.44445时存储的实际值是11009049289107177/4503599627370496,即2.44449999999999989519494647...现在应该很明显为什么数字是这样四舍五入的。

如果需要精确地存储小数,请考虑使用decimal类型。

票数 11
EN

Stack Overflow用户

发布于 2012-12-27 21:47:00

Notes from msdn

由于将十进制值表示为浮点数或对浮点值执行算术运算可能会导致精度损失,因此在某些情况下,

(Double,Int32,MidpointRounding)方法可能不会按照模式参数的指定对中点值进行舍入。下面的示例说明了这一点,其中2.135四舍五入为2.13,而不是2.14。这是因为在内部,该方法将值乘以10位数,而本例中的乘法操作会损失精度

这是如何实现的圆周:

代码语言:javascript
运行
复制
double num = roundPower10Double[digits];
value *= num;
if (mode == MidpointRounding.AwayFromZero)
{
    double num2 = SplitFractionDouble(&value);
    if (Abs(num2) >= 0.5)
    {
        value += Sign(num2);
    }
}

如您所见,value与num相乘,num是

代码语言:javascript
运行
复制
roundPower10Double = new double[] { 1.0, 10.0, 100.0, 1000.0, 10000.0, 
      100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000,  
      100000000000, 1000000000000, 10000000000000, 100000000000000, 1E+15 };    

所以,实际上你有给出0,4999999999963622.44445 * 10000.0 - 24444,0。这比0.5还小。这样就有了2.4444

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14055611

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档