概要
2点間の距離を比較するときに、sqrt
といった関数で距離を求める汎用メソッド/関数を使うのに対して、距離の2乗のままで比較して計算スピードを上げることが考えられる。
昔の大型計算機で大きな規模の方程式を解くときなどは、計算スピードを上げるために距離の2乗のままで比較をしていたりしたが、簡単なシミュレーションやアニメーションなどで、それがどれくらい効いてくるのかがよくわからなかった。
そこで、他の関数も含めて、Mathクラスのクラスメソッドとして定義されている浮動小数点系の関数群の実行時間を計ってみた。
結果概要
加減乗除算の間では実行時間にあまり差はなく、これらを1としたときの各関数の実行時間程度は以下のようになった。
+-*/ | 1 |
abs、sqrt、exp、log、random | 1 |
sin、cos | 2~3 |
tan、atan | 4~5 |
atan2 | 5~6 |
asin、acos | 6~7 |
pow(**) | 7~8 |
一般的な方針
先の結果から、浮動小数点の計算を含むコードに関して、以下のようにまとめられる。
- 距離の計算などにsqrtを気軽に使ってもよい(足し算を一つ増やす程度)
- exp、logも気軽に使ってよい
- 累乗計算はコストが高い
- 距離計算などで自乗項が出てくる場合、乗算に変更した方がよい
- 三角関数は、加減乗除の2~5倍のコスト
- 逆三角関数は、加減乗除の5~7倍のコスト
参考
実行環境1
- mouse製ノートPC
- Celeron-325U/1.70GHz
- RAM 8GB
- Windows 10 Home(64bit)
コンソールからテストコードを実行。
ここでa = 1.1、b = -2.2で、各関数の繰り返し回数は100万回。時間の単位はミリ秒。
a+b | 17 | 17 | 17 |
a-b | 26 | 26 | 28 |
a*b | 20 | 18 | 20 |
a/b | 16 | 17 | 18 |
a**b | 156 | 157 | 157 |
abs(a) | 29 | 27 | 30 |
abs(b) | 30 | 29 | 30 |
sqrt(a) | 29 | 30 | 31 |
sin(a) | 71 | 71 | 71 |
cos(a) | 59 | 61 | 61 |
tan(a) | 83 | 84 | 84 |
asin(a) | 125 | 128 | 128 |
acos(a) | 124 | 127 | 125 |
atan(a) | 85 | 84 | 87 |
atan2(a) | 138 | 140 | 146 |
exp(a) | 15 | 17 | 17 |
log(a) | 15 | 17 | 18 |
random(a) | 26 | 27 | 27 |
実行環境2
- 自作PC
- Intel Core i5-4670/3.40GHz
- RAM 4.00GB
a+b | 9 | 10 | 9 |
a-b | 12 | 11 | 12 |
a*b | 7 | 9 | 7 |
a/b | 7 | 7 | 7 |
a**b | 72 | 71 | 72 |
abs(a) | 11 | 12 | 17 |
abs(b) | 12 | 17 | 12 |
sqrt(a) | 13 | 13 | 13 |
sin(a) | 27 | 25 | 23 |
cos(a) | 24 | 25 | 25 |
tan(a) | 43 | 43 | 42 |
asin(a) | 53 | 53 | 54 |
acos(a) | 53 | 50 | 51 |
atan(a) | 41 | 41 | 41 |
atan2(a) | 61 | 62 | 58 |
exp(a) | 7 | 7 | 8 |
log(a) | 6 | 7 | 7 |
random(a) | 12 | 13 | 12 |
テストコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
a = 1.1 b = -2.2 sTime = new Date().valueOf() for i in [1..1000000] x = a + b eTime = new Date().valueOf() console.log("+ #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = a - b eTime = new Date().valueOf() console.log("- #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = a * b eTime = new Date().valueOf() console.log("* #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = a / b eTime = new Date().valueOf() console.log("/ #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = a ** b eTime = new Date().valueOf() console.log("** #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.abs(a) eTime = new Date().valueOf() console.log("abs(+) #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.abs(b) eTime = new Date().valueOf() console.log("abs(-) #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.sqrt(a) eTime = new Date().valueOf() console.log("sqrt() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.sin(a) eTime = new Date().valueOf() console.log("sin() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.cos(a) eTime = new Date().valueOf() console.log("cos() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.tan(a) eTime = new Date().valueOf() console.log("tan() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.asin(a) eTime = new Date().valueOf() console.log("asin() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.acos(a) eTime = new Date().valueOf() console.log("acos() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.atan(a) eTime = new Date().valueOf() console.log("atan() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.atan2(a) eTime = new Date().valueOf() console.log("atan2() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.exp(a) eTime = new Date().valueOf() console.log("exp() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.log(a) eTime = new Date().valueOf() console.log("log() #{eTime - sTime}ms") sTime = eTime for i in [1..1000000] x = Math.random() eTime = new Date().valueOf() console.log("random() #{eTime - sTime}ms") sTime = eTime |