当前位置:  开发笔记 > 编程语言 > 正文

.NET上的双精度问题

如何解决《.NET上的双精度问题》经验,为你挑选了5个好方法。

我有一个简单的C#函数:

public static double Floor(double value, double step)
{
    return Math.Floor(value / step) * step;
}

计算较高的数字,低于或等于"值",即"步数"的倍数.但它缺乏精确性,如下面的测试所示:

[TestMethod()]
public void FloorTest()
{
    int decimals = 6;
    double value = 5F;
    double step = 2F;
    double expected = 4F;
    double actual = Class.Floor(value, step);
    Assert.AreEqual(expected, actual);
    value = -11.5F;
    step = 1.1F;
    expected = -12.1F;
    actual = Class.Floor(value, step);
    Assert.AreEqual(Math.Round(expected, decimals),Math.Round(actual, decimals));
    Assert.AreEqual(expected, actual);
}

第一个和第二个断言都可以,但是第三个断言失败,因为结果只等到第6个小数位.这是为什么?有没有办法纠正这个?

更新如果我调试测试我看到值相等,直到第8个小数位而不是第6个,可能是因为Math.Round引入了一些不精确.

注意在我的测试代码中,我写了"F"后缀(显式浮点常量),其中我的意思是"D"(双),所以如果我改变它,我可以有更多的精度.



1> Jon Grant..:

我实际上希望他们没有为浮点数和双精度数实现==运算符.要问一个double或float是否等于任何其他值,几乎总是错误的做法.



2> veggerby..:

计算机上的浮点运算不是Exact Science :).

如果要精确到预定义的小数位数,请使用Decimal而不是double或接受小间隔.


它是IEEE定义的有效数字内的精确科学.
此外,小数可能会遇到与双打相同的问题,因为它们也是浮点数.他们可以遇到相同的表示问题,但它不太出乎意料,因为它们的基数为10,而基数为2,我们习惯于处理基数10中的表示问题(例如1/3是0.333333 ..在基地10).

3> Henk Holterm..:

如果省略所有F后缀(即-12.1代替-12.1F),您将获得更多相等的几位数.您的常量(尤其是预期值)现在是浮动的,因为F.如果您是故意这样做,请解释.

但对于其余的我同意比较双重或浮动值的平等的其他答案,它只是不可靠.



4> Amy B..:

http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

例如,0.1和0.01(二进制)的不可表示性意味着尝试对0.1求平方的结果既不是0.01,也不是最接近它的可表示数。

仅在需要机器对数字系统的解释(二进制)时才使用浮点数。您不能代表10美分。



5> Michael Mead..:

如果需要precision,请使用System.Decimal.如果需要速度,请使用System.Double(或System.Float).浮点数不是"无限精度"数,因此断言相等必须包含容差.只要您的数字具有合理的有效位数,就可以了.

如果你想在非常大和非常小的数字上做数学运算,不要使用float或double.

如果您需要无限精度,请不要使用float或double.

如果要聚合非常多的值,请不要使用float或double(错误会自行复合).

如果您需要速度和尺寸,请使用float或double.

请参阅此答案(也由我),详细分析精度如何影响数学运算的结果.


有无限精确的东西.整数是无限精确的类型.在数学运算期间它没有精确度.可以实现无限精确(尽管非常低效)的十进制类型,但它在.Net中不是"开箱即用".
推荐阅读
kikokikolove
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有