循環小数
自明の問題はつまらないので、ちょっとぐらい難しい奴をやろうと思って、正解者数が少なめの「d<1000であるdに対して、1/dの循環小数の最大循環桁数は?」というのを探してみた。オイラープロジェクトの26問目。そんなに難しくないだろうと思ったけど、いろいろ考え出すと単純じゃないことが分かった。
たとえば、d=7では、
1/7=0.(142857)
で6桁が循環してる。同様に1/3(0.3333……)は1桁が循環してる。
1/11=0.(90) 1/19=0.(526315789473684210) 1/987=0.(10131712259371833839918946301925025329280648429 58459979736575481256332320162107396149949341438703140830 80040526849037487335359675785207700)
とかいう感じ。ちょっと調べ見た感じ、循環には2つのパターンがある。
0.XYZabcabcabc -- (1) 0.abcabcabc -- (2)
いきなり循環を始める(2)のタイプと、頭に数桁の非循環部がある(1)のタイプがある。で、とりあえず(2)だけ調べることにした。意外に重たい処理なので、(1)をやるのは若干ためらわれて、まだやってない。
Rubyにはbigdecimalという標準ライブラリがある。浮動小数点を文字列として扱って好きなだけ桁数を増やせる。まあ、いろいろ力業。
require 'bigdecimal' # 0.abcdabcd.... # 0.XYZabcdabcd.... figs = 2100 def rep?(str) (1..(str.length / 2)).each do |i| ary = str.scan(/.{#{i}}/) u = ary.uniq if u.size == 1 then return i, u end end return 0 end max = 0 (1..1000).each do |i| a = BigDecimal("1",figs) / BigDecimal(i.to_s) b = a.to_s.sub(/^0\./,"").sub(/E.*/,"") c = rep?(b) print "1/", i, "\n" # print "figs: ", a, "\n" print "repeating: ", c, "\n" max = c[0] if (c[0] > max) end print "max: ", max, "\n"
出力は、こんな感じ。
1/217 repeating: [30, ["460829493087557603686635944700"]] 1/218 repeating: [108, ["458715596330275229357798165137614678899082568807339449541284403669 724770642201834862385321100917431192660550"]] 1/219 repeating: [8, ["45662100"]] 1/220 repeating: [2, ["45"]] 1/221 repeating: [48, ["452488687782805429864253393665158371040723981900"]] 1/222 repeating: [3, ["450"]] 1/223 repeating: [222, ["4484304932735426008968609865470852017937219730941704035874439461883 408071748878923766816143497757847533632286995515695067264573991031390 134529147982062780269058295964125560538116591928251121076233183856502 24215246636771300"]] 1/224 repeating: 0 1/225 repeating: [1, ["4"]] 1/226
見ていると、どうも1/dの循環桁数は必ず(d-1)以下になっているようで、しかも、かなりの頻度で(d-1)桁の繰り返しが登場しているっぽい。というわけで、正解は990〜1000個の繰り返しじゃないかと思うのだけど、全然ツメが甘い感じ。