繁体   English   中英

如何在C#中处理精度

[英]How to deal with precision in C#

查找两点之间的积分点数的奇异精度行为不包括:

我正在为此编写一个算法(伪)。

给定x1,y1和x2,y2

我计算了double m,其中m是以(double)(y2-y1)/(x2-x1)给出的线段的斜率,然后我计算了double c,其中c是以y1-(m * x1)给出的y截距

然后对于i = Min(x1,x2)i <Max(x1,x2)对于j = Min(y1,y2)j <Max(y1,y2)如果j =(m * i)+ c,则++

最后,返回结果-1

该代码适用于某些测试用例,但在其他一些用例上却失败,例如,当两个端点彼此垂直时,我必须处理m的无穷大,而处理c的NaN情况。 但是,一个特殊的案例引起了我的注意,分别针对x1,y1和x2,y2的测试案例43,38,17,6。

运行代码j从6开始,而i从17开始,所以这一点肯定在线段上,即使我不应该将其计算在内,因为这是一个终点。 这个值i,j!=(m * i)+ c = 5.9999999999 ...而不是6,这是什么奇怪?这怎么可能? 我在哪里为此失去精度? 更重要的是,我如何失去精度?

码:

        int cnt = 0;
        double i, j;
        double m = (double)(y2 - y1) / (x2 - x1);
        double c = y1 - (m * x1);
        for (i = Math.Min(x1, x2); i <= Math.Max(x1, x2); i++)
        {
            for (j = Math.Min(y1, y2); j <= Math.Max(y1, y2); j++)
            {
                if (j == (m * i) + c||double.IsInfinity(m) && double.IsNaN(c))
                    cnt++;
            }
        }
        return cnt - 2;

所以我将所有变量都更改为十进制,但是不幸的是,我仍然无法通过测试。 但我认为我已经将其缩小到这一点:小数m =(小数)(y2-y1)/(x2-x1);

mcdouble ,因此(m*i)+c将返回double 但是j是一个int 因此,您正在将整数与双精度进行比较。 给定浮点表示形式 ,在进行直接比较时,这将成为一个问题。 您需要将比较的右侧强制转换为整数,或者进行某种非精确比较。 或者,您可以使用非浮点精度的内容,例如decimal ,这不会显示此问题。

双打不能精确。 它们仅精确到一定位数。 请记住,它们使用内部格式以字节存储。 这将不可避免地引起一些精度误差。

甚至更糟的是,即使不进行计算,也无法精确存储您放入双精度值的某些值。

使您知道的示例:可以在此处测试将1.94分配给double变量,结果将为: 1.939999999999999946709294817992486059665679931640625

这是错误的做法,并且注定无法将两个浮点数与相等运算符进行比较。

有关浮点数的重要阅读: 每位计算机科学家都应了解的浮点算法

将无限多个实数压缩为有限数量的位需要近似表示。 尽管有无限多个整数,但是在大多数程序中,整数计算的结果可以存储在32位中。 相反,在给定固定位数的情况下, 大多数使用实数的计算将产生无法使用那么多位数精确表示的数量。 因此,浮点计算的结果通常必须四舍五入,以重新适合其有限表示形式。 舍入误差是浮点计算的特征。

作为解决方案,如果您真的要比较,可以在比较结果之前用Math.round(x, decimals)敏感地舍入结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM