AVX/AVX2によるSVML (Short Vector Mathematical Library)を使った計算

# はじめに

Intel SVML (Short Vector Mathematical Library)を使ったAVX/AVX2によるによる計算について説明します．

SVMLは，整数の除算や，三角関数，指数，対数，べき乗をSIMD計算するためのIntelによる関数ライブラリです．
SVMLライブラリの多くのルーチンはインテル製マイクロプロセッサ向けに高度に最適化されています．
AMD等の互換マイクロプロセッサーよりもIntelCPUでは速く動く可能性が高いです．

使用可能なコンパイラは，インテルコンパイラと，Visual Studio (2019から)です．
gccは，使えるかどうかわかりません．WSL上のUbuntuでは，デフォルトでは使えませんでした．
iccが無料で使えるようになっているので，gccではなくiccを使えば，UNIX系でも問題なくコードをコンパイルすることはできますが，これを使うと非常に互換性が下がると思ってください．
簡単な対応方法ってないんですかね．．．

なお，expやlogの計算はこれらよりも[fmath](https://github.com/herumi/fmath)のライブラリを使ったほうが速いです．



## 除算・余り
下記命令で整数の除算やその余りが計算できます．

* _mm256_div_epi|epu8|16|32|64
* _mm256_rem_epi|epu8|16|32|64

特定のサイズなら除算結果と余りを同時に求められます．

_mm256_divrem_epi32|epu32

## 三角関数
下記の基本的な三角関数群が使えます．

```cpp
extern __m256  _mm256_sin_ps(__m256);
extern __m256d _mm256_sin_pd(__m256d);
extern __m256  _mm256_cos_ps(__m256);
extern __m256d _mm256_cos_pd(__m256d);
extern __m256  _mm256_sincos_ps(__m256  * /*cos_res*/, __m256);
extern __m256d _mm256_sincos_pd(__m256d * /*cos_res*/, __m256d);
extern __m256  _mm256_tan_ps(__m256);
extern __m256d _mm256_tan_pd(__m256d);
extern __m256  _mm256_asin_ps(__m256);
extern __m256d _mm256_asin_pd(__m256d);
extern __m256  _mm256_acos_ps(__m256);
extern __m256d _mm256_acos_pd(__m256d);
extern __m256  _mm256_atan_ps(__m256);
extern __m256d _mm256_atan_pd(__m256d);
extern __m256  _mm256_atan2_ps(__m256, __m256);
extern __m256d _mm256_atan2_pd(__m256d, __m256d);
extern __m256  _mm256_sind_ps(__m256);
extern __m256d _mm256_sind_pd(__m256d);
extern __m256  _mm256_cosd_ps(__m256);
extern __m256d _mm256_cosd_pd(__m256d);
extern __m256  _mm256_tand_ps(__m256);
extern __m256d _mm256_tand_pd(__m256d);
extern __m256  _mm256_sinh_ps(__m256);
extern __m256d _mm256_sinh_pd(__m256d);
extern __m256  _mm256_cosh_ps(__m256);
extern __m256d _mm256_cosh_pd(__m256d);
extern __m256  _mm256_tanh_ps(__m256);
extern __m256d _mm256_tanh_pd(__m256d);
extern __m256  _mm256_asinh_ps(__m256);
extern __m256d _mm256_asinh_pd(__m256d);
extern __m256  _mm256_acosh_ps(__m256);
extern __m256d _mm256_acosh_pd(__m256d);
extern __m256  _mm256_atanh_ps(__m256);
extern __m256d _mm256_atanh_pd(__m256d);
```

## 指数・対数計算
下記，指数計算・対数計算が可能です．

|func |math  |
|:---:|:----:|
|exp2 | 2^x  |
|exp  | e^x  |
|expm1| e^x-1|
|x^y  | pow  |

|func |math       |
|:---:|:---------:|
|log2 | log_2(x)  |
|log10| log_10(x) |
|log  | log_e(x)  |
|log1p| log_e(1+x)|

```cpp
extern __m256  _mm256_log_ps(__m256);
extern __m256d _mm256_log_pd(__m256d);
extern __m256  _mm256_log1p_ps(__m256);
extern __m256d _mm256_log1p_pd(__m256d);
extern __m256  _mm256_log10_ps(__m256);
extern __m256d _mm256_log10_pd(__m256d);
extern __m256  _mm256_log2_ps(__m256);
extern __m256d _mm256_log2_pd(__m256d);
extern __m256  _mm256_logb_ps(__m256);
extern __m256d _mm256_logb_pd(__m256d);
extern __m256  _mm256_exp_ps(__m256);
extern __m256d _mm256_exp_pd(__m256d);
extern __m256  _mm256_exp10_ps(__m256);
extern __m256d _mm256_exp10_pd(__m256d);
extern __m256  _mm256_exp2_ps(__m256);
extern __m256d _mm256_exp2_pd(__m256d);
extern __m256  _mm256_expm1_ps(__m256);
extern __m256d _mm256_expm1_pd(__m256d);
extern __m256  _mm256_pow_ps(__m256, __m256);
extern __m256d _mm256_pow_pd(__m256d, __m256d);
```

## 切り捨て，切り上げ，四捨五入，浮動小数点あまり
浮動小数点の整数化に関する演算ができます．

```cpp
extern __m256  _mm256_trunc_ps(__m256);
extern __m256d _mm256_trunc_pd(__m256d);
extern __m256  _mm256_svml_floor_ps(__m256);
extern __m256d _mm256_svml_floor_pd(__m256d);
extern __m256  _mm256_svml_ceil_ps(__m256);
extern __m256d _mm256_svml_ceil_pd(__m256d);
extern __m256  _mm256_svml_round_ps(__m256);
extern __m256d _mm256_svml_round_pd(__m256d);
extern __m256  _mm256_fmod_ps(__m256, __m256);
extern __m256d _mm256_fmod_pd(__m256d, __m256d);
```

## その他演算

* svml_sqrt: 平方根
* invsqrt: 逆数平行根（ニュートン法で高精度化済み）
* cbrt: 3乗根
* invcbrt: 逆数3乗根
* hypot:  hypotenuse, sqrt(x^2+y^2), L2ノルムの計算
* cdfnorm: 正規累積分布
* cdfnorminv: 逆数正規累積分布
* cexp: 複素exp
* clog: 複素対数
* csqrt: 複素平方根
* erf: 誤差関数
* inverf: 逆数誤差関数
* erfc: 相補誤差関数
* inverfc: 逆数相補誤差関数

```cpp
extern __m256  _mm256_svml_sqrt_ps(__m256);
extern __m256d _mm256_svml_sqrt_pd(__m256d);
extern __m256  _mm256_invsqrt_ps(__m256);
extern __m256d _mm256_invsqrt_pd(__m256d);
extern __m256  _mm256_cbrt_ps(__m256);
extern __m256d _mm256_cbrt_pd(__m256d);
extern __m256  _mm256_invcbrt_ps(__m256);
extern __m256d _mm256_invcbrt_pd(__m256d);
extern __m256  _mm256_hypot_ps(__m256, __m256);
extern __m256d _mm256_hypot_pd(__m256d, __m256d);
extern __m256  _mm256_cdfnorm_ps(__m256);
extern __m256d _mm256_cdfnorm_pd(__m256d);
extern __m256  _mm256_cdfnorminv_ps(__m256);
extern __m256d _mm256_cdfnorminv_pd(__m256d);
extern __m256  _mm256_cexp_ps(__m256);
extern __m256  _mm256_clog_ps(__m256);
extern __m256  _mm256_csqrt_ps(__m256);
extern __m256  _mm256_erf_ps(__m256);
extern __m256d _mm256_erf_pd(__m256d);
extern __m256  _mm256_erfc_ps(__m256);
extern __m256d _mm256_erfc_pd(__m256d);
extern __m256  _mm256_erfcinv_ps(__m256);
extern __m256d _mm256_erfcinv_pd(__m256d);
extern __m256  _mm256_erfinv_ps(__m256);
extern __m256d _mm256_erfinv_pd(__m256d);
```