Continued fraction/Arithmetic/G(matrix ng, continued fraction n1, continued fraction n2): Difference between revisions

Content added Content deleted
Line 2,820: Line 2,820:
484/49 / 22/7 is {0 1 0 0 0 0 1 0} [9; 1, 7, 6] [3; 7] gives [3; 7]
484/49 / 22/7 is {0 1 0 0 0 0 1 0} [9; 1, 7, 6] [3; 7] gives [3; 7]
√2 * √2 = [1; 0, 1]
√2 * √2 = [1; 0, 1]
</pre>

=={{header|Icon}}==
{{trans|ObjectIcon}}

<syntaxhighlight lang="icon">
$define YES 1
$define NO &null

record CF (terminated, # Are there no more terms to memoize?
memo, # Memoized terms.
term_gen) # A co-expression to generate more terms.

record ng8 (a12, a1, a2, a,
b12, b1, b2, b)

global golden_ratio
global silver_ratio
global sqrt2
global frac_13_11
global frac_22_7
global one, two, three, four

global practically_infinite_number
global much_too_big_number

procedure r2cf (n, d)
return make_cf (create r2cf_generate (n, d))
end

procedure i2cf (i)
return make_cf (create r2cf_generate (i, 1))
end

procedure cf_add (x, y)
return ng8_apply (ng8 (0, 1, 1, 0, 0, 0, 0, 1), x, y)
end

procedure cf_sub (x, y)
return ng8_apply (ng8 (0, 1, -1, 0, 0, 0, 0, 1), x, y)
end

procedure cf_mul (x, y)
return ng8_apply (ng8 (1, 0, 0, 0, 0, 0, 0, 1), x, y)
end

procedure cf_div (x, y)
return ng8_apply (ng8 (0, 1, 0, 0, 0, 0, 1, 0), x, y)
end

procedure main ()
initial {
initialize_global_CF ()
}

show ("golden ratio", golden_ratio, "(1 + sqrt(5))/2")
show ("silver ratio", silver_ratio, "(1 + sqrt(2))")
show ("sqrt(2)", sqrt2, "silver ratio minus 1")
show ("13/11", frac_13_11)
show ("22/7", frac_22_7, "approximately pi")
show ("1", one)
show ("2", two)
show ("3", three)
show ("4", four)

show ("(1 + 1/sqrt(2))/2",
ng8_apply (ng8(0, 1, 0, 0, 0, 0, 2, 0),
silver_ratio, sqrt2),
"method 1")
show ("(1 + 1/sqrt(2))/2",
ng8_apply (ng8(1, 0, 0, 1, 0, 0, 0, 8),
silver_ratio, silver_ratio),
"method 2")
show ("(1 + 1/sqrt(2))/2",
cf_mul (cf_add (one, (cf_div (one, sqrt2))), r2cf (1, 2)),
"method 3")

show ("sqrt(2) + sqrt(2)", cf_add (sqrt2, sqrt2));
show ("sqrt(2) - sqrt(2)", cf_sub (sqrt2, sqrt2));
show ("sqrt(2) * sqrt(2)", cf_mul (sqrt2, sqrt2));
show ("sqrt(2) / sqrt(2)", cf_div (sqrt2, sqrt2));
end

procedure initialize_global_CF ()
golden_ratio := make_cf (create generate_constant (1))
silver_ratio := make_cf (create generate_constant (2))
frac_13_11 := r2cf (13, 11)
frac_22_7 := r2cf (22, 7)
one := i2cf (1)
two := i2cf (2)
three := i2cf (3)
four := i2cf (4)
sqrt2 := cf_sub (silver_ratio, one)
return
end

procedure show (expression, cf, note)
writes (right (expression, 19), " => ")
if /note then
write (cf2string (cf))
else
write (left (cf2string (cf), 48), note)
return
end

procedure make_cf (gen)
return CF (NO, [], gen)
end

# Get a continued fraction's ith term, or fail if there is no such
# term.
procedure cf_get_term (cf, i)

local j, term

if *cf.memo <= i then {
if \cf.terminated then {
fail
} else {
every j := *cf.memo to i do {
if \ (term := @cf.term_gen) then {
put (cf.memo, term)
} else {
cf.terminated := YES
fail
}
}
}
}
return cf.memo[i + 1]
end

# Generate a continued fraction's terms, with &null as "infinity".
procedure cf_generate (cf)
local i, term

i := 0
while term := cf_get_term (cf, i) do {
suspend term
i +:= 1
}
repeat suspend &null
end

# A co-expression that generates a continued fraction's terms, with
# &null as "infinity".
procedure cf2coexpression (cf)
return create cf_generate (cf)
end

# Make a human-readable string from a continued fraction.
procedure cf2string (cf, max_terms)
local s, i, done, term
local sep_str

/max_terms := 20

s := "["
i := 0
done := NO
while /done do {
if not (term := cf_get_term (cf, i)) then {
s ||:= "]"
done := YES
} else if i = max_terms then {
s ||:= ",...]"
done := YES
} else {
s ||:= ["", ";", ","][min (i + 1, 3)] || term
i +:= 1
}
}
return s
end

