【问题标题】:Sine approximation error in JavaJava中的正弦逼近误差
【发布时间】:2016-07-02 04:42:24
【问题描述】:

我对在 Java 中编写的近似正弦函数的方法有点恼火。在这里,它基于泰勒的系列。

  static double PI = 3.14159265358979323846;
  static double eps = 0.0000000000000000001;

  static void sin(double x) {
    x = x % (2 * PI);
    double term = 1.0;
    double res  = 0.0;

    for (int i = 1; term > eps; i++) {
        term = term * (x / i);
        if (i % 4 == 1) res += term;
        if (i % 4 == 3) res -= term;
    }
  System.out.println(sum);
 }

对于小值,我得到了非常好的正弦近似值,但对于大值(例如 pow(10,22)),结果似乎非常非常错误。

结果如下:

 sin(pow(10,22)) // 0.8740280612007599
 Math.sin(pow(10,22)) // -0.8522008497671888

有人有想法吗?谢谢!

最好的问候,

【问题讨论】:

    标签: java math trigonometry


    【解决方案1】:

    请放心,Java sin 功能也将关闭。

    您的问题是sin 的泰勒展开式的收敛半径很小,即使您在该半径内,收敛也很慢。

    还有浮点考虑:浮点double 为您提供大约 15 个有效数字的准确度。

    因此对于sin 的大参数,准确度会显着下降,尤其是考虑到sin 是一个周期性 函数:

    sin(x + 2 * pi * n) = sin(x) 为任意整数n

    【讨论】:

    • 我认为x = x % (2 * PI); 会避免这种精度损失(即使它是参数的近似值)。有什么办法可以减少吗?
    • 不。最初的x 已经太近似了。您不能将大型浮点参数与周期性函数一起使用。这就是我害怕的生活。不过是个好问题。我很惊讶没有其他人支持它。
    • 谢谢!我会寻找另一种方法(我和一些朋友正在学校编写一种新语言。我们必须实现一个数学类!)。如果您有任何有用的参考.. ;)
    • @Bathsheba 为什么“精度会显着下降,特别是考虑到 sin 是一个周期函数”?周期函数在精度方面有什么特别之处?
    • 因为浮点数越来越大,它们之间的“间隙”也会越来越大。
    【解决方案2】:

    您的答案对于大数字是不正确的,因为由于double 演示文稿,您累积了很多舍入错误。当数字很大时,您的 for 循环将在 term 变得小于 epsilon 之前进行大量迭代。在每次迭代中,都会累积一个舍入误差。结果是最终值有很大的误差。阅读有关“数值分析”的一些不错的参考资料。无论如何,根据定义,Tylor 的级数近似于 sin 接近 0。因此,对于非常大的数字,不正确是正常的。

    【讨论】:

      【解决方案3】:

      差异实际上与泰勒级数的收敛半径无关,而与双精度不够准确以保持如此大的数字所需的精度有关。正弦函数的泰勒级数的半径是无穷大。

      10^22 大约是 2^73。由于双精度数的尾数为 52 位,因此可以以双精度格式存储的连续值将彼此相距 2^21。由于正弦函数的评估需要比这更高的分辨率,因此您将无法可靠地得到答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-10
        • 1970-01-01
        • 2015-06-15
        • 1970-01-01
        • 2012-12-03
        • 2015-08-29
        • 2019-07-11
        • 1970-01-01
        相关资源
        最近更新 更多