提高余弦精度

时间:2015-11-29 17:33:17

标签: java trigonometry cosine

给定这种计算x的余弦的方法:

public static double myCos(double x){
        double alteSumme, neueSumme, summand;
        int j = 0;
        neueSumme = 1.0;
        summand = 1.0;
        do
        {
            j++;
            summand *= -x * x / j;
            j++;
            summand /= j;
            alteSumme = neueSumme;
            neueSumme += summand;
        } while ( neueSumme != alteSumme );
        return alteSumme;
    }

我得到大x的不准确结果: enter image description here

我必须将域名从实数转换为区间 [0,PI / 2] 以获得准确的结果。

所以,我写了这个方法:

public static double transform(double x){
        x = x%(2*Math.PI);
        if(!(0<=x&&x<Math.PI)){
            x = -(x+Math.PI);
        }
        if(!(0<=x&&x<Math.PI/2)){
            x = -(x-2*Math.abs(x-Math.PI/2));
        }
        return x;
    }

它应分三步完成。

  1. 将域从reals转换为[0,2PI)。

  2. 将域名从[0,2PI]转换为[0,PI)。

  3. 将域名从[0,PI)转换为[0,PI / 2]

  4. 但不知何故,它会产生错误的结果。

    你帮我找错了吗?

    修改

    public class Main {
    
        public static double transform(double x) {
            x = x % (2 * Math.PI);
            if (!(0 <= x && x < Math.PI)) {
                x = -(x + Math.PI);
            }
            if (!(0 <= x && x < Math.PI / 2)) {
                x = -(x - 2 * Math.abs(x - Math.PI / 2));
            }
            return x;
        }
    
        public static double myCos(double x) {
    
            x = transform(x);
    
            double alteSumme, neueSumme, summand;
            int j = 0;
            neueSumme = 1.0;
            summand = 1.0;
            do {
                j++;
                summand *= -x * x / j;
                j++;
                summand /= j;
                alteSumme = neueSumme;
                neueSumme += summand;
            } while (neueSumme != alteSumme);
            return alteSumme;
        }
    
        public static void main(String[] args) {
            int n = 0;
            int k =50;
            for (double y = k * Math.PI; y <= (k + 2) * Math.PI; y += Math.PI/4) {
    
                System.out.println(n + ":" + y + ": " + myCos(y) + " " + Math.cos(y));
                n++;
            }
        }
    }
    

    enter image description here

1 个答案:

答案 0 :(得分:1)

<强>更新 以下是transform仅适用于cos的实现。

/**
 * @param x any value
 * @return x within [0..2PI)
public static double transform(double x) {
    x = Math.abs(x);   // We can do this because Cosine is symmetric around the y axis.
    double y = Math.floor(x / (Math.PI * 2));
    return x - y * Math.PI * 2;
}

根据要求,这是我的测试类:

package cosine;

public class Main {

    public static double transform(double x) {
        x = Math.abs(x);
        double y = Math.floor(x / (Math.PI * 2));
        return x - y * Math.PI * 2;
    }

    public static double myCos(double x) {

        x = transform(x);

        double alteSumme, neueSumme, summand;
        int j = 0;
        neueSumme = 1.0;
        summand = 1.0;
        do {
            j++;
            summand *= -x * x / j;
            j++;
            summand /= j;
            alteSumme = neueSumme;
            neueSumme += summand;
        } while (neueSumme != alteSumme);
        return alteSumme;
    }

    public static void main(String[] args) {
        int n = 0;
        for (double y = -20 * Math.PI; y < 20 * Math.PI; y += Math.PI / 3) {
            double x = Math.PI / 3 + y;
            double tmpa, tmpb;
            System.out.println(
                    n + ":" + x + ": " + (tmpa = myCos(x)) + " " + (tmpb = Math.cos(x)) + "  DIFF: " + (tmpa - tmpb));
            n++;
        }
    }
}

<强>更新

仅通过计算余弦超过0..π:

,这是一个小小的改进
public static double myCos(double x) {
    // Cosine is symmetric around the Y axis: get rid of the sign.
    x = Math.abs(x);

    // Calculate the number of times 2*PI fits in x
    double y = Math.floor(x / (Math.PI * 2));

    // and subtract that many 2*PI
    x -= y * Math.PI * 2;
    // x is now within 0 and 2*PI.

    // The PI..2PI range is the negated version of 0..PI.
    double sign = 1;
    if ( x > Math.PI ) {
       sign = -1;
       // mirror x in the line x=Math.PI:
       x =  - x + Math.PI; // or: Math.PI * 2 - x
    }

    /* cosine approximation ... */

    return alteSumme * sign;
}