1 USING: accessors classes.tuple kernel math math.functions
2 project-euler.common ranges sequences ;
5 ! http://projecteuler.net/index.php?section=problems&id=64
10 ! All square roots are periodic when written as continued
11 ! fractions and can be written in the form:
13 ! √N=a0+1/(a1+1/(a2+1/a3+...))
15 ! For example, let us consider √23:
17 ! √23=4+√(23)−4=4+1/(1/(√23−4)=4+1/(1+((√23−3)/7)
19 ! If we continue we would get the following expansion:
21 ! √23=4+1/(1+1/(3+1/(1+1/(8+...))))
23 ! The process can be summarised as follows:
25 ! a0=4, 1/(√23−4) = (√23+4)/7 = 1+(√23−3)/7
26 ! a1=1, 7/(√23−3) = 7*(√23+3)/14 = 3+(√23−3)/2
27 ! a2=3, 2/(√23−3) = 2*(√23+3)/14 = 1+(√23−4)/7
28 ! a3=1, 7/(√23−4) = 7*(√23+4)/7 = 8+√23−4
29 ! a4=8, 1/(√23−4) = (√23+4)/7 = 1+(√23−3)/7
30 ! a5=1, 7/(√23−3) = 7*(√23+3)/14 = 3+(√23−3)/2
31 ! a6=3, 2/(√23−3) = 2*(√23+3)/14 = 1+(√23−4)/7
32 ! a7=1, 7/(√23−4) = 7*(√23+4)/7 = 8+√23−4
34 ! It can be seen that the sequence is repeating. For
35 ! conciseness, we use the notation √23=[4;(1,3,1,8)], to
36 ! indicate that the block (1,3,1,8) repeats indefinitely.
38 ! The first ten continued fraction representations of
39 ! (irrational) square roots are:
41 ! √2=[1;(2)] , period=1
42 ! √3=[1;(1,2)], period=2
43 ! √5=[2;(4)], period=1
44 ! √6=[2;(2,4)], period=2
45 ! √7=[2;(1,1,1,4)], period=4
46 ! √8=[2;(1,4)], period=2
47 ! √10=[3;(6)], period=1
48 ! √11=[3;(3,6)], period=2
49 ! √12=[3;(2,6)], period=2
50 ! √13=[3;(1,1,1,1,6)], period=5
52 ! Exactly four continued fractions, for N <= 13, have an odd period.
54 ! How many continued fractions for N <= 10000 have an odd period?
63 C: <cont-frac> cont-frac
65 : deep-copy ( cont-frac -- cont-frac cont-frac )
66 dup tuple>array rest cont-frac slots>tuple ;
68 : create-cont-frac ( n -- n cont-frac )
69 dup sqrt >fixnum dup 1 <cont-frac> ;
71 : step ( n cont-frac -- n cont-frac )
75 ! Extract the constant
79 ! Find the new denominator
80 num-const 2 ^ n swap -
83 ! Find the fraction in lowest terms
89 ! Find the new whole number
90 num-const n sqrt + new-denom / >fixnum
93 ! Find the new num-const
99 ! Finally, update the continuing fraction
100 drop new-whole new-num-const new-denom <cont-frac>
103 :: loop ( c l n cf -- c l n cf )
104 n cf step :> new-cf drop
106 l new-cf = [ loop ] unless ;
108 : find-period ( n -- period )
118 [ perfect-square? ] reject
125 : euler064a ( -- n ) try-all ;
134 : >cfrac< ( fr -- n a b )
135 [ n>> ] [ a>> ] [ b>> ] tri ;
137 ! (√n + a) / b = 1 / (k + (√n + a') / b')
139 ! b / (√n + a) = b (√n - a) / (n - a^2) = (√n - a) / ((n - a^2) / b)
140 :: reciprocal ( fr -- fr' )
141 fr >cfrac< :> ( n a b )
147 :: split ( fr -- k fr' )
148 fr >cfrac< :> ( n a b )
159 reciprocal split nip ;
161 :: period ( n -- period )
162 n sqrt >integer sq n = [ 0 ] [
163 n pure split nip :> start
172 : euler064b ( -- ct )
173 10000 [1..b] [ period odd? ] count ;