◆順列組合せの公式はΠ(総乗)を使うべき
順列組合せの算出方法
n個からr個取り出す取り出し方の数を出したいことは極めて頻繁にあります。
取り出したものの順番を気にするものを「順列」、順番はどうでもよい場合を「組み合わせ」といいます。
「順列の算出法」はとても簡単で、
- nから順に1を引きながら、r回かけていく
例えば7個から3個とりだすなら7×6×5=210となります。10個から2個なら、 10×9=90です。
冒頭の図のΠ(直積)はΣ(総和)の掛け算版というべきもので、ある値から
1ずつインクリメントして最後の値まで掛け算を行います。
「直積」より「総乗」と呼ぶ方が適切ではあります。
「組合せの算出法」はrrをrとn-rの小さい方として
- 順列(n,rr)の値をrrの階乗で割る
例えば7個から3個取り出すなら(7×6×5)/(3×2)=35となります。10個から2個なら、 (10×9)/2=45です。10個から8個取り出すのは10個から2個と同じ(10×9)/2=45となります。
順列組合せの一般的なトリッキーで愚かな公式
一般的な順列の公式ではΠ(直積/総乗)は用いません。
その代わりのおぞましいトリックを用います。
トリックとは、掛け算を途中で止めることを、それ以下の 掛け算で割ることで「表す」やり方で、 例えば5×4を得るのに(5×4×3×2×1)/(3×2×1)を 計算するという形のものです。
- 5!/3!=(5×4×3×2×1)/(3×2×1)=5×4
n!/(n-r)!を見てその意味(階乗を計算するのではなく、途中まで掛け算をするだけ) を直ちに把握することは困難で、 それゆえ覚えにくいものとなっています。
さらに、意味を把握することなく単純に無意味な計算を行いがちに
なります。
例えばn=10,r=2ならnPrは10×9と簡単なものであるにも関わらず
一旦10!(なんと3628800)を計算した上で8!(40430)を計算し、割り算
を行うという愚かな作業を「意味を考えない教条主義者は」
実行することも考えられます。
例えば7個から2個選ぶという設問に対し7×6=42と即座に計算した生徒に対し
「ずるをするな。ちゃんと7の階乗と5の階乗を計算しなさい」と先生は言い
「この公式はそういう意味じゃないんですよ」と生徒が丁寧に説明すると
「先生をバカにするのか!」と怒り出し、大きな木製の三角定規で生徒になぐり
かかるといった事態が起こるかも知れません。(あるかも知れないというだけですよ。まあ、
近いことはありました)
直積/総乗をつかった公式に置き換えよう
現在教科書,参考書に載っている公式
このトリッキーな公式が本来の単純な理屈を分かりづらくし、覚えづらくしています。
Π(直積/総乗)を使った公式
「Πなんて記号は教えていないから使えない」などというのは愚劣な言い訳に すぎません。教えればいいのです。Σが使えるならΣの掛け算版のΠが使えない 理由はありません。
階乗の導入だけで済むというのも説得力があるとは思えません。基本要素の 種類が少なくすんでも表現が誤解を生むものになるのでは「楽」とは言えません。
直積/総乗記号に次のような表記方があればさらにスマートになります。
実際の値:参考
おおよそどの程度の値になるのか参考までに表を載せます。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
1 | 1 | |||||||||
2 | 2 | 2 | ||||||||
3 | 3 | 6 | 6 | |||||||
4 | 4 | 12 | 24 | 24 | ||||||
5 | 5 | 20 | 60 | 120 | 120 | |||||
6 | 6 | 30 | 120 | 360 | 720 | 720 | ||||
7 | 7 | 42 | 210 | 840 | 2520 | 5040 | 5040 | |||
8 | 8 | 56 | 336 | 1680 | 6720 | 20160 | 40320 | 40320 | ||
9 | 9 | 72 | 504 | 3024 | 15120 | 60480 | 181440 | 362880 | 362880 | |
10 | 10 | 90 | 720 | 5040 | 30240 | 151200 | 604800 | 1814400 | 3628800 | 3628800 |
nCr 組合せ表
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
1 | 1 | |||||||||
2 | 2 | 1 | ||||||||
3 | 3 | 3 | 1 | |||||||
4 | 4 | 6 | 4 | 1 | ||||||
5 | 5 | 10 | 10 | 5 | 1 | |||||
6 | 6 | 15 | 20 | 15 | 6 | 1 | ||||
7 | 7 | 21 | 35 | 35 | 21 | 7 | 1 | |||
8 | 8 | 28 | 56 | 70 | 56 | 28 | 8 | 1 | ||
9 | 9 | 36 | 84 | 126 | 126 | 84 | 36 | 9 | 1 | |
10 | 10 | 45 | 120 | 210 | 252 | 210 | 120 | 45 | 10 | 1 |
単純な計算機を載せます。
nとrに値を入れて[計算する]をクリックするとnPr,nCrの
計算を行います。
[nU][nD][rU][rD]はn,rを増加/減少させます。
次の計算を行っています。
function calcP(n,r){ var p=1; for(var i=0;i<r;++i) p *= n--; return p; } function calcC(n,r){ var rr=Math.min(r,n-r); var p=1; for(var i=2;i<=rr;++i) p /= i; return p; }なお整数でなく実数で計算するなら次の形で計算すれば組合せの オーバーフローの可能性を少し減らすことができます。
function calcC(n,r){ var rr=Math.min(r,n-r); var p=1; for(var i=1;i<=rr;++i) p = (p*n--)/i; return p; }2015/3/21:さらなる巨大数値での演算機を □2000個から1000個選ぶ!巨大組合せ計算式に置きました。
###
2015/3/16
この記事の本題ではありませんが組合せの処理にr=min(r,n-r)を入れました。
10000個から9999個を選ぶ組合せ数(10000C9999)などの値もオーバーフローすることなく取得できます。
2015/3/20
組合せ計算のオーバーフローを少し減らすやり方を追加しました。
1000個から500個
を選ぶ場合2.70×10の299乗になります。javascriptの数値の最大は1.8×10の308乗
のため、このやり方を採用するとぎりぎりオーバーフロー無しで計算できます。
ただし、整数では途中割り切れない値となる可能性がありこの方法は採れません。
割り切れる形での手法は検討中です。
| 固定リンク