Ruby で二項係数の計算をしてみました。(各種計算式を使用して)
0. 前提条件
- Debian GNU/Linux 10.2 (64bit) での作業を想定。
- Ruby 2.7.0 での作業を想定。
1. 二項係数について
個の物から 個のものを選ぶ組み合わせは 通りあり、 とも表す。また、二項級数(二項定理)の係数であることから、 とも呼ばれる。
以下、二項係数の主な重要性質。
2. Ruby スクリプトの作成
- 4種の計算式を使用する。(前述の (1), (2), (3), (4))
(使用する計算式(メソッド)の切り替えはコメント/アンコメントで) - Shebang ストリング(1行目)では、フルパスでコマンド指定している。(当方の慣習)
まず、計算用モジュール。
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 |
|
そして、実行部分。
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 |
|
3. Ruby スクリプトの実行
使用する計算式を指定(binom_1
〜 binom_4
のどれか1つをアンコメント)し、(実行権限付与後)実行。
( を で表示)
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 |
|
(実際には、折り返しはない)
4. ベンチマーク
N=100, R=3 として 10,000 回実行した場合のベンチマークをとってみた。
File: bm_binom.rb
#! /usr/local/bin/ruby
#***************************************************
# 二項係数の計算
#
# DATE AUTHOR VERSION
# 2019.10.19 mk-mode.com 1.00 新規作成
#
# Copyright(C) 2019 mk-mode.com All Rights Reserved.
#***************************************************
#
require 'benchmark'
require './binom_coeff'
class BmBinom
include BinomCoeff
N = 100
R = 3
LOOP_CNT = 10000
# 計算
#
# 計算式
# 1. (n r) = n! / r!(n -r)!
# 2. (n r) = ((n - 1) r) + ((n - 1) (k - 1))
# (recursively)
# 3. (n r) = (n / r) * ((n - 1) (k - 1))
# (recursively)
# 4. (n r) = Π(n - i + 1) / i (i = 1, ..., r)
#
# **注意**
# 計算式(2) では、 n と r の組み合わせにより重くなる。
def calc
Benchmark.bm(10) do |x|
x.report("TEST-1") do
LOOP_CNT.times { |_| binom_1(N, R) }
end
x.report("TEST-2") do
LOOP_CNT.times { |_| binom_2(N, R) }
end
x.report("TEST-3") do
LOOP_CNT.times { |_| binom_3(N, R) }
end
x.report("TEST-4") do
LOOP_CNT.times { |_| binom_4(N, R) }
end
end
rescue => e
msg = "[ERROR][#{self.class.name}.#{__method__}] #{e}\n"
msg << e.backtrace.map { |tr| "\t#{tr}" }.join("\n")
$stderr.puts msg
end
end
BmBinom.new.calc if __FILE__ == $0
1 2 3 4 5 6 |
|
今回使用した計算式の中では、(3) の (再帰的)が最速であった。
以上。