符号付き 32 ビット整数を英語で読めとのお達しで...
o1 = c("One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven",
"Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen")
o2 = c("", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety")
o3 = "Hundred"
o4 = c("Thousand", "Million", "Billion")
count = function(n) {
cat("n =", n, "\n")
ans = NULL
if (0 > n) {
ans = "Negative"
n = -n
}
s = unlist(strsplit(as.character(abs(n)), ""))
ns = length(s)
if (12 > ns) s = c(rep(0, 12 - ns), s)
s = matrix(as.numeric(s), ncol = 3, byrow = TRUE)
if (all(s == 0)) ans = "Zero"
for (i in 1:4) {
if (any(s[i, ] != 0)) {
if (s[i, 1] > 0) ans = c(ans, o1[s[i, 1]], o3)
if (s[i, 2] >= 2) {
ans = c(ans, o2[s[i, 2]])
if (s[i, 3] != 0) ans = c(ans, o1[s[i, 3]])
}
if (1 >= s[i, 2] && (s[i, 2] + s[i, 3] != 0)) ans = c(ans, o1[s[i, 2] * 10 + s[i, 3]])
if (3 >= i) ans = c(ans, o4[4 - i])
}
}
paste(ans, collapse = " ")
}
# テストデータ
q = c(7, 123, 4567, 89012, 0, -34, -5678901, 1111111111)
ans = c("Seven", "One Hundred Twenty Three", "Four Thousand Five Hundred Sixty Seven", "Eighty Nine Thousand Twelve",
"Zero", "Negative Thirty Four", "Negative Five Million Six Hundred Seventy Eight Thousand Nine Hundred One",
"One Billion One Hundred Eleven Million One Hundred Eleven Thousand One Hundred Eleven")
for (i in seq_along(q)) {
a = count(q[i])
cat("a: ", a, "\n")
cat("b: ", ans[i], "\n")
if (a != ans[i]) cat("Wrong!!\n\n")
}
結果は一応 OK
n = 7
a: Seven
b: Seven
n = 123
a: One Hundred Twenty Three
b: One Hundred Twenty Three
n = 4567
a: Four Thousand Five Hundred Sixty Seven
b: Four Thousand Five Hundred Sixty Seven
n = 89012
a: Eighty Nine Thousand Twelve
b: Eighty Nine Thousand Twelve
n = 0
a: Zero
b: Zero
n = -34
a: Negative Thirty Four
b: Negative Thirty Four
n = -5678901
a: Negative Five Million Six Hundred Seventy Eight Thousand Nine Hundred One
b: Negative Five Million Six Hundred Seventy Eight Thousand Nine Hundred One
n = 1111111111
a: One Billion One Hundred Eleven Million One Hundred Eleven Thousand One Hundred Eleven
b: One Billion One Hundred Eleven Million One Hundred Eleven Thousand One Hundred Eleven
「カプレカ数」での,二番目の定義によるものを出力するプログラム。
かなり時間のかかるプログラムであり,5 番目のカプレカ数を出力するまでには 35 秒かかる。
N = 631764
for (i in 0:N) {
str = unlist(strsplit(as.character(i), ""))
big = as.numeric(paste(sort(str, decreasing = TRUE), collapse=""))
small = as.numeric(paste(sort(str), collapse=""))
if (big - small == i) print(i)
}
[1] 0
[1] 495
[1] 6174
[1] 549945
[1] 631764
ユーザ システム 経過
34.915 0.202 34.773
0 から 1000 までのカプレカ数を求めよとのことだ...
カプレカ数とは馴染みのないものであるが,定義は 2 通りあるそうだ。
1. 2 乗して前の部分と後ろの部分に分けて(偶数桁 2n 桁である場合は先頭 n 桁と末尾 n 桁に分け,奇数桁 2n + 1 桁である場合は先頭 n 桁と末尾 n + 1 桁に分けて)和を取ったとき,元の値に等しくなるもの。
2. 桁を並べ替えて最大にしたものから最小にしたものの差を取ったとき,元の値に等しくなるもの。
今回は,前者のことをいっているようだ。
Wikipedia で調べると
カプレカ数
1, 9, 45, 55, 99, 297, 703, 999, 2223, 2728, 4879, 4950, 5050, 5292, …(オンライン整数列大辞典の数列 A006886 http://oeis.org/A006886)が簡単に見つかる。
プログラムを書いて,0 ~ 5300 の範囲を探索すると,得られる出力と違うところがある。
a1 = 0:5300
a2 = a1^2
old = options(scipen=10)
a3 = strsplit(as.character(a2), "")
options(old)
a4 = sapply(a3, function(x) {
y = unlist(x)
n = length(y)
if (n == 1) {
as.numeric(paste(y, collapse=""))
} else {
m = n %/% 2
as.numeric(paste(y[1:m], collapse="")) + as.numeric(paste(y[(m+1):n], collapse=""))
}
})
a1[a1 == a4]
> a1[a1 == a4]
[1] 0 1 9 45 55 99 297 703 999 2223 2728 4950 5050
0 は明白な カプレカ数だと思うがそれはさておき,プログラムによる出力には 4879 はない。4879^2 = 2380 と 4641 なので,2380 + 4641 = 7021 になるので,カプレカ数ではないはず。2380 の最後の 0 を無視するというルールならば,238 + 4641 = 4879 になるのでカプレカ数ということになるのだが。同様に,5292^2 = 2800 と 5264 なので,28 + 5264 = 5292 ではあるが?と根拠を求めてネットサーフィンすると,
Karekar numbers
http://www.numbersaplenty.com/set/Kaprekar_number/
に,
Note that the second part can start with zero: 5292^2 = {28} {005264} and 28+5264=5292.
と書いてあった。後ろ半分の数字の前に 0 があってもよいということは,前の部分の後ろの 0 は無視してもよいということである(無視しない場合も考えよということ)。このルールも加えてプログラムを修正する。
プログラムに for を使うことになったがやむを得ない。
N = 5300
a1 = 0:N
a2 = a1^2
old = options(scipen=10)
a3 = strsplit(as.character(a2), "")
options(old)
a4 = a5 = integer(N+1)
for (i in seq_along(a1)) {
y = unlist(a3[[i]])
n = length(y)
if (n == 1) {
a4[i] = a5[i] = as.numeric(paste(y, collapse=""))
} else {
m = n %/% 2
a4[i] = as.numeric(paste(y[1:m], collapse="")) + # 前半分の後ろの 0 を無視しない
as.numeric(paste(y[(m+1):n], collapse=""))
a5[i] = as.numeric(paste(gsub("0*$", "", y[1:m]), collapse="")) + # 前半分の後ろの 0 を無視する
as.numeric(paste(y[(m+1):n], collapse=""))
}
}
a1[a1 == a4 | a1 == a5] # 前半分の後ろの 0 を無視しない場合と無視する場合のどちらか一方でも可ということで
> a1[a1 == a4 | a1 == a5]
[1] 0 1 9 45 55 99 297 703 999 2223 2728 4879 4950 5050 5292
Wikipedia などの例示と一致した。
10 万までで 5 秒弱かかって,以下の結果を得る。
> print(a1[a1 == a4 | a1 == a5])})
[1] 0 1 9 45 55 99 297 703 999 2223 2728 4879 4950 5050 5292 7272
[17] 7777 9999 17344 22222 38962 77778 82656 95121 99999