2017.08.09

三角関数 計算方法

はじめに

Math.sinMath.cosMath.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ソースコード

このアルゴリズムJavaのプログラムにしたものが以下です。

このプログラムで指定する角度の単位は度(°)で、0~359.9999..の範囲を超えて指定した場合でも、自動でこの範囲内に収める処理も含めています。

TriFunction.java

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
public class TriFunction {
	// 角度から象限を求める
	static int GetOrthant( double deg )
	{
		if ( (   0.0 < deg ) && (  90.0 > deg ) ) return 1;
		if ( (  90.0 < deg ) && ( 180.0 > deg ) ) return 2;
		if ( ( 180.0 < deg ) && ( 270.0 > deg ) ) return 3;
		if ( ( 270.0 < deg ) && ( 360.0 > deg ) ) return 4;
		return 0;
	}


	public static void main(String[] args) {
		int    orthant;		// 角度を含む象限
		int    loopnumber;	// ループ回数
		double delta;		// 処理終了条件(角度の差)
		// 計算に使用
		double deg, rad;
		double deg1, deg2, degm;
		double x1, y1;
		double x2, y2;
		double mx, my, d;
		double new_x, new_y;
		// 計算結果(sin,cos,tan)
		double ans_sin, ans_cos, ans_tan;

		// 入力した引数が1以上かを調べる
		if ( 1 > args.length ) {
			// 入力した引数が1未満の場合、使用方法を表示する
			System.out.println( 
				"TriFunction [角度(°)]" );
			return;
		}

		// 1番目の引数の値をdegに代入
		try {
			// 引数を変換し、角度degに代入
			deg = Double.valueOf( args[ 0 ] );
		}
		catch( NumberFormatException ne )
		{
			System.out.println( "引数が不正です" );
			return;
		}

		// 角度degを0.0~359.999...の範囲に直す
		for ( ; ; ) {
			// degが0.0未満
			if ( 0.0 > deg ) {
				deg += 360.0;
				continue;
			}
			// degが360.0以上
			if ( 360.0 <= deg ) {
				deg -= 360.0;
				continue;
			}
			// ループを抜ける
			break;
		}

		// 結果の初期化
		ans_sin = ans_cos = ans_tan = 0.0;
		loopnumber = 0;

		// 角度から象限を求める
		orthant = GetOrthant( deg );
		x1 = y1 = x2 = y2 = 0.0;
		deg1 = deg2 = 0.0;
		switch ( orthant )
		{
			case 1:
				deg1 = 0.0;
				deg2 = 90.0;
				x1 =  1.0;
				y1 =  0.0;
				x2 =  0.0;
				y2 =  1.0;
				break;

			case 2:
				deg1 = 90.0;
				deg2 = 180.0;
				x1 =  0.0;
				y1 =  1.0;
				x2 = -1.0;
				y2 =  0.0;
				break;

			case 3:
				deg1 = 180.0;
				deg2 = 270.0;
				x1 = -1.0;
				y1 =  0.0;
				x2 =  0.0;
				y2 = -1.0;
				break;

			case 4:
				deg1 = 270.0;
				deg2 = 360.0;
				x1 =  0.0;
				y1 = -1.0;
				x2 =  1.0;
				y2 =  0.0;
				break;

			default:
				// 0°
				if ( 0.0 == deg ) {
					ans_sin = 0.0;
					ans_cos = 1.0;
					ans_tan = ans_sin / ans_cos;
					break;
				}
				// 90°
				if ( 90.0 == deg ) {
					ans_sin = 1.0;
					ans_cos = 0.0;
					ans_tan = ans_sin / ans_cos;
					break;
				}
				// 180°
				if ( 180.0 == deg ) {
					ans_sin = 0.0;
					ans_cos = -1.0;
					ans_tan = ans_sin / ans_cos;
					break;
				}
				// 270°
				if ( 270.0 == deg ) {
					ans_sin = -1.0;
					ans_cos = 0.0;
					ans_tan = ans_sin / ans_cos;
					break;
				}

				// 原因不明のエラー
				System.out.println( "原因不明のエラー" );
				return;
		}

		// 角度が0/90/180/270以外
		if ( 1 <= orthant ) {
			delta = 0.000000001;
			// 無限ループ
			for ( ; ; ) {
				// ループ回数
				++ loopnumber;

				// 角度の中間値を計算
				degm = ( deg1 + deg2 ) / 2.0;

				// 座標の中間点を計算
				mx = ( x1 + x2 ) / 2.0;
				my = ( y1 + y2 ) / 2.0;

				// 原点(0,0)と(mx,my)を結ぶ線の
				// 単位ベクトル(new_x, new_y)を計算
				d = Math.sqrt( mx * mx + my * my );
				new_x = mx / d;
				new_y = my / d;

				// 角度の差がdelta未満で終了
				if ( Math.abs( degm - deg ) < delta ) {
					ans_sin = new_y;
					ans_cos = new_x;
					ans_tan = ans_sin / ans_cos;
					break;
				}

				// 角度を狭める
				if ( deg > degm ) {
					x1 = new_x;
					y1 = new_y;
					deg1 = degm;
				}
				else {
					x2 = new_x;
					y2 = new_y;
					deg2 = degm;
				}
			}
		}

		// 結果の表示
		System.out.println( "■計算結果" );
		System.out.println( "sin(" + deg + ")=" + ans_sin );
		System.out.println( "cos(" + deg + ")=" + ans_cos );
		System.out.println( "tan(" + deg + ")=" + ans_tan );
		System.out.println( "ループ回数=" + loopnumber );

		System.out.println();

		System.out.println( "■Mathクラスでの計算結果" );
		rad = Math.toRadians( deg );
		System.out.println( "sin(" + deg + ")=" + Math.sin( rad ) );
		System.out.println( "cos(" + deg + ")=" + Math.cos( rad ) );
		System.out.println( "tan(" + deg + ")=" + Math.tan( rad ) );
	}
}

