arctanの近似計算

arctan関数の近似計算として、3次のガウス求積法による近似式は、

角度をラジアンから度数法に換算すると


C言語のコード

この近似計算をおこなうC言語のコードを以下に示す。
なお、浮動小数点実数にはdouble型ではなくfloat型を用いている。計算の精度からしてfloat型で十分であるし、単精度FPUを備えたマイコンならfloat型の加算や乗算を1命令で実行できる。

#define _USE_MATH_DEFINES
#include <stdio.h>
#include <math.h>

// 軽量版 atan2 関数 (戻り値はradではなくdeg単位)
float atan2_deg(float y, float x);
// 軽量版 atan 関数 (atan2_degから呼ばれる)
float atan_deg(float x);

// 軽量版 atan2 関数 (戻り値はradではなくdeg単位)
float atan2_deg(float y, float x)
{
    if (x == 0 && y == 0) return 0;
    float th;
    float abs_x = (x >= 0) ? x : -x;
    float abs_y = (y >= 0) ? y : -y;
    if (abs_x > abs_y) {
        float _th = atan_deg(y / x);
        if (x > 0) {
            th = _th;
        } else {
            if (y >= 0) {
                th = 180.0f + _th;
            } else {
                th = -180.0f + _th;
            }
        }
    } else {
        float _th = atan_deg(x / y);
        if (y > 0) {
            th = 90.0f - _th;
        } else {
            th = -90.0f - _th;
        }
    }
    return th;
}

// 軽量版 atan 関数 (atan2_degから呼ばれる)
float atan_deg(float x)
{
    // 近似計算
    float x2 = x * x;
    float th = ((76.39437f * x2 + 286.47889f) / (3 * x2 + 5)) * x;
    return th;
}

// テストプログラム
int main(void)
{
    printf(" x          y           deg1,        deg2,         error\n");
    for (int i = 0; i <= 90; i+=5) {
        double rad = (double)i * M_PI / 180.0;
        double deg = i;
        double x = cos(rad);
        double y = sin(rad);
        double rad1 = atan2(y, x);
        double deg1 = rad1 * 180.0 / M_PI;
        float  deg2 = atan2_deg((float)y, (float)x);

        printf("%9.6f, %9.6f, %11.6f, %11.6f, %11.6f\n",
            x, y, deg1, deg2, deg1 - deg2);
    }

    return 0;
}

実行結果

45度の近傍で誤差が大きくなるが最大で0.36度程度であり、計算量のわりにかなり精度の良い結果が得られた。

 x          y           deg1,        deg2,         error
 1.000000,  0.000000,    0.000000,    0.000000,    0.000000
 0.996195,  0.087156,    5.000000,    5.000000,    0.000000
 0.984808,  0.173648,   10.000000,   10.000006,   -0.000006
 0.965926,  0.258819,   15.000000,   15.000114,   -0.000114
 0.939693,  0.342020,   20.000000,   20.000893,   -0.000893
 0.906308,  0.422618,   25.000000,   25.004444,   -0.004444
 0.866025,  0.500000,   30.000000,   30.016794,   -0.016794
 0.819152,  0.573576,   35.000000,   35.052658,   -0.052658
 0.766044,  0.642788,   40.000000,   40.144478,   -0.144478
 0.707107,  0.707107,   45.000000,   44.640842,    0.359158
 0.642788,  0.766044,   50.000000,   49.855522,    0.144478
 0.573576,  0.819152,   55.000000,   54.947342,    0.052658
 0.500000,  0.866025,   60.000000,   59.983208,    0.016792
 0.422618,  0.906308,   65.000000,   64.995560,    0.004440
 0.342020,  0.939693,   70.000000,   69.999107,    0.000893
 0.258819,  0.965926,   75.000000,   74.999886,    0.000114
 0.173648,  0.984808,   80.000000,   79.999992,    0.000008
 0.087156,  0.996195,   85.000000,   85.000000,    0.000000
 0.000000,  1.000000,   90.000000,   90.000000,    0.000000

参考サイト