再帰呼び出しをすると簡単に書くことができても,時間がかかりすぎるのをどうにかしたい。そこで,時間と空間のトレードオフという常套手段をとります。
以下のスクリプト(プログラム)は処理時間が短い代わりに,メモリをたくさん消費します。80?86系のマシンではつらいでしょうが,Mac だと軽いですね。
n1, n2 が 20 以下の全ての場合の分布表が Macintosh Quadra 840AV で,結果をファイルに書き出すときは90 秒でできます。u_table.awk では,n1=n2=10 だけの分布表を求めるだけで 90 秒かかったわけですから大きな違いですね。
このスクリプトを実行すると,かなり大きなファイル(1.3MB)ができあがります。
# u-statistics2.awk BEGIN { LIMIT = 20 # 上限値の設定 for (n1 = 1; n1 <= LIMIT; n1++) { if (n1 >= 3) { # 不要なメモリを解放 for (i = 0; i <= n1-2; i++) { for (j = 0; j <= i*(n1-2); j++) { delete u[n1-2,i,j] } } } u[n1,0,0] = 1 for (n2 = 1; n2 <= n1; n2++) { printf "\n\n n1 = %i n2 = %i\n\n", n1, n2 m1 = max(n1, n2-1) m2 = min(n1, n2-1) for (i = 0; i < m1*m2+1; i++) { u[n1,n2,i] = u[m1,m2,i] } m1 = max(n1-1, n2) m2 = min(n1-1, n2) num = m1*m2+1 d_start = n1*n2-num+1 for (i = 0; i < num; i++) { u[n1,n2,d_start+i] += u[m1,m2,i] } denom = 1/combination(n1+n2, n2) cum2 = 1 cum1 = 0 printf "%3s:%10s %13s%13s%13s\n", "U", "度数", "確率", "累積1", "累積2" for (i = 0; i < n1*n2+1; i++) { x = u[n1,n2,i] y = x*denom cum1 += y printf "%3i:%10i %13.10f%13.10f%13.10f\n", i, x, y, cum1, cum2 cum2 -= y } } } } # n から m (n ≧ m ≧ 0 )を取り出す組合せを求める # 使用例: x = combination(10, 5) function combination(n, m, i, c) { c = 1 k = min(n, n-m) for (i = 1; i <= k; i++) { c *= (n-i+1)/i } return c } # x, y の大きい方を求める # 使用例: x = max(10, 5) function max(x, y) { return (x > y) ? x : y } # x, y の小さい方を求める # 使用例: x = min(10, 5) function min(x, y) { return (x < y) ? x : y }