C言語で逆三角関数のasin/acos/atan/atan2関数の使い方と自作関数を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
逆三角関数のasin/acos/atan/atan2関数
逆三角関数のasin/acos/atan/atan2関数を紹介します.
asin関数
1 |
double asin(double x); |
asin関数は,xの逆正弦(アークサイン) の主値を計算します.
すなわち,その正弦(サイン)がxとなるような値です.
asin関数の返り値は,xの逆正弦の主値をラジアン単位で返します.
acos関数
1 |
double acos(double x); |
acos関数は,x の逆余弦(アークコサイン) を計算します.
すなわち,その余弦(コサイン)がxとなる値です.
acos関数の返り値は,xの逆余弦をラジアン単位で返します.
atan/atan2関数
1 2 |
double atan(double x); double atan2(double y, double x); |
atan関数は,xの逆正接(アークタンジェント)の主値を計算します.
すなわち, その正接(tangent)がxとなるような値です.
atan関数の返り値は,xの逆正接の主値をラジアン単位で返します.
atan2関数は,y/x の逆正接 (arg tangent) の主値を計算します.
2つの引き数の符号は結果の象限を決定するために使われます.
atan2関数の返り値は,y/xの逆正接の主値をラジアン単位で返します.
asin/acos/atan/atan2関数の使い方
asin/acos/atan/atan2関数の使い方を紹介します.
asin関数の使い方
asin関数の使い方は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <math.h> int main(void) { printf("asin(0.0) = %lf\n", asin(0.0)); printf("asin(0.5) = %lf\n", asin(0.5)); printf("asin(-0.5) = %lf\n", asin(-0.5)); printf("asin(1.0) = %lf\n", asin(1.0)); printf("asin(-1.0) = %lf\n", asin(-1.0)); printf("asin(2.0) = %lf\n", asin(2.0)); printf("asin(-2.0) = %lf\n", asin(-2.0)); printf("asin(INFINITY) = %lf\n", asin(INFINITY)); printf("asin(-INFINITY) = %lf\n", asin(-INFINITY)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 |
$ gcc asin.c -lm $ a.out asin(0.0) = 0.000000 asin(0.5) = 0.523599 asin(-0.5) = -0.523599 asin(1.0) = 1.570796 asin(-1.0) = -1.570796 asin(2.0) = nan asin(-2.0) = nan asin(INFINITY) = nan asin(-INFINITY) = nan |
acos関数の使い方
acos関数の使い方は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <math.h> int main(void) { printf("acos(0.0) = %lf\n", acos(0.0)); printf("acos(0.5) = %lf\n", acos(0.5)); printf("acos(-0.5) = %lf\n", acos(-0.5)); printf("acos(1.0) = %lf\n", acos(1.0)); printf("acos(-1.0) = %lf\n", acos(-1.0)); printf("acos(2.0) = %lf\n", acos(2.0)); printf("acos(-2.0) = %lf\n", acos(-2.0)); printf("acos(INFINITY) = %lf\n", acos(INFINITY)); printf("acos(-INFINITY) = %lf\n", acos(-INFINITY)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 |
$ gcc acos.c -lm $ a.out acos(0.0) = 1.570796 acos(0.5) = 1.047198 acos(-0.5) = 2.094395 acos(1.0) = 0.000000 acos(-1.0) = 3.141593 acos(2.0) = nan acos(-2.0) = nan acos(INFINITY) = nan acos(-INFINITY) = nan |
atan/atan2関数の使い方
atan/atan2関数を使い方は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <math.h> int main(void) { printf("atan(0.0) = %lf\n", atan(0.0)); printf("atan(0.5) = %lf\n", atan(0.5)); printf("atan(-0.5) = %lf\n", atan(-0.5)); printf("atan(1.0) = %lf\n", atan(1.0)); printf("atan(-1.0) = %lf\n", atan(-1.0)); printf("atan(INFINITY) = %lf\n", atan(INFINITY)); printf("atan(-INFINITY) = %lf\n", atan(-INFINITY)); printf("atan2(0.0, 1.0) = %lf\n", atan2(0.0, 1.0)); printf("atan2(1.0, 1.0) = %lf\n", atan2(1.0, 1.0)); printf("atan2(1.0, 0.0) = %lf\n", atan2(1.0, 0.0)); printf("atan2(1.0, -1.0) = %lf\n", atan2(1.0, -1.0)); printf("atan2(0.0, -1.0) = %lf\n", atan2(0.0, -1.0)); printf("atan2(-1.0, -1.0) = %lf\n", atan2(-1.0, -1.0)); printf("atan2(-1.0, 0.0) = %lf\n", atan2(-1.0, 0.0)); printf("atan2(-1.0, 1.0) = %lf\n", atan2(-1.0, 1.0)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ gcc atan.c -lm $ a.out atan(0.0) = 0.000000 atan(0.5) = 0.463648 atan(-0.5) = -0.463648 atan(1.0) = 0.785398 atan(-1.0) = -0.785398 atan(INFINITY) = 1.570796 atan(-INFINITY) = -1.570796 atan2(0.0, 1.0) = 0.000000 atan2(1.0, 1.0) = 0.785398 atan2(1.0, 0.0) = 1.570796 atan2(1.0, -1.0) = 2.356194 atan2(0.0, -1.0) = 3.141593 atan2(-1.0, -1.0) = -2.356194 atan2(-1.0, 0.0) = -1.570796 atan2(-1.0, 1.0) = -0.785398 |
asin/acos/atan/atan2関数の自作関数
asin/acos/atan/atan2関数の自作関数を紹介します.
コードが冗長にならないようにするために,自作関数では以下の関数を利用しています.
上記の関数を知りたいあなたはこちらからどうぞ.
asin関数の自作関数
asin関数の自作関数を実装するためには,テイラー展開(マクローリン展開)を利用します(下式).
\begin{eqnarray*}
\arcsin x &=& \sum_{n=0}^{\infty} \frac{(2n)!}{4^n (n!)^2 (2n + 1)} x^{2n+1} \\
&=& x + \frac{x^3}{6} + \frac{3x^5}{40} + \frac{5x^7}{112} + ... {\rm \ \ \ for\ } |x| < 1
\end{eqnarray*}
asin関数の自作関数は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdbool.h> #include <float.h> #include <math.h> #include <errno.h> #define PI 3.1415926535897932384626433832795 double myasin(double x) { double t = x; double y = x; unsigned long n = 1; if (isnan(x)) { return NAN; } else if (isinf(x)) { return x >= 0.0 ? PI / 2 : -PI / 2; } else if (fabs(x) > 1.0) { errno = EDOM; return NAN; } while (true) { /* maclaurin expansion of arcsin(x) */ t *= ((x * x) * (2 * n - 1) * (2 * n - 1)) / ((2 * n) * (2 * n + 1)); if (fabs(t) <= 1e4 * DBL_EPSILON) { break; } y += t; n++; } return y; } int main(void) { printf("myasin(0.0) = %lf\n", myasin(0.0)); printf("myasin(0.5) = %lf\n", myasin(0.5)); printf("myasin(-0.5) = %lf\n", myasin(-0.5)); printf("myasin(1.0) = %lf\n", myasin(1.0)); printf("myasin(-1.0) = %lf\n", myasin(-1.0)); printf("myasin(2.0) = %lf\n", myasin(2.0)); printf("myasin(-2.0) = %lf\n", myasin(-2.0)); printf("myasin(INFINITY) = %lf\n", myasin(INFINITY)); printf("myasin(-INFINITY) = %lf\n", myasin(-INFINITY)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 |
$ gcc myasin.c $ a.out myasin(0.0) = 0.000000 myasin(0.5) = 0.523599 myasin(-0.5) = -0.523599 myasin(1.0) = 1.570684 myasin(-1.0) = -1.570684 myasin(2.0) = nan myasin(-2.0) = nan myasin(INFINITY) = 1.570796 myasin(-INFINITY) = -1.570796 |
acos関数の自作関数
acos関数の自作関数を実装するためには,テイラー展開(マクローリン展開)を利用します(下式).
\begin{eqnarray*}
\arccos x &=& \frac{\pi}{2} - \arcsin x \\
&=& \frac{\pi}{2} - \sum_{n=0}^{\infty} \frac{(2n)!}{4^n (n!)^2 (2n + 1)} x^{2n+1} \\
&=& \frac{\pi}{2} - x - \frac{x^3}{6} - \frac{3x^5}{40} - \frac{5x^7}{112} - ... {\rm \ \ \ for\ } |x| < 1
\end{eqnarray*}
acos関数の自作関数は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdbool.h> #include <float.h> #include <math.h> #include <errno.h> #define PI 3.1415926535897932384626433832795 double myacos(double x) { double t = x; double y = x; unsigned long n = 1; if (isnan(x)) { return NAN; } else if (x == 1.0) { return 0.0; } else if (isinf(x) || fabs(x) > 1.0) { errno = EDOM; return NAN; } while (true) { /* maclaurin expansion of arccos(x) */ t *= ((x * x) * (2 * n - 1) * (2 * n - 1)) / ((2 * n) * (2 * n + 1)); if (fabs(t) <= 1e4 * DBL_EPSILON) { break; } y += t; n++; } return (PI / 2) - y; } int main(void) { printf("myacos(0.0) = %lf\n", myacos(0.0)); printf("myacos(0.5) = %lf\n", myacos(0.5)); printf("myacos(-0.5) = %lf\n", myacos(-0.5)); printf("myacos(1.0) = %lf\n", myacos(1.0)); printf("myacos(-1.0) = %lf\n", myacos(-1.0)); printf("myacos(2.0) = %lf\n", myacos(2.0)); printf("myacos(-2.0) = %lf\n", myacos(-2.0)); printf("myacos(INFINITY) = %lf\n", myacos(INFINITY)); printf("myacos(-INFINITY) = %lf\n", myacos(-INFINITY)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 |
$ gcc myacos.c $ a.out myacos(0.0) = 1.570796 myacos(0.5) = 1.047198 myacos(-0.5) = 2.094395 myacos(1.0) = 0.000000 myacos(-1.0) = 3.141480 myacos(2.0) = nan myacos(-2.0) = nan myacos(INFINITY) = nan myacos(-INFINITY) = nan |
atan/atan2関数の自作関数
atan/atan2関数の自作関数を紹介します.
atan関数の自作関数は,アークタンジェントの連分数を利用します(下式).
\begin{eqnarray*}
\arctan x &=& \frac{x}{1 + \displaystyle \frac{1x^2}{3 - 1x^2 + \displaystyle \frac{(3x)^2}{5 - 3x^2 + ...}}}
\end{eqnarray*}
また,連分数の上限Nを24に設定します.
atan/atan2関数の自作関数は以下になります.
※以下の関数を追加で実装しています.
- is_positive_epsilon関数:+0(0に近い正の微小値)かどうか判定
- is_negative_epsilon関数:-0(0に近い負の微小値)かどうか判定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdbool.h> #include <stdint.h> #include <math.h> #include <float.h> #define PI 3.1415926535897932384626433832795 #define N 24 bool is_positive_epsilon(double x) { if (x >= 0.0 && x <= DBL_EPSILON) { return true; } return false; } bool is_negative_epsilon(double x) { if (x < 0.0 && x >= -DBL_EPSILON) { return true; } return false; } double myatan(double x) { int i, sign; double t; if (x > 1.0) { sign = 1; x = 1.0 / x; } else if (x < -1.0) { sign = -1; x = 1.0 / x; } else { sign = 0; } for (i = N; i >= 1; i--) { t = (i * i * x * x) / (2 * i + 1 + t); } if (sign > 0) { return PI / 2.0 - x / (1.0 + t); } else if (sign == 0) { return x / (1.0 + t); } else { return -PI / 2.0 - x / (1.0 + t); } } double myatan2(double y, double x) { if (is_positive_epsilon(y) && x < 0.0) { /* If y is +0 (-0) and x is less than 0, +pi (-pi) is returned. */ return PI; } else if (is_negative_epsilon(y) && x < 0.0) { return -PI; } else if (is_positive_epsilon(y) && x > 0.0) { /* If y is +0 (-0) and x is greater than 0, +0 (-0) is returned. */ return 0.0; } else if (is_negative_epsilon(y) && x > 0.0) { return 0.0; } else if (y < 0.0 && (is_positive_epsilon(x) || is_negative_epsilon(x))) { /* If y is less than 0 and x is +0 or -0, -pi/2 is returned. */ return -PI / 2.0; } else if (y > 0.0 && (is_positive_epsilon(x) || is_negative_epsilon(x))) { return PI / 2.0; } else if (isnan(x) || isnan(y)) { /* If either x or y is NaN, a NaN is returned. */ return NAN; } else if (is_positive_epsilon(y) && is_negative_epsilon(x)) { /* If y is +0 (-0) and x is -0, +pi (-pi) is returned. */ return PI; } else if (is_negative_epsilon(y) && is_negative_epsilon(x)) { return -PI; } else if (is_positive_epsilon(y) && is_positive_epsilon(x)) { /* If y is +0 (-0) and x is +0, +0 (-0) is returned. */ return 0.0; } else if (is_negative_epsilon(y) && is_positive_epsilon(x)) { return -0.0; } else if (y > 0.0 && (x < 0.0 && isinf(x))) { /* * If y is a finite value greater (less) than 0, and x is negative infinity, * +pi (-pi) is returned. */ return PI; } else if (y < 0.0 && (x < 0.0 && isinf(x))) { return -PI; } else if (y > 0.0 && (x > 0.0 && isinf(x))) { /* * If y is a finite value greater (less) than 0, and x is positive infinity, * +0 (-0) is returned. */ return 0.0; } else if (y < 0.0 && (x > 0.0 && isinf(x))) { return -0.0; } else if ((y > 0.0 && isinf(y)) && isfinite(x)) { /* * If y is positive infinity (negative infinity), and x is finite, * pi/2 (-pi/2) is returned. */ return PI / 2.0; } else if ((y < 0.0 && isinf(y)) && isfinite(x)) { return -PI / 2.0; } else if ((y > 0.0 && isinf(y)) && (x < 0.0 && isinf(x))) { /* * If y is positive infinity (negative infinity) and x is negative infinity, * +3*pi/4 (-3*pi/4) is returned. */ return 3.0 * PI / 4.0; } else if ((y < 0.0 && isinf(y)) && (x < 0.0 && isinf(x))) { return -3.0 * PI / 4.0; } else if ((y > 0.0 && isinf(y)) && (x > 0.0 && isinf(x))) { /* * If y is positive infinity (negative infinity) and x is positive infinity, * +pi/4 (-pi/4) is returned. */ return PI / 4.0; } else if ((y < 0.0 && isinf(y)) && (x > 0.0 && isinf(x))) { return -PI / 4.0; } if (y > 0.0 && x < 0.0) { return myatan(y / x) + PI; } else if (y < 0.0 && x < 0.0) { return myatan(y / x) - PI; } return myatan(y / x); } int main(void) { printf("myatan(0.0) = %lf\n", myatan(0.0)); printf("myatan(0.5) = %lf\n", myatan(0.5)); printf("myatan(-0.5) = %lf\n", myatan(-0.5)); printf("myatan(1.0) = %lf\n", myatan(1.0)); printf("myatan(-1.0) = %lf\n", myatan(-1.0)); printf("myatan(INFINITY) = %lf\n", myatan(INFINITY)); printf("myatan(-INFINITY) = %lf\n", myatan(-INFINITY)); printf("myatan2(0.0, 1.0) = %lf\n", myatan2(0.0, 1.0)); printf("myatan2(1.0, 1.0) = %lf\n", myatan2(1.0, 1.0)); printf("myatan2(1.0, 0.0) = %lf\n", myatan2(1.0, 0.0)); printf("myatan2(1.0, -1.0) = %lf\n", myatan2(1.0, -1.0)); printf("myatan2(0.0, -1.0) = %lf\n", myatan2(0.0, -1.0)); printf("myatan2(-1.0, -1.0) = %lf\n", myatan2(-1.0, -1.0)); printf("myatan2(-1.0, 0.0) = %lf\n", myatan2(-1.0, 0.0)); printf("myatan2(-1.0, 1.0) = %lf\n", myatan2(-1.0, 1.0)); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ gcc myatan.c $ a.out myatan(0.0) = 0.000000 myatan(0.5) = 0.463648 myatan(-0.5) = -0.463648 myatan(1.0) = 0.785398 myatan(-1.0) = -0.785398 myatan(INFINITY) = 1.570796 myatan(-INFINITY) = -1.570796 myatan2(0.0, 1.0) = 0.000000 myatan2(1.0, 1.0) = 0.785398 myatan2(1.0, 0.0) = 1.570796 myatan2(1.0, -1.0) = 2.356194 myatan2(0.0, -1.0) = 3.141593 myatan2(-1.0, -1.0) = -2.356194 myatan2(-1.0, 0.0) = -1.570796 myatan2(-1.0, 1.0) = -0.785398 |
まとめ
C言語で逆三角関数のasin/acos/atan/atan2関数と自作関数を紹介しました.
asin/acos/atan/atan2関数は複雑ですが,数式をコードに翻訳するイメージをつけましょう.
三角関数sin/cos/tan関数の使い方と自作関数を知りたいあなたはこちらからどうぞ.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!