SinとかSqrt等の算術演算と掛け算の処理負荷を比べてみた

結論：
-------------

* Pow関数 ：掛け算の75倍くらい
* Exp関数 ：掛け算の66倍くらい
* Atan関数：掛け算の55倍くらい
* Sin関数：掛け算の12倍くらい
* Sqrt関数：掛け算と同じくらい。**たまに掛け算より速い**（？？？）

（PCで、UnityのProfilerで計測、C#のMath関数を利用）

注意：
-------------
**※検証方法により違ってくるところもありますので、この結果は参考までにとどめて、鵜呑みにせずにご自身の環境、利用方法に沿った計測を行ってください。**

他の方のによる検証や情報なども寄せられましたので、是非ご参考にしてください。

[SinとかSqrt等の算術演算の速度の件 - Qiita](https://qiita.com/tatsunoru/items/577c3a22e79e38248cfe)
![QS_20190223-145803.png](https://qiita-image-store.s3.amazonaws.com/0/103403/28d7b24b-1512-a61f-e617-c67015d1de59.png)

<blockquote class="twitter-tweet" data-conversation="none" data-lang="ja"><p lang="ja" dir="ltr">CPU命令的には，各アーキ毎にどの命令がどのくらいのサイクル数が必要かは文書化されていて，<br>例えば以下のようなものがあります<a href="https://t.co/qR8Rk6uT17">https://t.co/qR8Rk6uT17</a><br><br>ここで重要なのはLatencyとthrough putです．</p>&mdash; 百千万億 萬.cpp (@TumoiYorozu_FBC) <a href="https://twitter.com/TumoiYorozu_FBC/status/1098809015671246849?ref_src=twsrc%5Etfw">2019年2月22日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

算術演算って何やってんのかわからん
---------------
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">昨日最適化してて思ったけど、四則演算くらいなら処理負荷まぁこんなもんか、って感覚はあるけど、SqrtとかSinとかAngle（Arcsine）とか実際の処理負荷どんなもんなんだろ（掛け算何回分くらいだろう？）っていうのは知りたい</p>&mdash; じーくどらむす (@geekdrums) <a href="https://twitter.com/geekdrums/status/1098252533972135938?ref_src=twsrc%5Etfw">2019年2月20日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


最適化しててふと疑問に感じることがありまして。

「ここで掛け算を1000回やってるから重いんだろうけど、**Atan使って必要なところを絞って100回に減らしたら、総合的に得なんだろうか……？**」と。

Math.○○系の関数って、なんか頑張って近似アルゴリズムとか走らせてるんだろうけど、その中で何回掛け算と同じような処理が走っているのかなんて、なかなか感覚的にはわからないですよね。ググっても良い資料が見当たらず、CPUやライブラリ依存のところがあるから測るしかないと言われ、Unityで軽く測ってみました。

なお、こういう計測や最適化はあまり専門ではないので、**測り方がおかしいんじゃねぇの！？っていうマサカリ**があれば投げてください。。

> 右端のカラムがSelf ms、右から2番めがTime msで、2番目の方が関数トータルでのコストです。

![Dz45tNwV4AASJ1f.png](https://qiita-image-store.s3.amazonaws.com/0/103403/adb1ff06-81a1-8b26-559e-c818fbfbe659.png)

なるほど、Sinが掛け算12回分とそこまで致命的ではないのが救いですが、Atanは重いですね、**掛け算100回分削れるならアド**があります。

**Powの意外なまでの重さ**にも驚きました。Powは2通り計測していて、Pow(f,f)と、Pow(f,2)で試しましたが、後者は最適化でf*fとかになってくれても良さそうですが、ほぼ変わらず、掛け算の70～75倍ほどのコストがかかっていました。

そして、**Sqrtの異常な速さ**。Sqrt用のCPU命令があるんですかね……？距離計算でMagnitudeよりSqrMagnitudeの方が軽いのは明白だけど、最後に掛け算一個削る程度の違いしかない模様。


計測は環境やライブラリにも依存していると思うので、他の環境で違った結果出るなら聞きたいです。

今回検証に使ったコードを置いておきます。


``` MathTest.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MathTest : MonoBehaviour
{
	public double count = 1000;
	public double step = 1;

	void Mult()
	{
		double f;

		for( double i = 0; i < count; i += step )
		{
			f = i * i;
		}
	}

	void Sin()
	{
		double f;

		for( double i = 0; i < count; i += step )
		{
			f = Math.Sin(i);
		}
	}

	void Sqrt()
	{
		double f;

		for( double i = 0; i < count; i += step )
		{
			f = Math.Sqrt(i);
		}
	}

	void Pow()
	{
		double f;

		for( double i = 0; i < count; i += step )
		{
			f = Math.Pow(i, i);
		}
	}

	void Pow2()
	{
		double f;

		for( double i = 0; i < count; i += step )
		{
			f = Math.Pow(i, 2);
		}
	}

	void Atan()
	{
		double f;

		for( double i = 0; i < count; i += step )
		{
			f = Math.Atan(i);
		}
	}

	void Exp()
	{
		double f;

		for( double i = 0; i < count; i += step )
		{
			f = Math.Exp(i);
		}
	}

	// Update is called once per frame
	void Update()
	{
		if( step <= 0 )
		{
			return;
		}

		Mult();

		Sin();

		Sqrt();

		Atan();

		Exp();

		Pow();

		Pow2();
	}
}

```

おまけ
---------

最適化したかったやつ（Atan使って角度の処理範囲を絞った）

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">2D影メッシュ生成スクリプト、我ながら良く作れたと思う。動かすと楽しい。 最適化もまぁまぁできた。 <a href="https://t.co/IEfL2owYwg">pic.twitter.com/IEfL2owYwg</a></p>&mdash; じーくどらむす (@geekdrums) <a href="https://twitter.com/geekdrums/status/1097609196059541504?ref_src=twsrc%5Etfw">2019年2月18日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>