我正在使用Heron的公式来找到三角形的区域。给定边a
,b
和c
,A = √(s(s-a)(s-b)(s-c))
,其中s是半透度(a+b+c)/2
。这个公式应该可以很好地工作,但我注意到Math.pow()和Math.sqrt()给出了不同的结果。为什么会发生这种情况,我该如何解决?
我写了两个方法来查找区域并确定它是否是整数。
在第一种方法中,我取平方根然后乘以它们:
public static boolean isAreaIntegral(long a, long b, long c)
{
double s = (a+b+c)/2.0;
double area = Math.sqrt(s)*Math.sqrt(s-a)*Math.sqrt(s-b)*Math.sqrt(s-c);
return area%1.0==0.0 && area > 0.0;
}
在第二种方法中,我找到了产品,然后取平方根:
public static boolean isAreaIntegral(long a, long b, long c)
{
double s = (a+b+c)/2.0;
double area = Math.pow(s*(s-a)*(s-b)*(s-c),0.5);
return area%1.0==0.0 && area > 0.0;
}
有人可以解释为什么这两个在数学上等价的方法会给出不同的值吗?我正在研究Project Euler Problem 94。我的回答是999990060
第一种方式,996784416
是第二种方式。 (我知道这两个答案都与实际情况相差甚远)
答案 0 :(得分:2)
我肯定会投票支持“舍入问题”,因为你将第一种方法中的多方法调用的结果(每个方法结果都被舍入)与第二种方法中的单一方法调用相乘,其中你只舍入一次
答案 1 :(得分:1)
答案之间的差异大于我的预期。或许它不是。现在已经很晚了,我的数学思想也在不久前崩溃了。
我认为你的问题在于四舍五入。当你将一堆根连在一起时,你的答案会比真实值更进一步。
第二种方法会更准确。 虽然,不一定像欧拉要求的那样准确。 计算器是一个不错的选择。
答案 2 :(得分:0)
这两种方法都存在问题。在比较浮点值(也就是 double 精度浮点值)时,通常应该非常小心。特别是,将计算结果与==
或!=
进行比较几乎总是有问题的(并且通常只是错误)。比较“等于”的两个浮点值应该使用类似
private static boolean isEqual(double x, double y)
{
double epsilon = 1e-8;
return Math.abs(x - y) <= epsilon * Math.abs(x);
// see Knuth section 4.2.2 pages 217-218
}
在这种情况下,浮点余数运算符也不会有所需的结果。请考虑以下经典示例
public class PrecisionAgain
{
public static void main(String[] args)
{
double d = 0;
for (int i=0; i<20; i++)
{
d += 0.1;
}
System.out.println(d);
double r = d%1.0;
System.out.println(r);
}
}
输出:
2.0000000000000004
4.440892098500626E-16
在你的情况下,为了排除这些舍入错误,return语句可能是(!)简单的东西,如
return (area - Math.round(area) < 1e8);
但在其他情况下,您绝对应该阅读有关浮点运算的更多信息。 (网站http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html经常被推荐,但可能很难开始......)
这仍然无法真正回答您的实际问题:为什么结果会有所不同?毫无疑问,答案很简单:因为他们犯了不同的错误(但他们都犯了错误 - 这实际上更重要!)