さんすうRuby - 3と7と11の倍数
2010 年 6 月 14 日 by 山平事の発端は先日見かけたサイトでした。
1 + 1 + 1 = 3なので、111は3の倍数なんだそうです。
えっ、そうなの?と思って読んでみると、証明まで載っています。
ナルホドォ~興味深い。。。
興味深いついでに、プログラムで確認してみたくなったので、早速Rubyで実装してみます。
倍数の判定方法が興味深く、素数でもある3と7と11について試してみることにします。
普通の倍数判定
まずは普通に割って余りが0かどうかを確認するプログラムを準備します。
これは検算に使います。
-
def by3d(n)
-
(n % 3 == 0)
-
end
-
-
def by7d(n)
-
(n % 7 == 0)
-
end
-
-
def by11d(n)
-
(n % 11 == 0)
-
end
要は値の剰余が0なら割り切れると判断しています。
3の倍数かどうかを判別する
3の倍数かどうかを調べるには各桁の数字を合計した数が3の倍数かどうかを見ればよいとのこと。
各桁の数の合計が2桁以上のときの値が3の倍数かどうかを調べるには、各桁の…と1桁になるまで繰り返してよいことが分かります。
-
def by3p(n)
-
while n.to_s.length> 1 do
-
n = eval(n.to_s.split(//).join('+'))
-
end
-
(n % 3 == 0)
-
end
数値を文字列化(to_s)して分割(split(//))、各文字を"+"ではさんで再文字列化(join('+'))して計算(eval)します。
これを文字列が1桁になるまで繰り返しています。
7の倍数かどうかを判別する
7の倍数かを判定する方法は、いくつかありますが、なるべく桁数を気にしたくないので、2桁目以上の値から1桁目を2倍した値を引いていく方法を採用しました。
-
def by7p(n)
-
while n> 9 do
-
n = eval(n.to_s[0..-2] + " - 2 * " + n.to_s[-1])
-
end
-
(n % 7 == 0)
-
end
3の倍数と同じように文字列化(to_s)した後、2桁目以上の値(n.to_s[0..-2])から1桁目を2倍した値を引く(" - 2 * " + n.to_s[-1])式を作成して計算(eval)しています。
ここで注意しなければいけないのが、文字列の場合、2桁の正数と1桁の負数が判別できないので、10以上の間繰り返すようにしています。
11の倍数かどうかを判別する
11の倍数は奇数桁の合計と偶数桁の合計の差が11の倍数かどうかで判別します。
要は各桁を交互に+-していけば良いことが分かります。
-
def by11p(n)
-
d = "-+".split(//)
-
while n> 9 do
-
c = n.to_s.split(//)
-
candi = ''
-
candi = candi <<d[c.length%2] <<c.shift while c.length> 0
-
n = eval(candi).abs
-
end
-
(n == 0)
-
end
3の倍数の時のように、単純にsplit(//).join('+')で式が作成できないので、交互に+-を取得(d[c.length%2])しています。
1桁になるまでに負の値になることがあるので、ここでは結果の絶対値(eval(candi).abs)を次に渡すようにしています。
検算を自動化する
検算は最初に作ったメソッドとの結果を比較します。
-
def checkresult(maxcount, methods)
-
ok, ng = 0, 0
-
maxcount.times do |t|
-
r = []
-
methods.each do |m|
-
r.push(method(m).call(t))
-
end
-
result = (r.uniq.length == 1)
-
ok += 1 if result
-
ng += 1 if !result
-
puts "#{t}: #{result} ok:#{ok}, ng:#{ng}\n" if !result# debug
-
end
-
(ng == 0)
-
end
メソッドをcallしている箇所がなんだか不細工な気がしますが、それぞれの倍数判別ロジックを好きな回数検算できます。
-
maxcount = 100000
-
checkresult(maxcount, [:by3d, :by3p ])
-
checkresult(maxcount, [:by7d, :by7p ])
-
checkresult(maxcount, [:by11d, :by11p])
駆け足になりましたが以上です。


