如何在Java中获得三角函数的精确值

时间:2015-04-08 13:36:17

标签: java math floating-point-precision

这与thisthis不重复 我正在为Android开发一个计算器应用程序,我在网上搜索过去20-30天,但没有找到任何合理的答案。我还研究了很多关于浮点计算的论文。 我也尝试过Math和StrictMath库。

我尝试了以下值

Math.cos(Math.PI/4) result in 0.7071067811865476 which is correct answer

Math.cos(Math.PI/2) result in 6.123233995736766E-17 correct answer is 0

Math.cos(Math.PI) result in -1.0 which is correct

Math.cos((3*Math.PI)/2) result in -1.8369701987210297E-16 correct answer is 0

Math.cos(Math.PI*2) result in 1.0 which is correct



Math.sin(Math.PI/4) result in 0.7071067811865476 which is correct answer

Math.sin(Math.PI/2) result in 1 which is correct

Math.sin(Math.PI) result in 1.2246467991473532E-16 correct answer is 0

Math.sin((3*Math.PI)/2) result in -1 which is correct

Math.sin(Math.PI*2) result in -2.4492935982947064E-16 correct answer is 0



Math.tan(Math.PI/4) result in 0.999999999999999 correct answer is 1

Math.tan(Math.PI/2) result in 1.633123935319537E16 correct answer is NaN

Math.tan(Math.PI) result in -1.2246467991473532E-16 correct answer is 0

Math.tan((3*Math.PI)/2) result in 5.443746451065123E15 correct answer is NaN

Math.tan(Math.PI*2) result in -2.4492935982947064E-16 correct answer is 0

当我在Google官方计算器上尝试所有这些计算时,除了tan((3 * PI)/ 2)和tan(PI / 2)

之外,所有这些计算都包含在Stock Lollipop中。

当我在卡西欧fx-991 PLUS上尝试所有这些计算时,所有答案都是正确的。

现在我的问题是“Google的计算器和卡西欧的计算器如何使用有限的浮动精度CPU来获得正确答案?”和“我怎么能 实现相同的输出?“

3 个答案:

答案 0 :(得分:4)

我对许多正确答案持怀疑态度#34;你给的价值。 sin(pi)为0,但Math.PI不是pi,它是近似值。只接近PI的东西的正弦不应该给你0.用户如何输入值?如果用户输入十进制输入,小数点后16位,他/她应该会得到一些在小数点后16位处取消的结果。如果用户要求sin(10 ^ -15)并且您将输入更改为0并返回0的结果,那么您可以通过计算{来使用户无法计算sin x的数值导数为0 {1}}。如果用户输入类似Math.PI的近似值并将输入更改为pi。

,情况也是如此

正如Bryan Reilly回答的那样,您可以在将结果呈现给用户之前对结果进行舍入,这样可以避免显示类似5 * 10 ^ -15而不是0的值。

您可以将输入移动到接近0的范围。例如,对于大于pi或小于-pi的x值,您可以减去2pi的倍数以获得[-pi,pi]中的值。然后,您可以使用trig标识将您需要的域减少到[0,pi / 2]。例如,如果x在[-pi,pi / 2]中,则使用sin(x)= -sin(x + pi)。

如果任何舍入错误都是不可接受的,那么也许您应该使用符号计算器而不是浮点计算器。

答案 1 :(得分:2)

最有可能的是,如果结果比1.0E-14小,那么Google和Casios计算器就会向下舍入。

如果数字太大,可以做类似的事情。

浮点不准确很难处理,但舍入是解决它们的最常用方法。

虽然看起来你知道幕后发生了什么,但这可能会对你有所帮助:

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

答案 2 :(得分:0)

也许他们使用像Big Decimal Class

这样的东西

抱歉,我还不允许提供简单的评论。

例如昨天我创建了一个简单的swing应用程序,它从十进制转换为unsigned int二进制,反之亦然。问题是,用户在文本框中输入的是要转换的字符串值,它们甚至可以轻松超过Long.MAX_VALUE。

我想要的是用户在两种情况下都可以根据需要输入任意数量的数字,因此我使用Big Integer Class,它类似于大十进制但适用于整数值。使用它的结果允许用户输入令人难以置信的长度的字符串,并且我的程序输出的转换数量甚至更多,远远超过Long.MAX_VALUE。

但是,由于数学函数使用双精度数,因此我们仍然限制使用' Big'类,用双精度和字符串初始化。如果你有一个应用程序,你可以用字符串表示数字(最大字符长度为Integer.MAX_VALUE),那么' Big'上课很棒。但是,如果要使用double进行初始化,则显然受限于double的约束。