Rubyのインクリメント速度のバージョンごとの比較

## TL;DR

Rubyでは `i++` ができない。
たまたま `i++` しようとしたらエラーになったのでそういえばインクリメント演算子がRubyだと出来なかった気がするなと思い、念のために調べてみた。

公式ドキュメントじゃないけど、割と自明な話しだと思うので公式ではなく個人のテックブログを参照した。詳細に調べられていたので問題ないかなと思う。
そして恐らくだが以前も同じブログを参照した気がする。

[Ruby にインクリメント演算子のようなものが無い理由](https://blog.tokoyax.com/entry/ruby/increment)

選択肢としては`i += 1`と`i.succ`、`i.next`の3パターンあるがなにが違うのか気になったので調べたところ先人がすでに調べていた。

[RubyのIntegerにおけるsuccとnext](http://simanman.hatenablog.com/entry/2014/04/28/005436)

ただこの記事も前述の記事も2014年〜2015年なので現在のRubyバージョンでは状況が変わっている可能性があるし、なんなら自分が問題を起こしたバージョン(ruby@2.4.1p111)とで結果が異なる可能性があるのではないか？と思い、せっかくなので調べてみた。

## 結論:
3つの中で`succ`が比較的安定、速い。
次点で`i += 1`、`next`はFixnumで他に比べて遅い。

Rubyでインクリメントしたいとき、普段は `i += 1`か `i.succ`を使う。
パフォーマンスが気になる箇所では `i.succ` を使うのがベター。次点で`i += 1`、`i.next`を使ってたらレビューで指摘してあげたほうがいいかもしれない……くらいかな。

2つ目のブログで書かれている状態とほぼ同じ結果になったのでおそらくは原因も同じと推測される。
各バージョンのコードまでは検証するつもりがなかったので省略してるけど多分同じなんだろうと思う。

## 検証環境:

```
MacOS version 10.14.5（18F132)
MacBook Pro (Retina, 15-inch, Late 2013)
プロセッサ 2.3 GHz Intel Core i7
memory 16 GB 1600 MHz DDR3
```

## 検証項目:

各バージョンの最新 + 問題を起こしたバージョンで検証。
本来は何度か実行してその平均値で出すんだろうけどメンドイので1回しかやってないので何かの検証目的でいる場合はサンプルデータ1くらいの扱いでお願いします。

検証コードは2つ目のブログの検証コードをそのまま流用。
理由としては計測する方法が変わると期待する結果も変わってしまう可能性があるため、できるだけ条件を同じにしたかったから。

実行したコード（ファイル名が違うだけ）

```example.ruby

require 'benchmark'

Benchmark.bm do |x|
  cnt = 100000000
  fixnum = 1
  bignum = 1 << 64


  x.report("+=1 Fixnum") do
    a = fixnum
    cnt.times{ a += 1 }
  end

  # Fixnum#succ
  x.report("Fixnum succ") do
    a = fixnum
    cnt.times{ a = a.succ }
  end

  # Fixnum#next
  x.report("Fixnum next") do
    a = fixnum
    cnt.times{ a = a.next }
  end

  x.report("+=1 Bignum") do
    a = bignum
    cnt.times{ a += 1 }
  end

  # Bignum#succ
  x.report("Bignum succ") do
    a = bignum
    cnt.times{ a = a.succ }
  end

  # Bignum#next
  x.report("Bignum_next") do
    a = bignum
    cnt.times{ a = a.next }
  end
end
```

### ruby@2.4.1p111

Fixnumのときの`next`だけが遅い。ブログの現象と同じ。

```bash
$ ruby example.rb
        user     system      total        real
 +=1 Fixnum  4.720000   0.000000   4.720000 (  4.724997)
 Fixnum succ  4.720000   0.000000   4.720000 (  4.727951)
 Fixnum next  5.870000   0.010000   5.880000 (  5.879860)
 +=1 Bignum 10.570000   0.000000  10.570000 ( 10.582265)
 Bignum succ 10.340000   0.010000  10.350000 ( 10.354154)
 Bignum_next 10.110000   0.010000  10.120000 ( 10.121698)
```

### ruby@2.6.3

Fixnumで`next`だけが遅いという現象が発生してたのでこれはなにか別のアプリケーションが影響してるのか？と思ってもう一回実行したんだけど結果ほぼ変わらずだったのでどうやら`next`がFixnumのときだけ遅いっぽい。

```bash
$ ruby example.rb
       user     system      total        real
+=1 Fixnum  5.052053   0.007104   5.059157 (  5.068701)
Fixnum succ  4.829195   0.004266   4.833461 (  4.840140)
Fixnum next  6.159282   0.002336   6.161618 (  6.165148)
+=1 Bignum 10.592028   0.004909  10.596937 ( 10.601052)
Bignum succ 10.377451   0.003914  10.381365 ( 10.384787)
Bignum_next 10.320459   0.003760  10.324219 ( 10.327414)
```

### ruby@2.5.5

こちらもブログの現象と同じといえる。

```bash
$ ruby example.rb
       user     system      total        real
+=1 Fixnum  4.719072   0.001677   4.720749 (  4.722440)
Fixnum succ  4.651602   0.001740   4.653342 (  4.654881)
Fixnum next  5.748883   0.001787   5.750670 (  5.752244)
+=1 Bignum 10.454205   0.007352  10.461557 ( 10.471455)
Bignum succ 10.872434   0.028426  10.900860 ( 10.935718)
Bignum_next 10.624259   0.024823  10.649082 ( 10.674851)
```

### ruby@2.4.6

ブログの（ｒｙ

```bash
ruby example.rb
       user     system      total        real
+=1 Fixnum  4.430000   0.000000   4.430000 (  4.437439)
Fixnum succ  4.570000   0.020000   4.590000 (  4.615233)
Fixnum next  5.950000   0.020000   5.970000 (  6.008219)
+=1 Bignum 10.600000   0.030000  10.630000 ( 10.660327)
Bignum succ 10.050000   0.020000  10.070000 ( 10.093179)
Bignum_next 10.370000   0.020000  10.390000 ( 10.410649)
```

### ruby@2.3.7

たまたまなのかもしれないけど一番古いRubyのバージョンが一番遅いだろうとなんとなく考えていたが結果が真逆だったのが面白い。
昔のほうが特定の条件下では高速に動作するのか。
とはいえそのためにあえて`2.3.7`使うひとはいないと思うけど、どうしても速度がほしいなら別の言語選ぶだろうしな。

```bash
ruby example.rb                                                                                                  [05 30 00:37:43]
       user     system      total        real
+=1 Fixnum  4.170000   0.000000   4.170000 (  4.173693)
Fixnum succ  4.150000   0.000000   4.150000 (  4.154439)
Fixnum next  5.280000   0.000000   5.280000 (  5.282451)
+=1 Bignum  9.170000   0.000000   9.170000 (  9.176064)
Bignum succ  9.230000   0.010000   9.240000 (  9.233617)
Bignum_next  9.420000   0.000000   9.420000 (  9.428198)
```