太郎Work

Unityとかで困ったこと等を残しておきます

Vector3.magnitudeの負荷について

きっかけ

とある実装でC#処理負荷が非常に高く困っていたのですが、C#の実行速度が遅いからと考えていました。

ふと、magnitudeの平方根計算が非常に高負荷になっているのではないかと思い、検証してみました。

A,B2点間の距離を出す式は以下のようになり、公式リファレンスにも負荷があるよと記述があります

{ \displaystyle
V = V_A - V_B\\
length = \sqrt{Dot(V,V)}
}
HatenaってTex記述もできるんだねすごぃ
Unity - Scripting API: Vector3.sqrMagnitude


計測方法

そこで負荷を以下の計算式で試してみました

magnitude Vector3.magnitude
sqrMagnitude Vector3.sqrMagnitude
systemMagnitude System.Math.Sqrt(V.x*V.x+V.y*V.y+V.z*V.z)
systemSqrMagnitude V.x*V.x+V.y*V.y+V.z*V.z

最初に以下のようなスクリプトを組んだのですが、ラムダ式の負荷が想像以上に高く(ベタに記述した場合の2倍以上)正確な実行速度差が分からなかったためdelegateを使わないようにしています。
また、実行結果が正しい事を確認するために結果をlengthとして出力しています。

IEnumerator Start () {
	yield return new WaitForSeconds(0.5f);
	CalcTest("magnitude", (v) => v.magnitude);
	yield return 0;
	CalcTest("sqrMagnitude", (v) => v.sqrMagnitude);
	yield return 0;
	CalcTest("systemMagnitude", (v) => (float)System.Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z));
	yield return 0;
	CalcTest("systemSqrMagnitude", (v) => v.x * v.x + v.y * v.y + v.z * v.z);
}
void CalcTest(string n, System.Func<Vector3,float> method) {
	var vA = Vector3.zero;
	var vB = new Vector3(2f, 2f, 2f);
	var v = vA - vB;
	float length = 0f;
	float time = Time.realtimeSinceStartup;
	for(int i = 0; i < COUNT; i++) {
		length = method(v);
	}
	Debug.Log(n + "->" + (Time.realtimeSinceStartup - time) + " length=" + length);
}

実行結果

今回は10000000回の実行速度を計測します。
環境

  • Corei7-2600K 3.4Ghz
  • UnityEditor

magnitude->2.611315 length=3.464102
sqrMagnitude->1.627022 length=12
systemMagnitude->1.290134 length=3.464102
systemSqrMagnitude->0.8662863 length=12

まさかの結果でした。

magnitudeはSystem.Mathの2倍の負荷がかかる事がわかりました。
magnitudeの実装を見るとSystem.Math.Sqrtを実行しているだけだったのでVector3のプロパティを通すだけで負荷がかかるようです。

平方根の負荷自体は1.5倍程度だったので激しくボトルネックになることはなさそうです。


面白い結果が分かってよかったです。