2017/08/09 公開
・三角関数 計算方法
Math.sin/Math.cos/Math.tanを使わずに、指定角度の三角関数の値を(sin,cos,tan)を計算するアルゴリズムを紹介します。
ここで紹介するアルゴリズムは、指定された角度の単位ベクトル(x,y)を求め、xをcos、yをsin、y/xをtanとするものです。指定角度の単位ベクトルの求め方は、以下のとおりです。
①計算するために与えられた角度が、どの象限に入っているか、また、座標軸上にあるかを判定します。下の図は、象限を表しているもので、角度θ、0°<θ<90°であれば第1象限、90°<θ<180°であれば第2象限、180°<θ<270°であれば第3象限、270°<θ<360°であれば第4象限に入ることを表しています。角度が0°/90°/180°/270°の場合は、座標軸上です。
②その象限をに対応する座標軸の単位ベクトルを2つ決めます。その対応する2つの単位ベクトルを赤矢印で示します。(下図)
下図は、指定角度60°のときに選択された2つの単位ベクトルです。
③2つの単位ベクトルの先部分の座標の中点(2つの座標の平均)を通り、原点(0,0)を始点とする単位べクトルを求めます。同時に、求めた単位ベクトルのX軸からの角度も計算します。これも計算に使用した2つの単位ベクトルの角度の平均で求められます。計算した角度が指定角度に近ければ、この単位ベクトルが求める結果でとなり、処理を終了します。
下図は、0°と90°の間の単位ベクトルを求めています。角度は(0°+90°)/2=45°です。
④2つの単位ベクトルのうち1つを③で求めた単位ベクトルに変えます。単位ベクトルの選択条件は、変更後の単位ベクトル角度の範囲内に、指定角度が入ることです。
下図は、0°の単位ベクトルを45°の単位ベクトルに変更した例です。60°の単位ベクトルが2つの単位ベクトルに挟まれていることが分かります。
⑤変更後の単位ベクトルで③の処理に戻ります。
このように単位ベクトルの間の角度を1/2ずつ狭めていき、指定の角度まで近づけます。
このアルゴリズムをJavaのプログラムにしたものが以下です。
このプログラムで指定する角度の単位は度(°)で、0~359.9999..の範囲を超えて指定した場合でも、自動でこの範囲内に収める処理も含めています。
TriFunction.java ← クリックしてダウンロードページに移動001: public class TriFunction { 002: // 角度から象限を求める 003: static int GetOrthant( double deg ) 004: { 005: if ( ( 0.0 < deg ) && ( 90.0 > deg ) ) return 1; 006: if ( ( 90.0 < deg ) && ( 180.0 > deg ) ) return 2; 007: if ( ( 180.0 < deg ) && ( 270.0 > deg ) ) return 3; 008: if ( ( 270.0 < deg ) && ( 360.0 > deg ) ) return 4; 009: return 0; 010: } 011: 012: 013: public static void main(String[] args) { 014: int orthant; // 角度を含む象限 015: int loopnumber; // ループ回数 016: double delta; // 処理終了条件(角度の差) 017: // 計算に使用 018: double deg, rad; 019: double deg1, deg2, degm; 020: double x1, y1; 021: double x2, y2; 022: double mx, my, d; 023: double new_x, new_y; 024: // 計算結果(sin,cos,tan) 025: double ans_sin, ans_cos, ans_tan; 026: 027: // 入力した引数が1以上かを調べる 028: if ( 1 > args.length ) { 029: // 入力した引数が1未満の場合、使用方法を表示する 030: System.out.println( 031: "TriFunction [角度(°)]" ); 032: return; 033: } 034: 035: // 1番目の引数の値をdegに代入 036: try { 037: // 引数を変換し、角度degに代入 038: deg = Double.valueOf( args[ 0 ] ); 039: } 040: catch( NumberFormatException ne ) 041: { 042: System.out.println( "引数が不正です" ); 043: return; 044: } 045: 046: // 角度degを0.0~359.999...の範囲に直す 047: for ( ; ; ) { 048: // degが0.0未満 049: if ( 0.0 > deg ) { 050: deg += 360.0; 051: continue; 052: } 053: // degが360.0以上 054: if ( 360.0 <= deg ) { 055: deg -= 360.0; 056: continue; 057: } 058: // ループを抜ける 059: break; 060: } 061: 062: // 結果の初期化 063: ans_sin = ans_cos = ans_tan = 0.0; 064: loopnumber = 0; 065: 066: // 角度から象限を求める 067: orthant = GetOrthant( deg ); 068: x1 = y1 = x2 = y2 = 0.0; 069: deg1 = deg2 = 0.0; 070: switch ( orthant ) 071: { 072: case 1: 073: deg1 = 0.0; 074: deg2 = 90.0; 075: x1 = 1.0; 076: y1 = 0.0; 077: x2 = 0.0; 078: y2 = 1.0; 079: break; 080: 081: case 2: 082: deg1 = 90.0; 083: deg2 = 180.0; 084: x1 = 0.0; 085: y1 = 1.0; 086: x2 = -1.0; 087: y2 = 0.0; 088: break; 089: 090: case 3: 091: deg1 = 180.0; 092: deg2 = 270.0; 093: x1 = -1.0; 094: y1 = 0.0; 095: x2 = 0.0; 096: y2 = -1.0; 097: break; 098: 099: case 4: 100: deg1 = 270.0; 101: deg2 = 360.0; 102: x1 = 0.0; 103: y1 = -1.0; 104: x2 = 1.0; 105: y2 = 0.0; 106: break; 107: 108: default: 109: // 0° 110: if ( 0.0 == deg ) { 111: ans_sin = 0.0; 112: ans_cos = 1.0; 113: ans_tan = ans_sin / ans_cos; 114: break; 115: } 116: // 90° 117: if ( 90.0 == deg ) { 118: ans_sin = 1.0; 119: ans_cos = 0.0; 120: ans_tan = ans_sin / ans_cos; 121: break; 122: } 123: // 180° 124: if ( 180.0 == deg ) { 125: ans_sin = 0.0; 126: ans_cos = -1.0; 127: ans_tan = ans_sin / ans_cos; 128: break; 129: } 130: // 270° 131: if ( 270.0 == deg ) { 132: ans_sin = -1.0; 133: ans_cos = 0.0; 134: ans_tan = ans_sin / ans_cos; 135: break; 136: } 137: 138: // 原因不明のエラー 139: System.out.println( "原因不明のエラー" ); 140: return; 141: } 142: 143: // 角度が0/90/180/270以外 144: if ( 1 <= orthant ) { 145: delta = 0.000000001; 146: // 無限ループ 147: for ( ; ; ) { 148: // ループ回数 149: ++ loopnumber; 150: 151: // 角度の中間値を計算 152: degm = ( deg1 + deg2 ) / 2.0; 153: 154: // 座標の中間点を計算 155: mx = ( x1 + x2 ) / 2.0; 156: my = ( y1 + y2 ) / 2.0; 157: 158: // 原点(0,0)と(mx,my)を結ぶ線の 159: // 単位ベクトル(new_x, new_y)を計算 160: d = Math.sqrt( mx * mx + my * my ); 161: new_x = mx / d; 162: new_y = my / d; 163: 164: // 角度の差がdelta未満で終了 165: if ( Math.abs( degm - deg ) < delta ) { 166: ans_sin = new_y; 167: ans_cos = new_x; 168: ans_tan = ans_sin / ans_cos; 169: break; 170: } 171: 172: // 角度を狭める 173: if ( deg > degm ) { 174: x1 = new_x; 175: y1 = new_y; 176: deg1 = degm; 177: } 178: else { 179: x2 = new_x; 180: y2 = new_y; 181: deg2 = degm; 182: } 183: } 184: } 185: 186: // 結果の表示 187: System.out.println( "■計算結果" ); 188: System.out.println( "sin(" + deg + ")=" + ans_sin ); 189: System.out.println( "cos(" + deg + ")=" + ans_cos ); 190: System.out.println( "tan(" + deg + ")=" + ans_tan ); 191: System.out.println( "ループ回数=" + loopnumber ); 192: 193: System.out.println(); 194: 195: System.out.println( "■Mathクラスでの計算結果" ); 196: rad = Math.toRadians( deg ); 197: System.out.println( "sin(" + deg + ")=" + Math.sin( rad ) ); 198: System.out.println( "cos(" + deg + ")=" + Math.cos( rad ) ); 199: System.out.println( "tan(" + deg + ")=" + Math.tan( rad ) ); 200: } 201: }
TriFunctionを実行
C:\talavax\javasample>java TriFunction 60.0
60°のsin、cos、tanを求めます。
TriFunction.javaの出力結果
■計算結果 sin(60.0)=0.8660254037768191 cos(60.0)=0.5000000000131974 tan(60.0)=1.732050807507921 ループ回数=35 ■Mathクラスでの計算結果 sin(60.0)=0.8660254037844386 cos(60.0)=0.5000000000000001 tan(60.0)=1.7320508075688767
■関連コンテンツ
数学関数について | 数学関数について解説 |
中点 | 中点(ちゅうてん)について解説 |
単位ベクトル単位ベクトルは長さが1のベクトルのことです。任意の長さのベクトルを単位ベクトルに変換する方法も解説しています。 |
|
単位円単位円は半径が1の円のことです。単位円と三角関数(sinθ、cosθ)の関係についても解説しています。 |
|
三角関数 sinsinの意味と、Math.sinメソッドの使い方をソースコードを使って解説しています。 |
|
三角関数 coscosの意味と、Math.cosメソッドの使い方をソースコードを使って解説しています。 |
|
三角関数 tantanの意味と、Math.tanメソッドの使い方をソースコードを使って解説しています。 |
|
円周率π(パイ)π(パイ)の意味と、Math.PIの使い方について解説 |
|
計算結果の表示足し算(加法)/引き算(減法)/掛け算(乗法)/割り算(除法)の使い方を説明 |
■新着情報
2022.07.07 | 外部プログラムの実行 | exeファイル実行 |
2022.07.06 | 完全数 | 6=1+2+3 |
■広告