(JAPLA 2005/09/24)
「幸運数(fortune number):改定版」について
帝京平成大学 鈴木義一郎
ある数を1桁の数値に分解して、各数値の平方和を次の数値とする。例えば
": 13
13
,.": 13
1
3
".,.": 13
1 3
,.&.": 13
1 3
【1桁の数値に分解している】
([:*:,.&.":) 13
1 9
分解した各数値を平方している。
(next=:[:+/[:*:,.&.":) 13
10
【1桁の数値に分解した各数値の平方和を算出して「次の数」を出力するのが「next」という関数である】
next^:1 2(13)
10 1
このような“操作”で「1」に推移したとき、「13」を「fortune number」と名づける。
next^:1 2(37)
58 89
next^:1 2 3 4 5 6 7 8(37)
58 89 145 42 20 4 16 37
最初の数「37」に戻ってしまったので、この後は同じ数字を循環するだけだから1に推移することはないので、「unfortune(number)」と名づける。
]s1=:next^:1 2 3 4 5 6 7 8(4)
16 37 58 89 145 42 20 4
]s2=:next^:1 2 3 4 5 6 7 8 9(4)
16 37 58 89 145 42 20 4 16
s1-:~.s1
1
s2-:~.s2
0
【(重複要素が無ければ「1」、あれば「0」になる。“-:”は集合として一致すれば“1”を与える原子動詞で、“~.”は「重複要素を排除する」という原子動詞である)
次に右引数で与えた数に対して、1に推移する(fortune)か、循環列に入った(unfortune)ところで「stop」する片側関数を、次のように定義する。
reg_no=:3 :0
k=.#s=.r=.(next=.[:+/[:*:,.&.":)y.
while. k=1
do. k=.s-:~.s=.s,r=.next r
end.
}:s
)
reg_no 2
4 16 37 58 89 145 42 20
reg_no 3
9 81 65 61 37 58 89 145 42 20 4 16
reg_no 4
16 37 58 89 145 42 20 4
reg_no 5
25 29 85 89 145 42 20 4 16 37 58
reg_no 6
36 45 41 17 50 25 29 85 89 145 42 20
4 16 37 58
reg_no 7
49 97 130 10 1
reg_no 8
64 52 29 85 89 145 42 20 4 16 37 58
reg_no 9
81 65 61 37 58 89 145 42 20 4 16
reg_no 10
1
reg_no 11
2 4 16 37 58 89 145 42 20
reg_no 12
5 25 29 85 89 145 42 20 4 16 37 58
reg_no 13
10 1
reg_no 14
17 50 25 29 85 89 145 42 20 4 16 37
58
reg_no 15
26 40 16 37 58 89 145 42 20 4
更に、「100」までこの関数を適用した結果から、循環列に入るケースは
c=:4 16 61 20 24 42 37 73 58 85 89 98
145 154 415 451 514 541
といった数値のいずれかに推移したときに循環列に入ることが確かめられる。
次に、右引数で与えた数字以下のfortune number を出力する片側関数を以下のように定義する。
fortune=:3 :0
f=.r=.1
while. r<y.
do. f=.f,(1={:reg_no r)#r=.r+1
end.
)
fortune 15
1 7 10 13
fortune 100
1 7 10 13 19 23 28 31 32 44 49 68 70
79 82 86 91 94 97 100
以下では、fortune number の個数だけを調べてみる。
# fortune 1000
143
# fortune 10000
1442
# fortune 100000
14377
6!:2'n=.fortune 1000000'
4362.72
(計算時間は1時間強を要した!)
# n
143071
以上の結果から、fortune
number の個数の割合は、14%強含まれていることが分かる。
さらに、fortune
number の個数が10等分した範囲にどの程度一様に分布しているかについて調べてみると、「n」には1000000 以下のfortune
numberが入力されているから
+/"1=<.(143{.n)%100
19 13 12 22 10 5 19 11 13 18 1
+/"1=<.(1442{.n)%1000
142 156 144 162 130 150 129 149 149
130 1
+/"1=<.(14377{.n)%10000
1441 1597 1601 1448 1537 1464 1237
1434 1338 1279 1
+/"1=<.n%100000
14376 14861 15003 14341 14205 14386
13841 14313 14172 13572 1
次の関数は、fortune number かunfortune(number)かを判定し、さらに判定に至るまでに要したステップ数と循環列にはいったときの数を出力するものである。
judge=:3 :0
s=.r=.(next=.[:+/[:*:,.&.":)y.
c=.4 16 61 20 24 42 37 73 58 85
c=.c,89 98 145 154 415 451 514 541
while.-.r e.1,c
do. s=.s,r=.next r
end.
if.r=1
do.(#s);'fortune'else.(#s);r;'unfortune' end.
)
judge 2
1 |
4 |
Unfortune |
judge 6
8 |
85 |
Unfortune |
judge 7
5 |
Fortune |
judge 13
2 |
Fortune |
judge 14
5 |
85 |
Unfortune |
judge 77
1 |
98 |
Unfortune |
judge 89
1 |
145 |
unfortune |
judge 999
3 |
85 |
Unfortune |
judge 9999
3 |
85 |
Unfortune |
judge 99999
7 |
85 |
Unfortune |
judge 899999
7 |
Fortune |
以上の適用結果をみると、数字が大きくなってもfortune number かunfortune(number)かの判定に要するステップ数は存外多くはならないことが予想される。
freq=:3 :0
next=.[:+/[:*:,.&.":
f=.1+i.20+s=.q=.0
c=.4 16 61 20 24 42 37 73 58 85
c=.c,89 98 145 154 415 451 514 541
while. s<y.
do.p=.r=.next s=.s+1
while.-.r e.1,c do.p=.p,r=.next r end.
q=.q+f=#p
end.
)
freq 14
4 2 2 3 2 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
freq 100
26 15 19 20 11 3 4 2 0 0 0 0 0 0 0 0 0 0 0 0
freq 1000
118 135 170 176 170 116 66 31 6 12 0 0 0 0 0 0 0 0 0 0
freq 10000
681 811 1404 2015 2041 1430 888 529 117 84 0 0 0 0 0 0 0 0 0 0
freq 100000
4202 7980 12516 19087 20181 16786 9957 6341 1560 1290 100 0 0 0 0 0 0 0 0 0
freq 1000000
25823 84229 125199 184273 190195 186849 104776 63158 19058 13980 2460 0 0 0 0 0 0 0 0 0
一般に、p進数の場合についても同じ問題を考えてみよう。
10進数の数値をp進数に変換する関数を次のように定義する。
p_10=:13 :'((>.x.^.1+y.)$x.)#:y.'
regp_no=:4 :0
p_10=.(([:>.[^.1:+])$[)#:]
(t=.q=.+/*:r);s=.<r=.y. [ d=.1
while. d=1 do.
(t=.t,q=.+/*:r);s=.s,<r=.x.p_10 q
(t;s) [ d=.t-:~.t
end.
)
5 regp_no 1 1
2 4 16 10 4 |
1 1 |
2 |
4 |
3 1 |
2 0 |
8 regp_no 1 1
2 4 16 4 |
1 1 |
2 |
4 |
2 0 |
8 regp_no 1 2
5 25 10 5 |
1 2 |
5 |
3 1 |
1 2 |
8 regp_no 1 3
10 5 25 10 |
1 3 |
1 2 |
5 |
3 1 |
は「1」に収束しているので fortune number である。
8 regp_no 1 4
17 5 25 10 5 |
1 4 |
2 1 |
5 |
3 1 |
1 2 |
8 regp_no 1 5
26 13 26 |
1 5 |
3 2 |
1 5 |
8 regp_no 1 6
37 41 26 13 26 |
1 6 |
4 5 |
5 1 |
3 2 |
1 5 |
8 regp_no 1 7
50 40 25 10 5 25 |
1 7 |
6 2 |
5 0 |
3 2 |
1 2 |
5 |
8 regp_no 2 0
4 16 4 |
2 0 |
4 |
2 0 |
8 regp_no 2 1
5 25 10 5 |
2 1 |
5 |
3 1 |
1 2 |
8 regp_no 2 2
8 1 1 |
2 2 |
1 0 |
1 |
は「1」に収束しているので fortune number である。
8 regp_no 2 3
13 26 13 |
2 3 |
1 5 |
3 2 |
8 regp_no 2 4
20 20 |
2 4 |
2 4 |
8 regp_no 2 5
29 34 20 20 |
2 5 |
3 5 |
4 2 |
2 4 |
8 regp_no 2 6
40 25 10 5 25 |
2 6 |
5 0 |
3 1 |
1 2 |
5 |
8 regp_no 2 7
53 61 74 6 36 32 16 4 16 |
1 7 |
6 5 |
7 5 |
1 1 2 |
6 |
4 4 |
4 0 |
2 0 |
4 |
8 regp_no 7 0
49 37 41 26 13 26 |
7 0 |
6 1 |
4 5 |
5 1 |
3 2 |
1 5 |
8 regp_no 7 1
50 40 25 10 5 25 |
7 1 |
6 2 |
5 0 |
3 1 |
1 2 |
5 |
8 regp_no 7 2
53 61 74 6 36 32 16 4 16 |
7 2 |
6 5 |
7 5 |
1 1 2 |
6 |
4 4 |
4 0 |
2 0 |
4 |
8 regp_no 7 3
58 53 61 74 6 36 32 16 4 16 |
7 3 |
7 2 |
6 5 |
7 5 |
1 1 2 |
6 |
4 4 |
4 0 |
2 0 |
4 |
8 regp_no 7 4
65 2 4 16 4 |
7 4 |
1 0 1 |
2 |
4 |
2 0 |
8 regp_no 7 5
74 6 36 32 16 4 16 |
7 5 |
1 1 2 |
6 |
4 4 |
4 0 |
2 0 |
4 |
8 regp_no 7 6
85 30 45 50 40 25 10 5 25 |
7 6 |
1 2 5 |
3 6 |
5 5 |
6 2 |
5 0 |
3 1 |
1 2 |
5 |
8 regp_no 7 7
98 21
29 34 20 20 |
7 7 |
1 4 2 |
2 5 |
3 5 |
4 2 |
2 4 |
最後に、右引数に10進法で与えた数以下のp進数のfortune numberを出力する両側関数を次のように定義する。
fortunep=:4 :0
p_10=.(([:>.[^.1:+])$[)#:]
r=.1+#f=.''
while. r<y.
do. t=.x.regp_no
x.p_10 r=.r+1
f=.f,(1=+/*:,.&.":{:>{.t)#1{t
end.
)
8 fortunep 11
1 0 |
1 3 |
8 fortunep 25
1 0 |
1 3 |
2 2 |
3 1 |
8 fortunep 80
1 0 |
1 3 |
2 2 |
3 1 |
3 3 |
1 0 0 |
1 0 3 |
1 1 3 |
1 1 4 |
1 1 5 |
8 regp_no 1 1 3
11 10
5 25 10 |
1 1 3
|
1 3 |
1 2 |
5 |
3 1 |
8 regp_no 1 1 4
18 8
1 1 |
1 1 4 |
2 2 |
1 0 |
1 |
8 regp_no 1 1 5
27 18
8 1 1 |
1 1 5 |
3 3 |
2 2 |
1 0 |
1 |