数値クラスに逆数を取得するメソッドを追加（＋refinementsの勉強）

Rubyで時々「数値の逆数くらいメソッドで取得したい」と思うことがある。メソッドがあれば、数式を書いて括弧で括ったりする手間が省ける。

```ruby:例
(1 / num).abs
# ↓
num.inverse.abs
```

無ければ作ればいいだけだが、いい機会なのでrefinementsを初めて利用してみる。ついでにモジュラ逆数の計算方法を写経する。

（追記）せっかく作ったのでgem化した。refinements無しも添付したため、利用は選択可能。
https://rubygems.org/gems/numeric_inverse

## コード
refinementsによるメソッド定義方法は簡単だった。

* 通常のパッチでは単に既存クラスを開く、つまり `class XXX; ...; end` と書く。（モジュールも可）
* refinementsでは適当なモジュールを作成し、その中で `refine(XXX) do; ...; end` と書く（ [`Module#refine`](https://docs.ruby-lang.org/ja/latest/method/Module/i/refine.html) を呼び出す）。 `...` の部分は変わらない。

---

逆数を求めるメソッド `#inverse` は以下のように実装する。

* 基本的には親クラスである `Numeric` に `1/self` を計算するメソッドを追加するだけでいい
	* `Integer`, `Rational`, `Float`, `Complex` など子クラスはこれを呼び出すことになる
	* `Integer#/` は整商を求めてしまうので、 `#/` でなく `#quo` を明示的に使う方が良い
* せっかくなので、整数クラス `Integer` ではオーバーライドして工夫をしておく
	* 整数論では「[モジュラ逆数](https://ja.wikipedia.org/wiki/モジュラ逆数)」というものが存在するので、引数に法を与えたらそちらを計算できるようにする
	* 通常の逆数も、わざわざ `super()` を呼んで割り算をせず、直接 `Rational` を作成してしまえばいい
* メソッド名が長いと使うときに結局面倒なので、別名 `#inv` も作っておく

```ruby:numeric_inverse.rb
module NumericInverse
	refine Numeric do
		##
		# Returns its inverse.
		#
		# @return [Numeric] inverse
		#
		def inverse
			1.quo(self)
		end

		alias inv inverse
	end

	refine Integer do
		##
		# Returns its inverse.
		#
		# @overload inverse
		#   @return [Rational] inverse
		# @overload inverse(m)
		#   @param m [Integer] modulus
		#   @return [Integer] modular multiplicative inverse
		#   @raise [ArgumentError] if +m+ is not coprime to +self+
		#
		def inverse(m = nil)
			return Rational(1, self) if m.nil?

			# extended Euclidean algorithm
			a, b, u, v = self, m, 1, 0
			until b.zero?
				a, (t, b) = b, a.divmod(b)
				u, v = v, u - t * v
			end

			# u is an inverse iff self.gcd(m) == 1
			if a.abs != 1
				raise ArgumentError,
				      "modulus is not coprime to the receiver" 
			end

			u = -u if a < 0
			u % m   # 0 <= u < m || m < u <= 0
		end

		alias inv inverse
	end
end
```

一応yardocを書いてみたが、ドキュメントはうまく生成されなかった。（yard 0.9.16）

## 利用
[`main.using`](https://docs.ruby-lang.org/ja/latest/method/main/s/using.html) または [`Module#using`](https://docs.ruby-lang.org/ja/latest/method/Module/i/using.html) を呼び出すことで、以降それに応じた範囲内（ファイル内／モジュール定義内）で利用できるようになる。

```ruby
# モジュールを定義しただけでは使えない
require './numeric_inverse'
p Rational(1227, 2018).inv   #=> NoMethodError

# `#using` を呼び出すと、スコープ内で使えるようになる
using NumericInverse
p Rational(1227, 2018).inv   #=> (2018/1227)
```

---

一緒に定義した `Integer#inverse` もきちんと機能している。

```ruby
require './numeric_inverse'
using NumericInverse

# 整数の普通の逆数
p 63.inv        #=> (1/63)
p 63.inv * 63   #=> (1/1)

# モジュラ逆数
p 63.inv(100)              #=> 27
p 63.inv(100) * 63         #=> 1701
p 63.inv(100) * 63 % 100   #=> 1
```

### irbでのエラー対策
irbで上記コードを試すと、 `using` のところでエラーが出る。

```irb
irb(main):001:0> require './numeric_inverse'
=> true
irb(main):002:0> using NumericInverse
RuntimeError: main.using is permitted only at toplevel
	from (irb):2:in `using'
	from (irb):2
	from /usr/bin/irb:11:in `<main>'
```

これを避けるには、irb起動時に `--context-mode=1` オプションを追加する。（3未満の数なら良いが、0だと例外バックトレースが長くなるとのこと。）

## 参考

* refinements
	* [instance method Module#refine - Rubyリファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/method/Module/i/refine.html)
	* [refinements - Documentation for Ruby trunk](https://docs.ruby-lang.org/en/trunk/syntax/refinements_rdoc.html)
	* [YARD does not generate documentation for refinements · Issue #780 · lsegal/yard](https://github.com/lsegal/yard/issues/780)
	* [Bug #9580: Refinements regression in IRB - Ruby trunk - Ruby Issue Tracking System](https://bugs.ruby-lang.org/issues/9580#note-4)
* モジュラ逆数
	* [逆数 - Wikipedia](https://ja.wikipedia.org/wiki/逆数)
	* [モジュラ逆数 - Wikipedia](https://ja.wikipedia.org/wiki/モジュラ逆数)
	* [Extended Euclidean algorithm - Wikipedia](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)
	* [pow_mod, inverse の速度 - (iwi) ｛ 反省します - TopCoder部](https://topcoder.g.hatena.ne.jp/iwiwi/20130105/1357363348) ： こちらのページのコードを参考に実装した