コンパイル ソースコードが「ANSI」の場合

C:\talavax\javasample>javac -encoding sjis TriFunction.java

コンパイル ソースコードが「UTF-8」の場合

C:\talavax\javasample>javac TriFunction.java

実行

C:\talavax\javasample>java TriFunction 60.0

60°のsincostanを求めます。

出力結果

■計算結果
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

関連コンテンツ

数学に関係するJavaのメソッドやソースコードなどを紹介しています。

2022.10.25

2つの座標の真ん中の座標の求める計算について説明しています。

2021.02.18

Math.cosメソッドとMath.sinメソッドを使ってtanθを計算する方法を解説しています。

2024.05.16

単位ベクトルの意味と、単位ベクトルの求め方を解説しています。

2020.03.23

単位円の意味をくわしく解説しています。

2020.03.23

sin(サイン)の意味と、Math.sinメソッドの使い方をソースコードを使って詳しく解説しています。

2020.03.23

cos(コサイン)の意味と、Math.cosメソッドの使い方をソースコードを使って詳しく解説しています。

2020.03.23

tan(タンジェント)の意味と、Math.tanメソッドの使い方を解説しています。

2020.03.23

円周率、πってどうゆう意味?

2020.03.23

与えられた任意の角度を0°から360°に収めるメソッドの作り方を説明します。

2016.02.21

処理を繰り返すために使用するfor文について解説しています。

2020.03.23

基本的な計算である足し算(加法)/引き算(減法)/掛け算(乗法)/割り算(除法)を行うプログラム作成。

2020.03.23

Javaを使った簡単な応用プログラム(生年月日から年齢を計算プログラムなど)を紹介しています。

2022.07.07

Javaの学習に役立つソースコードを多数紹介しています。是非、ご覧ください。

2022.09.10

条件式を判断して処理を分岐する方法を詳しく説明しています。

2023.03.20

メソッドを抜けるときに使用するreturn文について説明しています。

2020.03.20

Javaのmainメソッドで受け取るパラメータについて解説しています。

2017.09.26

mainメソッドで受け取るパラメータの数の取得の仕方について解説しています。

2019.05.14

変数やクラスに格納されている値をコンソール出力する方法は?

2020.03.23

式の値によって処理を分岐する方法を詳しく解説しています。

2016.08.04

プログラムの最初に実行されるメソッドは?

2022.12.13

プログラミングで使う変数って何?

2020.03.23

Javaのプログラムを書いてみませんか?プログラムの書き方をくわしく説明しています。

2020.03.23

「Javaソースコード」から実行可能な「オブジェクトコード」に変換する方法をくわしく説明しています。

2020.03.23

Javaのプログラムを作ってみませんか?プログラミングに必要なものの用意から実行までを説明しています。

2020.03.23

Swingパッケージを使ってグラフィック表示を行う方法を解説しています。

2020.03.23

画像フォーマット形式・色・大きさ・傾きなどの変更、特定の図形(文字・記号など)を見つけたり、取り出したりする画像処理について詳しく解説。

2015.11.29

繰り返し処理を使ったJavaのソースコードサンプルを紹介しています。

2020.03.23

配列を使うJavaソースコードを多数紹介しています。

2021.05.18

三角形、台形、円などいろいろな図形の面積を計算するプログラムを紹介しています。詳しくは、記事をご覧ください。

2021.05.18

StringクラスとStringBuilderクラスを利用したプログラミングの仕方を紹介しています。

2016.12.16

プログラミング、ITに関する用語をまとめています。

2022.10.17

日本で使われてきた伝統文様「和柄」について解説しています。

2022.07.27

アルゴリズムって何?

2022.12.29

国際単位系における角度の単位のラジアンについて説明しています。興味のある方は、記事をご覧ください。

2016.01.26

XY平面座標の4つの領域について解説しています。

2017.02.24

平面上の位置を表す座標系の1つXY座標系について詳しく解説。

2020.03.23

複数の数値の合計値と平均値を計算するプログラムをJavaのソースコードを使って解説しています。

2020.03.23

プログラミング言語とは?種類や特徴について説明しています。

2022.08.03

「ゆるゆるプログラム」のコンテンツを紹介しています。興味のある方はこの記事をご覧ください。

2020.03.23

広告