« May 2012 | Main | September 2012 »

June 30, 2012

sin関数、cos関数を自作する

久々の自作シリーズです。
sin()とcos()をC++で使いたいのですが、あいにくmath.hをインクルードできません。
そこで、自作してみようと思います。

基本的にはテイラー展開(しかも、sin(),cos()の場合はマクローリン展開)です。
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! ...
cos(x) = (x^2)/2! - (x^4)/4! + (x^6)/6! - (x^8)/8! ...

2つの方法を試したのですが、より精度の出る方をご紹介します。

----- 要求精度を満足したところで処理を終える -----
double sin(double x)
{
    double s = x;
    double e = x;
    double d;
    int k;

    // 必要精度の設定.
    double eps = 1e-32;

    x = fmod(x, 2 * π);
    for(k = 2; k <= 200; k = k + 2)
    {
        d = s;
        e = -e * x;
        e = e * x;
        e = e / k;
        e = e / (k + 1);
        s = s + e;

        // ここからは、精度の検証.
        double work = e;
        if(work < 0)
        {
            work *= -1;    // 絶対値へ.
        }
        if(work < eps)                          // 精度の判定.
        {
            return s;
        }
    }
    return 1L;
}

double cos(double x)
{
    double s = 1.0;
    double e = 1.0;
    double d;
    int k;

    // 必要精度の設定.
    double eps = 1e-32;

    x = fmod(x, 2 * π);
    for(k = 1; k <= 200; k = k + 2)
    {
        d = s;
        e = -e * x;
        e = e * x;
        e = e / k;
        e = e / (k + 1);
        s = s + e;

        // ここからは、精度の検証.
        double work = e;
        if(work < 0)
        {
            work *= -1;    // 絶対値へ.
        }
        if(work < eps)                          // 精度の判定.
        {
            return s;
        }
    }
    return 1L;
}

ざっくりですが、これで動くと思います。
絶対値の取得は関数がありますね。
そっちが使える環境なら使った方がよいと思います。
私の環境では使えないのでちまちま判定しています。

参考までに、「ネイピア数eの累乗」に関するエントリーもココにあります。

| | Comments (295) | TrackBack (0)

« May 2012 | Main | September 2012 »