【发布时间】:2014-04-06 23:58:41
【问题描述】:
当我执行以下程序时,我开始了解准确性问题:
public static void main(String args[])
{
double table[][] = new double[5][4];
int i, j;
for(i = 0, j = 0; i <= 90; i+= 15)
{
if(i == 15 || i == 75)
continue;
table[j][0] = i;
double theta = StrictMath.toRadians((double)i);
table[j][1] = StrictMath.sin(theta);
table[j][2] = StrictMath.cos(theta);
table[j++][3] = StrictMath.tan(theta);
}
System.out.println("angle#sin#cos#tan");
for(i = 0; i < table.length; i++){
for(j = 0; j < table[i].length; j++)
System.out.print(table[i][j] + "\t");
System.out.println();
}
}
输出是:
angle#sin#cos#tan
0.0 0.0 1.0 0.0
30.0 0.49999999999999994 0.8660254037844387 0.5773502691896257
45.0 0.7071067811865475 0.7071067811865476 0.9999999999999999
60.0 0.8660254037844386 0.5000000000000001 1.7320508075688767
90.0 1.0 6.123233995736766E-17 1.633123935319537E16
(请原谅杂乱无章的输出)。 我注意到了几件事:
- sin 30 即
0.5存储为0.49999999999999994。 - tan 45 即
1.0存储为0.9999999999999999。 - tan 90 即
infinity或undefined存储为1.633123935319537E16(这是一个非常大的数字)。
当然,看到输出我很困惑(即使在破译输出之后)。
所以我读过this 的帖子,最好的答案告诉我:
这些accuracy problems 是由浮点数的internal representation 引起的,您无能为力。
顺便说一句,在运行时打印这些值通常仍然会产生正确的结果,至少使用现代 C++ 编译器。对于大多数操作来说,这不是什么大问题。
2008 年 10 月 7 日 7:42 回答
康拉德·鲁道夫
所以,我的问题是:
有没有办法防止这种不准确的结果(在 Java 中)?
我应该对结果进行四舍五入吗?在这种情况下,我将如何存储infinity,即Double.POSITIVE_INFINITY?
【问题讨论】:
-
theta不完全是半 pi,这就是为什么输出中没有 Infinity - NaN/InF 不“存储为”1.633123935319537E16,它仍然是一个有限的数字。 -
请参阅tan(PI/2),了解为什么您没有获得 Infinity。但是,我不知道如何将棕褐色“接受接近 PI/2 的值”作为 PI/2,并且所有环境似乎都会产生 a 值。
-
@user2864740 谢谢,这告诉了我为什么...但是你能告诉我如何解决它吗?
-
我能想到的唯一直接解决方案是在调用 tan 之前对输入进行特殊处理。如果您喜欢它“足够接近 PI/2”,只需返回 Inf/-Inf(或任何您期望的)而不是调用 tan。如果你需要做“三角正确”数学,可能有一个库可以处理精确的数学概念。 (我认为“符号数学”可能是一个有用的搜索词)。
-
@user2864740 谢谢,我会注意的。