Continued fraction convergents: Difference between revisions

m
→‎{{header|Phix}}: forgot the heading
(Added a reference to Wikipedia article on Continued Fractions.)
m (→‎{{header|Phix}}: forgot the heading)
 
(9 intermediate revisions by 5 users not shown)
Line 1:
{{draft task}}
 
{{clarify task}}
Given a positive real number, if we truncate its [[continued fraction]] representation at a certain depth, we obtain a rational approximation to the real number. The sequence of successively better such approximations is its convergent sequence.
 
Line 13:
A simple check is to do this for the golden ratio <math>\frac{\sqrt{5}+1}{2}</math>, that is, <math>a=5, b=1, m = 1, n = 2 </math>, which should output <math>(1,1), (2,1), (3,2), (5,3), (8,5), \dots</math>.
 
Print the results for 415/93, 649/200, <math>\sqrt{2}</math>, <math>\sqrt{5}</math>, and the golden ratio.
;Reference
 
[[wp:Continued fraction|Wikipedia: Continued fraction]]
;References and related tasks
* [[wp:Continued fraction|Wikipedia: Continued fraction]]
* [[Continued fraction]]
* [[Continued fraction/Arithmetic]]
* [[Continued fraction/Arithmetic/Construct from rational number]]
* [[Calkin-Wilf sequence]]
 
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">function convergents(x::Real, maxcount::T) where T <: Integer
components = T[]
rationals = Rational{T}[]
for _ in 1:maxcount
fpart, ipart = modf(x)
push!(components, T(ipart))
fpart == 0 && break
x = inv(fpart)
end
numa, denoma, numb, denomb = T(1), T(0), T(components[begin]), T(1)
push!(rationals, numb // denomb)
for comp in components[begin+1:end]
numa, denoma, numb, denomb = numb, denomb, numa + comp * numb, denoma + comp * denomb
push!(rationals, numb // denomb)
end
return rationals
end
 
const tests = [("415/93", 415//93), ("649/200", 649//200), ("sqrt(2)", sqrt(2)),
("sqrt(5)", sqrt(5)), ("golden ratio", (sqrt(5) + 1) / 2)]
 
println("The continued fraction convergents for the following (maximum 8 terms) are:")
for (s, x) in tests
println(lpad(s, 15), " = ", convergents(x, 8))
end
</syntaxhighlight>{{out}}
<pre>
The continued fraction convergents for the following (maximum 8 terms) are:
415/93 = Rational{Int64}[4, 9//2, 58//13, 415//93]
649/200 = Rational{Int64}[3, 13//4, 159//49, 649//200]
sqrt(2) = Rational{Int64}[1, 3//2, 7//5, 17//12, 41//29, 99//70, 239//169, 577//408]
sqrt(5) = Rational{Int64}[2, 9//4, 38//17, 161//72, 682//305, 2889//1292, 12238//5473, 51841//23184]
golden ratio = Rational{Int64}[1, 2, 3//2, 5//3, 8//5, 13//8, 21//13, 34//21]
</pre>
 
=={{header|Phix}}==
{{trans|Wren}}
<!--(phixonline)-->
<syntaxhighlight lang="phix">
with javascript_semantics
requires("1.0.5") -- mpq_get_d() added
include mpfr.e
 
procedure cfcRat(integer m, n)
sequence p = {mpq_init(0), mpq_init(1)},
q = {mpq_init(1), mpq_init(0)},
s = {},
t = sprintf("%d/%d",{m,n})
mpq r = mpq_init_set_si(m, n),
rem = mpq_init_set(r)
while true do
mpq whole = mpq_init_set_si(trunc(mpq_get_d(rem)))
mpq {pn, qn, sn} = mpq_inits(3)
mpq_mul(pn,whole,p[-1])
mpq_add(pn,pn,p[-2])
mpq_mul(qn,whole,q[-1])
mpq_add(qn,qn,q[-2])
mpq_div(sn,pn,qn)
p &= pn
q &= qn
s &= {mpq_get_str(sn)}
if mpq_cmp(r,sn)=0 then exit end if
mpq_sub(rem,rem,whole)
mpq_inv(rem,rem)
end while
printf(1,"%14s = %s\n",{t,join(s)})
end procedure
 
procedure cfcQuad(string d, integer a, b, m, n, k)
sequence p = {0, 1},
q = {1, 0},
s = {}
atom rem = (sqrt(a)*b + m) / n
for i=1 to k do
integer whole = trunc(rem),
pn = whole * p[-1] + p[-2],
qn = whole * q[-1] + q[-2]
mpq sn = mpq_init_set_si(pn, qn)
p &= pn
q &= qn
s &= {mpq_get_str(sn)}
rem = 1/(rem-whole)
end for
printf(1,"%14s = %s\n",{d,join(s)})
end procedure
 
printf(1,"The continued fraction convergents for the following (maximum 8 terms) are:\n")
cfcRat(415,93)
cfcRat(649,200)
cfcQuad("sqrt(2)",2, 1, 0, 1, 8)
cfcQuad("sqrt(5)",5, 1, 0, 1, 8)
cfcQuad("golden ratio",5, 1, 1, 2, 8)
 
</syntaxhighlight>
{{out}}
<pre>
The continued fraction convergents for the following (maximum 8 terms) are:
415/93 = 4 9/2 58/13 415/93
649/200 = 3 13/4 159/49 649/200
sqrt(2) = 1 3/2 7/5 17/12 41/29 99/70 239/169 577/408
sqrt(5) = 2 9/4 38/17 161/72 682/305 2889/1292 12238/5473 51841/23184
golden ratio = 1 2 3/2 5/3 8/5 13/8 21/13 34/21
</pre>
 
=={{header|Raku}}==
{{trans|Julia}}
<syntaxhighlight lang="raku" line># 20240210 Raku programming solution
 
sub convergents(Real $x is copy, Int $maxcount) {
my @components = gather for ^$maxcount {
my $fpart = $x - take $x.Int;
$fpart == 0 ?? ( last ) !! ( $x = 1 / $fpart )
}
my ($numa, $denoma, $numb, $denomb) = 1, 0, @components[0], 1;
return [ Rat.new($numb, $denomb) ].append: gather for @components[1..*] -> $comp {
( $numa, $denoma, $numb , $denomb )
= $numb, $denomb, $numa + $comp * $numb, $denoma + $comp * $denomb;
take Rat.new($numb, $denomb);
}
}
 
my @tests = [ "415/93", 415/93, "649/200", 649/200, "sqrt(2)", sqrt(2),
"sqrt(5)", sqrt(5), "golden ratio", (sqrt(5) + 1) / 2 ];
 
say "The continued fraction convergents for the following (maximum 8 terms) are:";
for @tests -> $s, $x {
say $s.fmt('%15s') ~ " = { convergents($x, 8).map: *.nude.join('/') } ";
}</syntaxhighlight>
{{out}}
<pre>
The continued fraction convergents for the following (maximum 8 terms) are:
415/93 = 4/1 9/2 58/13 415/93
649/200 = 3/1 13/4 159/49 649/200
sqrt(2) = 1/1 3/2 7/5 17/12 41/29 99/70 239/169 577/408
sqrt(5) = 2/1 9/4 38/17 161/72 682/305 2889/1292 12238/5473 51841/23184
golden ratio = 1/1 2/1 3/2 5/3 8/5 13/8 21/13 34/21
</pre>
You may [https://ato.pxeger.com/run?1=dVNNb9pAED305l_xYrliTRdj01AREE2vvUa5ISotsCZu7LW7u25AEfkjveTQ_qn8mo6_EKDWF8_OvDezM2_n128tHsvX1z-ljQeTt3fClCusc_VT6q1U1rA7KVJ4OySG3MWe46uy8DKxW-elsj6eHQDZHl_WeVbkquJgjq2wD1IjzjW-HcENtoF7cSG0JSSlHsCKR0lWQLlnLaYDzBHi9hYMqTAWPq6uyCbSHBGGHcqvSIf2JsxTZSY4vI1UeW3QedWdV35F5Qj56ZUX4ZIjqmtraUutsMCdsIGST-ySvgxEUUi1mZ52eZorCoL-EoPP8CrnsWuGf14MF9-x0mUA1H2ban7RU5NK4ENbsn8ePws0jG7M9eT_0-msmerBcSp9rTS1tAu419F4ePPR5WgMDvfT9c1wFIbkai3ymR_aspFPvtbiznk7DWJ8RIx9Ym3zlMpDC5vkFGBthDqIfBJ8VDOXM8cxYg_3_kFWr9UmqpQbxFqsiaZOH3CtDslE_zTNnxK1BaMHmWRlhgms1JnxIbScujOnFrLps1LP8Oqh1fJVxTwTxJllvffR2PR8vMClaTyfLYu345j4QSaKKfqBKjcy-J4nivWGRDiAShycZtPahesW7y8 Attempt This Online!]
 
=={{header|Sidef}}==
<syntaxhighlight lang="ruby">func num2cfrac(n, r) {
gather {
r.times {
n = 1/((n - take(n.floor.int)) || break)
}
}
}
 
func convergents(x, n) {
var cfrac = num2cfrac(x, n)
 
var(n1, n2) = (0, 1)
var(d1, d2) = (1, 0)
 
gather {
for z in (cfrac) {
(n1, n2) = (n2, n2*z + n1)
(d1, d2) = (d2, d2*z + d1)
take(n2/d2)
}
}
}
 
var tests = ["415/93", 415/93, "649/200", 649/200, "sqrt(2)", sqrt(2),
"sqrt(5)", sqrt(5), "golden ratio", (sqrt(5) + 1) / 2 ]
 
var terms = 8
say "The continued fraction convergents for the following (maximum #{terms} terms) are:"
tests.each_slice(2, {|s,x|
printf("%15s = %s\n", s, convergents(x, terms).map { .as_frac }.join(' '))
})</syntaxhighlight>
{{out}}
<pre>
The continued fraction convergents for the following (maximum 8 terms) are:
415/93 = 4/1 9/2 58/13 415/93
649/200 = 3/1 13/4 159/49 649/200
sqrt(2) = 1/1 3/2 7/5 17/12 41/29 99/70 239/169 577/408
sqrt(5) = 2/1 9/4 38/17 161/72 682/305 2889/1292 12238/5473 51841/23184
golden ratio = 1/1 2/1 3/2 5/3 8/5 13/8 21/13 34/21
</pre>
 
=={{header|Wren}}==
{{libheader|Wren-rat}}
Well, the task seems reasonably clear now to me.
 
The following is loosely based on the Python code [https://leancrew.com/all-this/2023/08/continued-fractions-in-python/ here]. If a large number of terms were required for quadratic real numbers, then one might need to use 'arbitrary precision' arithmetic to minimize round-off errors when converting between floats and rationals.
Line 48 ⟶ 236:
var q = [1, 0]
var s = []
var rrem = (a.sqrt * b + m) / n
var rem = r
for (i in 1..k) {
var whole = rem.truncate
7,795

edits