ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – 如何在此三角区域计算中避免舍入误差?

2019-08-29 06:14:00  阅读:187  来源: 互联网

标签:java floating-point precision area


我试图用顶点计算三角形的面积

{{0,1000000000},{1,0},{0,-1000000000}}

很容易看出这个三角形的面积应该是1,000,000,000,但是当我尝试使用Heron公式或Shoelace公式计算Java中的面积时,我得到该区域的0.

我很确定这是由于使用双打时的舍入误差,但我不知道如何继续.有什么指针吗?

程序:

private static double areaShoelace(int[][] v) {
    return 0.5 * Math.abs(v[0][0]*v[1][1] + v[1][0]*v[2][1] + v[2][0]*v[0][1] +
            v[1][0]*v[0][1] + v[2][0]*v[1][1] + v[0][0]*v[2][1]);
}

private static double areaHeron(double a, double b, double c) {
    double p = (a + b + c) / 2.0d;
    return Math.sqrt(p * (p - a) * (p - b) * (p - c));
}

private static double length(int[] a, int [] b) {
    return Math.hypot(a[0] - b[0], a[1] - b[1]);
}

public static void main(String[] args) {
    int[][] tri = new int[][]{{0,1000000000},{1,0},{0,-1000000000}};
    System.out.println(areaShoelace(tri));
    System.out.println(areaHeron(length(tri[0], tri[1]), length(tri[1],tri[2]), length(tri[0],tri[2])));
}

输出:

0.0
0.0

解决方法:

这里实际上有2个不同的错误.

在你的shoelace formula实现中,一些迹象是不正确的(一半应该是负面的).一旦你解决了这个问题,你应该在这种情况下得到正确的答案,但是你应该注意到乘法和加法是使用整数运算来执行的,这可能会导致大数字溢出.

如果将这些更改为浮点运算,将它们分组以减少运算次数和破坏性取消的可能性也是有意义的,我建议

0.5*Math.abs(v[0][0]*(v[1][1] - v[2][1]) + v[1][0]*(v[2][1] - v[0][1]) +
        v[2][0]*(v[0][1] - v[1][1]))

Heron公式的数值问题已得到很好的证实,并由浮点数大师William Kahan解释:Miscalculating Area and Angles of a Needle-like Triangle.

但是在这种情况下,你的问题甚至在此之前就出现了:Math.hypot(1,1000000000)的结果在数值上等于1000000000(剩余的数字会丢失到浮点舍入),因此当输入到Heron的公式时(即使精确计算),将给出0.

标签:java,floating-point,precision,area
来源: https://codeday.me/bug/20190829/1758182.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有