# Make a CF that applies the operation.
procedure ng8_apply (ng8, x, y)
return make_cf (create ng8_generate (ng8, x, y))
end

# A generator that applies a bihomographic function. A return of &null
# means "infinity".
procedure ng8_generate (ng, x, y)
local xsource, ysource
local a12, a1, a2, a
local b12, b1, b2, b
local r12, r1, r2, r
local n1, n2, n
local absorb_term_from
local term
local new_a12, new_a1, new_a2, new_a
local new_b12, new_b1, new_b2, new_b

xsource := make_source (x)
ysource := make_source (y)

a12 := ng.a12; a1 := ng.a1; a2 := ng.a2; a := ng.a
b12 := ng.b12; b1 := ng.b1; b2 := ng.b2; b := ng.b

repeat {
absorb_term_from := &null
if b12 = b1 = b2 = b = 0 then {
suspend &null # "Infinity".
} else if b2 = b = 0 then {
absorb_term_from := 'x'
} else if b2 = 0 | b = 0 then {
absorb_term_from := 'y'
} else if b1 = 0 then {
absorb_term_from := 'x'
} else if b12 ~= 0 & term := (a12/b12 = a1/b1 = a2/b2 = a/b) then {
suspend infinitized (term)
r12 := a12 % b12
r1 := a1 % b1
r2 := a2 % b2
r := a % b
a12 := b12; a1 := b1; a2 := b2; a := b
b12 := r12; b1 := r1; b2 := r2; b := r
} else {
# Put numerators over a common denominator.
n1 := a1 * b2 * b
n2 := a2 * b1 * b
n := a * b1 * b2
if abs (n1 - n) > abs (n2 - n) then
absorb_term_from := 'x'
else
absorb_term_from := 'y'
}

if \absorb_term_from === 'x' then {
term := @xsource
new_a2 := a12; new_a := a1
new_b2 := b12; new_b := b1
if \term then {
new_a12 := a2 + (a12 * term)
new_a1 := a + (a1 * term)
new_b12 := b2 + (b12 * term)
new_b1 := b + (b1 * term)
if too_big (new_a12 | new_a1 | new_a2 | new_a |
new_b12 | new_b1 | new_b2 | new_b) then
{
# All further terms are forced to "infinity".
xsource := make_source (&null)
new_a12 := a12; new_a1 := a1
new_b12 := b12; new_b1 := b1
}
}
a12 := new_a12; a1 := new_a1; a2 := new_a2; a := new_a
b12 := new_b12; b1 := new_b1; b2 := new_b2; b := new_b
}
else if \absorb_term_from === 'y' then {
term := @ysource
new_a1 := a12; new_a := a2
new_b1 := b12; new_b := b2
if \term then {
new_a12 := a1 + (a12 * term)
new_a2 := a + (a2 * term)
new_b12 := b1 + (b12 * term)
new_b2 := b + (b2 * term)
if too_big (new_a12 | new_a1 | new_a2 | new_a |
new_b12 | new_b1 | new_b2 | new_b) then
{
# All further terms are forced to "infinity".
ysource := make_source (&null)
new_a12 := a12; new_a2 := a2
new_b12 := b12; new_b2 := b2
}
}
a12 := new_a12; a1 := new_a1; a2 := new_a2; a := new_a
b12 := new_b12; b1 := new_b1; b2 := new_b2; b := new_b
}
}
end

procedure make_source (cf)
local source

if /cf then {
# Generate "infinity" terms.
source := create generate_constant (&null)
} else if type(cf) == "co-expression" then {
# Already a co-expression.
source := cf
} else {
# Use a continued fraction as a co-expression.
source := cf2coexpression (cf)
}
return source
end

procedure infinitized (term)
initial {
/practically_infinite_number := 2^64
}
if abs (term) >= abs (practically_infinite_number) then {
term := &null
}
return term
end

procedure too_big (num)
initial {
/much_too_big_number := 2^512
}
if abs (num) < abs (much_too_big_number) then fail
return num
end

procedure generate_constant (constant)
repeat suspend constant
end

procedure r2cf_generate (n, d)
local remainder
repeat {
if d = 0 then {
suspend &null
} else {
suspend (n / d)
remainder := n % d
n := d
d := remainder
}
}
end

procedure min (x, y)
return (if x < y then x else y)
end
</syntaxhighlight>

{{out}}
<pre>$ icon bivariate_continued_fraction_task_Icon.icn
golden ratio => [1;1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,...] (1 + sqrt(5))/2
silver ratio => [2;2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,...] (1 + sqrt(2))
sqrt(2) => [1;2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,...] silver ratio minus 1
13/11 => [1;5,2]
22/7 => [3;7] approximately pi
1 => [1]
2 => [2]
3 => [3]
4 => [4]
(1 + 1/sqrt(2))/2 => [0;1,5,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,...] method 1
(1 + 1/sqrt(2))/2 => [0;1,5,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,...] method 2
(1 + 1/sqrt(2))/2 => [0;1,5,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,...] method 3
sqrt(2) + sqrt(2) => [2;1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,...]
sqrt(2) - sqrt(2) => [0]
sqrt(2) * sqrt(2) => [2]
sqrt(2) / sqrt(2) => [1]
</pre>
</pre>