0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【UnityC#】Mathf.Sin()に巨大な値を入れた時の計算誤差を調べてみた

Last updated at Posted at 2018-07-02

はじめに

Unityの三角関数Mathf.Sin()を使用するとき、
計算誤差を減らすためにSin関数に渡すラジアン値θを0 ≦ θ < 2πの範囲に収めたほうが良いといわれます。

では、θ >= 2π となるようなθを入れた場合、どの程度の大きさの誤差が発生するのでしょうか?

ちょっと気になったので調べてグラフ化してみました。


ちなみに、数学的には以下のような等式が成立します。 >sin(θ + 2π * (任意の整数) ) = sin(θ) (θは実数とする)

環境

Unity2018.1.0f2
Windows 10

誤差の測定

誤差の測定区間

以下の3パターンの区間での誤差を調べてみました。

0 <= θ <= 36000° (θ = 0°, 360°, 720°, 1080°, 1440°, ・・・ 36000°)
36000° <= θ <= 72000°
1800000° <= θ <= 1836000°

θは360°刻みで増加させ、それぞれの誤差を測定しました。

誤差の計算式

ここで、sin(θ)の誤差Eは以下のような計算で求めています。

誤差Eの計算式
float E = Mathf.Abs(sin(theta) - sin(0.0f));

sin(0°)とsin(θ)の差分をとり、その絶対値を誤差としています。

差分をとるだけだと正・負の誤差が表れてしまって見づらいので、絶対値Mathf.Abs()で見やすくしています。


ちなみに、θはシータ(theta)と読みます。

測定結果

0 <= θ <= 36000°
image.png

36000° <= θ <= 72000°
image.png

1800000° <= θ <= 1836000°
image.png

Mathf.Sin(theta)のthetaの数値が大きくなるほど誤差も大きくなることが読み取れます。

ソースコード

Mathf.Sinの誤差の計測に使用したソースコードは以下になります。

TestSin.cs
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEditor;

public class TestSin : MonoBehaviour
{
	const int k_LoopMax = 10000;
	const int k_DegreeInterval = 360;

	void Start()
	{
		Debug.Log("計測を開始します");
		int largeDegree = 360;
		int smallDegree = 0;

		var sb = new StringBuilder();
        sb.AppendFormat("計測日時 : {0}\n", System.DateTime.Now);
        sb.AppendFormat("Unityバージョン : {0}\n", Application.unityVersion);
        sb.AppendFormat("ループ回数 : {0}\n", k_LoopMax);
        sb.AppendFormat("角度の刻み幅 : {0}\n", k_DegreeInterval);
        sb.AppendFormat("i,Degree,誤差の絶対値,sin(Degree)\n",smallDegree);

		int degree = smallDegree;
		float radian = degree * Mathf.Deg2Rad; // ラジアン値
		float baseSin = Mathf.Sin(radian); // sinのベース値

		sb.AppendFormat("{0},{1},{2},{3}\n", 
			-1, // ループカウンタ 
			degree, // 角度
			Mathf.Abs(Mathf.Sin(radian) - baseSin), // 誤差
			Mathf.Sin(radian) // サイン値
		);

		for (int i = 0; i < k_LoopMax; i++)
		{
			degree = largeDegree + smallDegree;
			radian = degree * Mathf.Deg2Rad;

			sb.AppendFormat("{0},{1},{2},{3}\n", 
				i, // ループカウンタ 
				degree, // 角度
				Mathf.Abs(Mathf.Sin(radian) - baseSin), // 誤差
				Mathf.Sin(radian) // サイン値
			);


			largeDegree += k_DegreeInterval;

		}

		Debug.Log("計測が完了しました");

		// CSV書き出し
		string csvText = sb.ToString();
		FileManager.Save(csvText);

		Debug.Log("CSV書き出しが完了しました");

		EditorApplication.isPlaying = false;

	}

}
FileManager.cs
using UnityEngine;
using System.IO;
using System;

/// <summary>
/// csvファイルの書き出しを行う
/// </summary>
public class FileManager
{
    // ファイル書き出し
    public static void Save(string text)
    {
# if UNITY_EDITOR
        var now = System.DateTime.Now;
        var datetime = string.Format("{0}{1:D2}{2:D2}_{3:D2}{4:D2}{5:D2}", now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
        var path = Application.dataPath + "/" + string.Format("Sin_{0}.csv", datetime);

        System.IO.StreamWriter sw = new System.IO.StreamWriter(path, false, System.Text.Encoding.GetEncoding("shift_jis"));

        sw.Write(text);
        sw.Flush();
        sw.Close();

        UnityEditor.AssetDatabase.Refresh();
# endif
    }
}

おまけ: Mathf.Sinの中身について軽く調べてみた。

Mathf.Sin()の正体は System.Math.Sin()

UnityEngine.Mathf.Sin()ですが、内部的にはSystem.Math.Sinを実行しているだけです。

Mathf.cs
public static float Sin(float f) { return (float)Math.Sin(f); }

参考:
https://github.com/Unity-Technologies/UnityCsReference/blob/2018.2/Runtime/Export/Mathf.cs

System.Math.Sin()の実装

System.Math.Sin()の中身はXの多項式(polynomial)で実装されているみたいです。 
https://stackoverflow.com/questions/25327821/how-can-i-see-the-source-code-of-system-math-sin

・・・テイラー展開?

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?