Calkin-Wilf sequence: Difference between revisions
m (→{{header|Factor}}: index, not term) |
m (→{{header|Factor}}: simplify) |
||
Line 31: | Line 31: | ||
: next-cw ( x -- y ) [ floor dup + ] [ 1 swap - + recip ] bi ; |
: next-cw ( x -- y ) [ floor dup + ] [ 1 swap - + recip ] bi ; |
||
: calkin-wilf ( -- list ) |
: calkin-wilf ( -- list ) 1 [ next-cw ] lfrom-by ; |
||
: >continued-fraction ( x -- seq ) |
: >continued-fraction ( x -- seq ) |
||
Line 43: | Line 43: | ||
! Task |
! Task |
||
"First 20 terms of the Calkin-Wilf sequence:" print |
"First 20 terms of the Calkin-Wilf sequence:" print |
||
20 calkin-wilf |
20 calkin-wilf ltake [ pprint bl ] leach nl nl |
||
83116/51639 cw-index "83116/51639 is at index %d.\n" printf</lang> |
83116/51639 cw-index "83116/51639 is at index %d.\n" printf</lang> |
Revision as of 16:46, 6 December 2020
The Calkin-Wilf sequence contains every nonnegative rational number exactly once. It can be calculated recursively as follows:
a0 = 0
an+1 = 1/(2⌊an⌋+1-an) for n > 0
- Show on this page terms 0 through 20 of the Calkin-Wilf sequence. To avoid floating point error, you may want to use a rational number data type.
It is also possible, given a nonnegative rational number, to determine where it appears in the sequence without calculating the sequence. The procedure is to get the continued fraction representation of the rational and use it as the run-length encoding of the binary representation of the term number, beginning from the end of the continued fraction.
It only works if the number of terms in the continued fraction is odd- use either of the two equivalent representations to achieve this:
[a0; a1, a2, ..., an] = [a0; a1, a2 ,..., an-1, 1]
Thus, for example, the fraction 9/4 has odd continued fraction representation 2; 3, 1, giving a binary representation of 100011, which means 9/4 appears as the 35th term of the sequence.
- Find the position of the number 83116/51639 in the Calkin-Wilf sequence.
- See also
- Wikipedia entry: Calkin-Wilf tree
Factor
<lang factor>USING: formatting io kernel lists lists.lazy math math.continued-fractions math.functions math.parser prettyprint sequences strings vectors ;
- next-cw ( x -- y ) [ floor dup + ] [ 1 swap - + recip ] bi ;
- calkin-wilf ( -- list ) 1 [ next-cw ] lfrom-by ;
- >continued-fraction ( x -- seq )
1vector [ dup last integer? ] [ dup next-approx ] until dup length even? [ unclip-last 1 - suffix! 1 suffix! ] when ;
- cw-index ( x -- n )
>continued-fraction <reversed> [ even? CHAR: 1 CHAR: 0 ? <string> ] map-index concat bin> ;
! Task "First 20 terms of the Calkin-Wilf sequence:" print 20 calkin-wilf ltake [ pprint bl ] leach nl nl
83116/51639 cw-index "83116/51639 is at index %d.\n" printf</lang>
- Output:
First 20 terms of the Calkin-Wilf sequence: 1 1/2 2 1/3 1+1/2 2/3 3 1/4 1+1/3 3/5 2+1/2 2/5 1+2/3 3/4 4 1/5 1+1/4 4/7 2+1/3 3/8 83116/51639 is at index 123456789.
FreeBASIC
Uses the code from Greatest common divisor#FreeBASIC as an include.
<lang freebasic>#include "gcd.bas"
type rational
num as integer den as integer
end type
dim shared as rational ONE, TWO ONE.num = 1 : ONE.den = 1 TWO.num = 2 : TWO.den = 1
function simplify( byval a as rational ) as rational
dim as uinteger g = gcd( a.num, a.den ) a.num /= g : a.den /= g if a.den < 0 then a.den = -a.den a.num = -a.num end if return a
end function
operator + ( a as rational, b as rational ) as rational
dim as rational ret ret.num = a.num * b.den + b.num*a.den ret.den = a.den * b.den return simplify(ret)
end operator
operator - ( a as rational, b as rational ) as rational
dim as rational ret ret.num = a.num * b.den - b.num*a.den ret.den = a.den * b.den return simplify(ret)
end operator
operator * ( a as rational, b as rational ) as rational
dim as rational ret ret.num = a.num * b.num ret.den = a.den * b.den return simplify(ret)
end operator
operator / ( a as rational, b as rational ) as rational
dim as rational ret ret.num = a.num * b.den ret.den = a.den * b.num return simplify(ret)
end operator
function floor( a as rational ) as rational
dim as rational ret ret.den = 1 ret.num = a.num \ a.den return ret
end function
function cw_nextterm( q as rational ) as rational
dim as rational ret = (TWO*floor(q)) ret = ret + ONE : ret = ret - q return ONE / ret
end function
function frac_to_int( byval a as rational ) as uinteger
redim as uinteger cfrac(-1) dim as integer lt = -1, ones = 1, ret = 0 do lt += 1 redim preserve as uinteger cfrac(0 to lt) cfrac(lt) = floor(a).num a = a - floor(a) : a = ONE / a loop until a.num = 0 or a.den = 0 if lt mod 2 = 1 and cfrac(lt) = 1 then lt -= 1 cfrac(lt)+=1 redim preserve as uinteger cfrac(0 to lt) end if if lt mod 2 = 1 and cfrac(lt) > 1 then cfrac(lt) -= 1 lt += 1 redim preserve as uinteger cfrac(0 to lt) cfrac(lt) = 1 end if for i as integer = lt to 0 step -1 for j as integer = 1 to cfrac(i) ret *= 2 if ones = 1 then ret += 1 next j ones = 1 - ones next i return ret
end function
function disp_rational( a as rational ) as string
if a.den = 1 or a.num= 0 then return str(a.num) return str(a.num)+"/"+str(a.den)
end function
dim as rational q q.num = 0 q.den = 1 for i as integer = 0 to 20
print i, disp_rational(q) q = cw_nextterm(q)
next i
q.num = 83116 q.den = 51639 print disp_rational(q)+" is the "+str(frac_to_int(q))+"th term."</lang>
- Output:
0 0 1 1 2 1/2 3 2 4 1/3 5 3/2 6 2/3 7 3 8 1/4 9 4/3 10 3/5 11 5/2 12 2/5 13 5/3 14 3/4 15 4 16 1/5 17 5/4 18 4/7 19 7/3 20 3/8 83116/51639 is the 123456789th term.
Raku
Technically, the Calkin-Wilf sequence should begin with 1, but start with 0 as that is what the task specifies.
Conveniently, having the bogus first term shifts the indices up by one, making the ordinal position and index match.
Only show the first twenty terms that are actually in the sequence.
<lang perl6>my @calkin-wilf = 0, 1, {1 / (.Int × 2 + 1 - $_)} … *;
- Rational to Calkin-Wilf index
sub r2cw (Rat $rat) { :2( join , flat (flat (1,0) xx *) Zxx reverse r2cf $rat ) }
- The task
say "First twenty terms of the Calkin-Wilf sequence: ",
@calkin-wilf[1..20]».&prat.join: ', ';
say "\n99991st through 100000th: ",
(my @tests = @calkin-wilf[99_991 .. 100_000])».&prat.join: ', ';
say "\nCheck reversibility: ", @tests».Rat».&r2cw.join: ', ';
say "\n83116/51639 is at index: ", r2cw 83116/51639;
- Helper subs
sub r2cf (Rat $rat is copy) { # Rational to continued fraction
gather loop {
$rat -= take $rat.floor; last if !$rat; $rat = 1 / $rat;
}
}
sub prat ($num) { # pretty Rat
return $num unless $num ~~ Rat|FatRat; return $num.numerator if $num.denominator == 1; $num.nude.join: '/';
}</lang>
- Output:
First twenty terms of the Calkin-Wilf sequence: 1, 1/2, 2, 1/3, 3/2, 2/3, 3, 1/4, 4/3, 3/5, 5/2, 2/5, 5/3, 3/4, 4, 1/5, 5/4, 4/7, 7/3, 3/8 99991st through 100000th: 1085/303, 303/1036, 1036/733, 733/1163, 1163/430, 430/987, 987/557, 557/684, 684/127, 127/713 Check reversibility: 99991, 99992, 99993, 99994, 99995, 99996, 99997, 99998, 99999, 100000 83116/51639 is at index: 123456789