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

From Rosetta Code
Content added Content deleted
m (→‎{{header|Phix}}: added syntax colouring the hard way)
(Added Wren)
Line 1,265: Line 1,265:
div test -> 3,7
div test -> 3,7
layered test -> -2,1,2,5,1,2,1,26,3
layered test -> -2,1,2,5,1,2,1,26,3
</pre>

=={{header|Wren}}==
{{trans|Kotlin}}
<lang ecmascript>class MatrixNG {
construct new() {
_cfn = 0
_thisTerm = 0
_haveTerm = false
}
cfn { _cfn }
cfn=(v) { _cfn = v }

thisTerm { _thisTerm }
thisTerm=(v) { _thisTerm = v }

haveTerm { _haveTerm }
haveTerm=(v) { _haveTerm = v }

consumeTerm() {}
consumeTerm(n) {}
needTerm() {}
}

class NG4 is MatrixNG {
construct new(a1, a, b1, b) {
super()
_a1 = a1
_a = a
_b1 = b1
_b = b
_t = 0
}

needTerm() {
if (_b1 == 0 && _b == 0) return false
if (_b1 == 0 || _b == 0) return true
thisTerm = (_a / _b).truncate
if (thisTerm == (_a1 / _b1).truncate) {
_t = _a
_a = _b
_b = _t - _b * thisTerm
_t = _a1
_a1 = _b1
_b1 = _t - _b1 * thisTerm
haveTerm = true
return false
}
return true
}

consumeTerm() {
_a = _a1
_b = _b1
}

consumeTerm(n) {
_t = _a
_a = _a1
_a1 = _t + _a1 * n
_t = _b
_b = _b1
_b1 = _t + _b1 * n
}
}

class NG8 is MatrixNG {
construct new(a12, a1, a2, a, b12, b1, b2, b) {
super()
_a12 = a12
_a1 = a1
_a2 = a2
_a = a
_b12 = b12
_b1 = b1
_b2 = b2
_b = b
_t = 0
_ab = 0

_a1b1 = 0
_a2b2 = 0

_a12b12 = 0
}

chooseCFN() { ((_a1b1 - _ab).abs > (_a2b2 - _ab).abs) ? 0 : 1 }

needTerm() {
if (_b1 == 0 && _b == 0 && _b2 == 0 && _b12 == 0) return false
if (_b == 0) {
cfn = (_b2 == 0) ? 0 : 1
return true
} else _ab = _a/_b

if (_b2 == 0) {
cfn = 1
return true
} else _a2b2 = _a2/_b2

if (_b1 == 0) {
cfn = 0
return true
} else _a1b1 = _a1/_b1

if (_b12 == 0) {
cfn = chooseCFN()
return true
} else _a12b12 = _a12/_b12

thisTerm = _ab.truncate
if (thisTerm == _a1b1.truncate && thisTerm == _a2b2.truncate &&
thisTerm == _a12b12.truncate) {
_t = _a
_a = _b
_b = _t - _b * thisTerm
_t = _a1
_a1 = _b1
_b1 = _t - _b1 * thisTerm
_t = _a2
_a2 = _b2
_b2 = _t - _b2 * thisTerm
_t = _a12
_a12 = _b12
_b12 = _t - _b12 * thisTerm
haveTerm = true
return false
}
cfn = chooseCFN()
return true
}

consumeTerm() {
if (cfn == 0) {
_a = _a1
_a2 = _a12
_b = _b1
_b2 = _b12
} else {
_a = _a2
_a1 = _a12
_b = _b2
_b1 = _b12
}
}

consumeTerm(n) {
if (cfn == 0) {
_t = _a
_a = _a1
_a1 = _t + _a1 * n
_t = _a2
_a2 = _a12
_a12 = _t + _a12 * n
_t = _b
_b = _b1
_b1 = _t + _b1 * n
_t = _b2
_b2 = _b12
_b12 = _t + _b12 * n
} else {
_t = _a
_a = _a2
_a2 = _t + _a2 * n
_t = _a1
_a1 = _a12
_a12 = _t + _a12 * n
_t = _b
_b = _b2
_b2 = _t + _b2 * n
_t = _b1
_b1 = _b12
_b12 = _t + _b12 * n
}
}
}

class ContinuedFraction {
nextTerm() {}
moreTerms() {}
}

class R2cf is ContinuedFraction {
construct new(n1, n2) {
_n1 = n1
_n2 = n2
}

nextTerm() {
var thisTerm = (_n1/_n2).truncate
var t2 = _n2
_n2 = _n1 - thisTerm * _n2
_n1 = t2
return thisTerm
}

moreTerms() { _n2.abs > 0 }
}

class NG is ContinuedFraction {
construct new(ng, n1) {
_ng = ng
_n = [n1]
}

construct new(ng, n1, n2) {
_ng = ng
_n = [n1, n2]
}

nextTerm() {
_ng.haveTerm = false
return _ng.thisTerm
}

moreTerms() {
while (_ng.needTerm()) {
if (_n[_ng.cfn].moreTerms()) {
_ng.consumeTerm(_n[_ng.cfn].nextTerm())
} else {
_ng.consumeTerm()
}
}
return _ng.haveTerm
}
}

var test = Fn.new { |desc, cfs|
System.print("TESTING -> %(desc)")
for (cf in cfs) {
while (cf.moreTerms()) System.write("%(cf.nextTerm()) ")
System.print()
}
System.print()
}

var a = NG8.new(0, 1, 1, 0, 0, 0, 0, 1)
var n2 = R2cf.new(22, 7)
var n1 = R2cf.new(1, 2)
var a3 = NG4.new(2, 1, 0, 2)
var n3 = R2cf.new(22, 7)
test.call("[3;7] + [0;2]", [NG.new(a, n1, n2), NG.new(a3, n3)])

var b = NG8.new(1, 0, 0, 0, 0, 0, 0, 1)
var b1 = R2cf.new(13, 11)
var b2 = R2cf.new(22, 7)
test.call("[1;5,2] * [3;7]", [NG.new(b, b1, b2), R2cf.new(286, 77)])

var c = NG8.new(0, 1, -1, 0, 0, 0, 0, 1)
var c1 = R2cf.new(13, 11)
var c2 = R2cf.new(22, 7)
test.call("[1;5,2] - [3;7]", [NG.new(c, c1, c2), R2cf.new(-151, 77)])

var d = NG8.new(0, 1, 0, 0, 0, 0, 1, 0)
var d1 = R2cf.new(22 * 22, 7 * 7)
var d2 = R2cf.new(22,7)
test.call("Divide [] by [3;7]", [NG.new(d, d1, d2)])

var na = NG8.new(0, 1, 1, 0, 0, 0, 0, 1)
var a1 = R2cf.new(2, 7)
var a2 = R2cf.new(13, 11)
var aa = NG.new(na, a1, a2)
var nb = NG8.new(0, 1, -1, 0, 0, 0, 0, 1)
var b3 = R2cf.new(2, 7)
var b4 = R2cf.new(13, 11)
var bb = NG.new(nb, b3, b4)
var nc = NG8.new(1, 0, 0, 0, 0, 0, 0, 1)
var desc = "([0;3,2] + [1;5,2]) * ([0;3,2] - [1;5,2])"
test.call(desc, [NG.new(nc, aa, bb), R2cf.new(-7797, 5929)])</lang>

{{out}}
<pre>
TESTING -> [3;7] + [0;2]
3 1 1 1 4
3 1 1 1 4

TESTING -> [1;5,2] * [3;7]
3 1 2 2
3 1 2 2

TESTING -> [1;5,2] - [3;7]
-1 -1 -24 -1 -2
-1 -1 -24 -1 -2

TESTING -> Divide [] by [3;7]
3 7

TESTING -> ([0;3,2] + [1;5,2]) * ([0;3,2] - [1;5,2])
-1 -3 -5 -1 -2 -1 -26 -3
-1 -3 -5 -1 -2 -1 -26 -3
</pre>
</pre>



Revision as of 15:56, 29 March 2021

Continued fraction/Arithmetic/G(matrix ng, continued fraction n1, continued fraction n2) is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

This task performs the basic mathematical functions on 2 continued fractions. This requires the full version of matrix NG:

I may perform perform the following operations:

Input the next term of continued fraction N1
Input the next term of continued fraction N2
Output a term of the continued fraction resulting from the operation.

I output a term if the integer parts of and and and are equal. Otherwise I input a term from continued fraction N1 or continued fraction N2. If I need a term from N but N has no more terms I inject .

When I input a term t from continued fraction N1 I change my internal state:

is transposed thus

When I need a term from exhausted continued fraction N1 I change my internal state:

is transposed thus

When I input a term t from continued fraction N2 I change my internal state:

is transposed thus

When I need a term from exhausted continued fraction N2 I change my internal state:

is transposed thus

When I output a term t I change my internal state:

is transposed thus

When I need to choose to input from N1 or N2 I act:

if b and b2 are zero I choose N1
if b is zero I choose N2
if b2 is zero I choose N2
if abs( is greater than abs( I choose N1
otherwise I choose N2

When performing arithmetic operation on two potentially infinite continued fractions it is possible to generate a rational number. eg * should produce 2. This will require either that I determine that my internal state is approaching infinity, or limiting the number of terms I am willing to input without producing any output.

C++

Uses matrixNG, NG_4 and NG from Continued_fraction/Arithmetic/G(matrix_NG,_Contined_Fraction_N)#C++, and r2cf from Continued_fraction/Arithmetic/Construct_from_rational_number#C++ <lang cpp>/* Implement matrix NG

  Nigel Galloway, February 12., 2013
  • /

class NG_8 : public matrixNG {

 private: int a12, a1, a2, a, b12, b1, b2, b, t;
          double ab, a1b1, a2b2, a12b12;
 const int chooseCFN(){return fabs(a1b1-ab) > fabs(a2b2-ab)? 0 : 1;}
 const bool needTerm() {
   if (b1==0 and b==0 and b2==0 and b12==0) return false;
   if (b==0){cfn = b2==0? 0:1; return true;} else ab = ((double)a)/b;
   if (b2==0){cfn = 1; return true;} else a2b2 = ((double)a2)/b2;
   if (b1==0){cfn = 0; return true;} else a1b1 = ((double)a1)/b1;
   if (b12==0){cfn = chooseCFN(); return true;} else a12b12 = ((double)a12)/b12;
   thisTerm = (int)ab;
   if (thisTerm==(int)a1b1 and thisTerm==(int)a2b2 and thisTerm==(int)a12b12){
     t=a; a=b; b=t-b*thisTerm; t=a1; a1=b1; b1=t-b1*thisTerm; t=a2; a2=b2; b2=t-b2*thisTerm; t=a12; a12=b12; b12=t-b12*thisTerm;
     haveTerm = true; return false;
   }
   cfn = chooseCFN();
   return true;
 }
 void consumeTerm(){if(cfn==0){a=a1; a2=a12; b=b1; b2=b12;} else{a=a2; a1=a12; b=b2; b1=b12;}}
 void consumeTerm(int n){
   if(cfn==0){t=a; a=a1; a1=t+a1*n; t=a2; a2=a12; a12=t+a12*n; t=b; b=b1; b1=t+b1*n; t=b2; b2=b12; b12=t+b12*n;}
   else{t=a; a=a2; a2=t+a2*n; t=a1; a1=a12; a12=t+a12*n; t=b; b=b2; b2=t+b2*n; t=b1; b1=b12; b12=t+b12*n;}
 }
 public:
 NG_8(int a12, int a1, int a2, int a, int b12, int b1, int b2, int b): a12(a12), a1(a1), a2(a2), a(a), b12(b12), b1(b1), b2(b2), b(b){

}};</lang>

Testing

[3;7] + [0;2] <lang cpp>int main() {

 NG_8 a(0,1,1,0,0,0,0,1);
 r2cf n2(22,7);
 r2cf n1(1,2);
 for(NG n(&a, &n1, &n2); n.moreTerms(); std::cout << n.nextTerm() << " ");
 std::cout << std::endl;
 NG_4 a3(2,1,0,2);
 r2cf n3(22,7);
 for(NG n(&a3, &n3); n.moreTerms(); std::cout << n.nextTerm() << " ");
 std::cout << std::endl;
 return 0;

}</lang>

Output:
3 1 1 1 4
3 1 1 1 4

[1:5,2] * [3;7] <lang cpp>int main() {

 NG_8 b(1,0,0,0,0,0,0,1);
 r2cf b1(13,11);
 r2cf b2(22,7);
 for(NG n(&b, &b1, &b2); n.moreTerms(); std::cout << n.nextTerm() << " ");
 std::cout << std::endl;
 for(NG n(&a, &b2, &b1); n.moreTerms(); std::cout << n.nextTerm() << " ");
 std::cout << std::endl;
 for(r2cf cf(286,77); cf.moreTerms(); std::cout << cf.nextTerm() << " ");
 std::cout << std::endl;
 return 0;

}</lang>

Output:
3 1 2 2
3 1 2 2

[1:5,2] - [3;7] <lang cpp>int main() {

 NG_8 c(0,1,-1,0,0,0,0,1);
 r2cf c1(13,11);
 r2cf c2(22,7);
 for(NG n(&c, &c1, &c2); n.moreTerms(); std::cout << n.nextTerm() << " ");
 std::cout << std::endl;
 for(r2cf cf(-151,77); cf.moreTerms(); std::cout << cf.nextTerm() << " ");
 std::cout << std::endl;
 return 0;

}</lang>

Output:
-1 -1 -24 -1 -2
-1 -1 -24 -1 -2

Divide [] by [3;7] <lang cpp>int main() {

 NG_8 d(0,1,0,0,0,0,1,0);
 r2cf d1(22*22,7*7);
 r2cf d2(22,7);
 for(NG n(&d, &d1, &d2); n.moreTerms(); std::cout << n.nextTerm() << " ");
 std::cout << std::endl;
 return 0;

}</lang>

Output:
3 7

([0;3,2] + [1;5,2]) * ([0;3,2] - [1;5,2]) <lang cpp>int main() {

 r2cf a1(2,7);
 r2cf a2(13,11);
 NG_8 na(0,1,1,0,0,0,0,1);
 NG A(&na, &a1, &a2); //[0;3,2] + [1;5,2]
 r2cf b1(2,7);
 r2cf b2(13,11);
 NG_8 nb(0,1,-1,0,0,0,0,1);
 NG B(&nb, &b1, &b2); //[0;3,2] - [1;5,2]
 NG_8 nc(1,0,0,0,0,0,0,1); //A*B
 for(NG n(&nc, &A, &B); n.moreTerms(); std::cout << n.nextTerm() << " ");
 std::cout << std::endl;
 for(r2cf cf(2,7); cf.moreTerms(); std::cout << cf.nextTerm() << " ");
 std::cout << std::endl;
 for(r2cf cf(13,11); cf.moreTerms(); std::cout << cf.nextTerm() << " ");
 std::cout << std::endl;
 for(r2cf cf(-7797,5929); cf.moreTerms(); std::cout << cf.nextTerm() << " ");
 std::cout << std::endl;
 return 0;

}</lang>

Go

Adding to the existing package from the Continued_fraction/Arithmetic/Construct_from_rational_number#Go task, re-uses cf.go and rat.go as given in that task.

File ng8.go: <lang Go>package cf

import "math"

// A 2×4 matix: // [ a₁₂ a₁ a₂ a ] // [ b₁₂ b₁ b₂ b ] // // which when "applied" to two continued fractions N1 and N2 // gives a new continued fraction z such that: // // a₁₂ * N1 * N2 + a₁ * N1 + a₂ * N2 + a // z = ------------------------------------------- // b₁₂ * N1 * N2 + b₁ * N1 + b₂ * N2 + b // // Examples: // NG8{0,1,1,0, 0,0,0,1} gives N1 + N2 // NG8{0,1,-1,0, 0,0,0,1} gives N1 - N2 // NG8{1,0,0,0, 0,0,0,1} gives N1 * N2 // NG8{0,1,0,0, 0,0,1,0} gives N1 / N2 // NG8{21,-15,28,-20, 0,0,0,1} gives 21*N1*N2 -15*N1 +28*N2 -20 // which is (3*N1 + 4) * (7*N2 - 5) type NG8 struct { A12, A1, A2, A int64 B12, B1, B2, B int64 }

// Basic identities as NG8 matrices. var ( NG8Add = NG8{0, 1, 1, 0, 0, 0, 0, 1} NG8Sub = NG8{0, 1, -1, 0, 0, 0, 0, 1} NG8Mul = NG8{1, 0, 0, 0, 0, 0, 0, 1} NG8Div = NG8{0, 1, 0, 0, 0, 0, 1, 0} )

func (ng *NG8) needsIngest() bool { if ng.B12 == 0 || ng.B1 == 0 || ng.B2 == 0 || ng.B == 0 { return true } x := ng.A / ng.B return ng.A1/ng.B1 != x || ng.A2/ng.B2 != x && ng.A12/ng.B12 != x }

func (ng *NG8) isDone() bool { return ng.B12 == 0 && ng.B1 == 0 && ng.B2 == 0 && ng.B == 0 }

func (ng *NG8) ingestWhich() bool { // true for N1, false for N2 if ng.B == 0 && ng.B2 == 0 { return true } if ng.B == 0 || ng.B2 == 0 { return false } x1 := float64(ng.A1) / float64(ng.B1) x2 := float64(ng.A2) / float64(ng.B2) x := float64(ng.A) / float64(ng.B) return math.Abs(x1-x) > math.Abs(x2-x) }

func (ng *NG8) ingest(isN1 bool, t int64) { if isN1 { // [ a₁₂ a₁ a₂ a ] becomes [ a₂+a₁₂*t a+a₁*t a₁₂ a₁] // [ b₁₂ b₁ b₂ b ] [ b₂+b₁₂*t b+b₁*t b₁₂ b₁] ng.A12, ng.A1, ng.A2, ng.A, ng.B12, ng.B1, ng.B2, ng.B = ng.A2+ng.A12*t, ng.A+ng.A1*t, ng.A12, ng.A1, ng.B2+ng.B12*t, ng.B+ng.B1*t, ng.B12, ng.B1 } else { // [ a₁₂ a₁ a₂ a ] becomes [ a₁+a₁₂*t a₁₂ a+a₂*t a₂] // [ b₁₂ b₁ b₂ b ] [ b₁+b₁₂*t b₁₂ b+b₂*t b₂] ng.A12, ng.A1, ng.A2, ng.A, ng.B12, ng.B1, ng.B2, ng.B = ng.A1+ng.A12*t, ng.A12, ng.A+ng.A2*t, ng.A2, ng.B1+ng.B12*t, ng.B12, ng.B+ng.B2*t, ng.B2 } }

func (ng *NG8) ingestInfinite(isN1 bool) { if isN1 { // [ a₁₂ a₁ a₂ a ] becomes [ a₁₂ a₁ a₁₂ a₁ ] // [ b₁₂ b₁ b₂ b ] [ b₁₂ b₁ b₁₂ b₁ ] ng.A2, ng.A, ng.B2, ng.B = ng.A12, ng.A1, ng.B12, ng.B1 } else { // [ a₁₂ a₁ a₂ a ] becomes [ a₁₂ a₁₂ a₂ a₂ ] // [ b₁₂ b₁ b₂ b ] [ b₁₂ b₁₂ b₂ b₂ ] ng.A1, ng.A, ng.B1, ng.B = ng.A12, ng.A2, ng.B12, ng.B2 } }

func (ng *NG8) egest(t int64) { // [ a₁₂ a₁ a₂ a ] becomes [ b₁₂ b₁ b₂ b ] // [ b₁₂ b₁ b₂ b ] [ a₁₂-b₁₂*t a₁-b₁*t a₂-b₂*t a-b*t ] ng.A12, ng.A1, ng.A2, ng.A, ng.B12, ng.B1, ng.B2, ng.B = ng.B12, ng.B1, ng.B2, ng.B, ng.A12-ng.B12*t, ng.A1-ng.B1*t, ng.A2-ng.B2*t, ng.A-ng.B*t }

// ApplyTo "applies" the matrix `ng` to the continued fractions // `N1` and `N2`, returning the resulting continued fraction. // After ingesting `limit` terms without any output terms the resulting // continued fraction is terminated. func (ng NG8) ApplyTo(N1, N2 ContinuedFraction, limit int) ContinuedFraction { return func() NextFn { next1, next2 := N1(), N2() done := false sinceEgest := 0 return func() (int64, bool) { if done { return 0, false } for ng.needsIngest() { sinceEgest++ if sinceEgest > limit { done = true return 0, false } isN1 := ng.ingestWhich() next := next2 if isN1 { next = next1 } if t, ok := next(); ok { ng.ingest(isN1, t) } else { ng.ingestInfinite(isN1) } } sinceEgest = 0 t := ng.A / ng.B ng.egest(t) done = ng.isDone() return t, true } } }</lang> File ng8_test.go: <lang Go>package cf

import "fmt"

func ExampleNG8() { cases := [...]struct { op string r1, r2 Rat ng NG8 }{ {"+", Rat{22, 7}, Rat{1, 2}, NG8Add}, {"*", Rat{13, 11}, Rat{22, 7}, NG8Mul}, {"-", Rat{13, 11}, Rat{22, 7}, NG8Sub}, {"/", Rat{22 * 22, 7 * 7}, Rat{22, 7}, NG8Div}, } for _, tc := range cases { n1 := tc.r1.AsContinuedFraction() n2 := tc.r2.AsContinuedFraction() z := tc.ng.ApplyTo(n1, n2, 1000) fmt.Printf("%v %s %v is %v %v %v gives %v\n", tc.r1, tc.op, tc.r2, tc.ng, n1, n2, z, ) }

z := NG8Mul.ApplyTo(Sqrt2, Sqrt2, 1000) fmt.Println("√2 * √2 =", z)

// Output: // 22/7 + 1/2 is {0 1 1 0 0 0 0 1} [3; 7] [0; 2] gives [3; 1, 1, 1, 4] // 13/11 * 22/7 is {1 0 0 0 0 0 0 1} [1; 5, 2] [3; 7] gives [3; 1, 2, 2] // 13/11 - 22/7 is {0 1 -1 0 0 0 0 1} [1; 5, 2] [3; 7] gives [-1; -1, -24, -1, -2] // 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] }</lang>

Output:

(Note, [1; 0, 1] = 1 + 1 / (0 + 1/1 ) = 2, so the answer is correct, it should however be normalised to the more reasonable form of [2].)

22/7 + 1/2 is {0 1 1 0 0 0 0 1} [3; 7] [0; 2] gives [3; 1, 1, 1, 4]
13/11 * 22/7 is {1 0 0 0 0 0 0 1} [1; 5, 2] [3; 7] gives [3; 1, 2, 2]
13/11 - 22/7 is {0 1 -1 0 0 0 0 1} [1; 5, 2] [3; 7] gives [-1; -1, -24, -1, -2]
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]

Julia

Translation of: Kotlin

<lang julia>abstract type MatrixNG end

mutable struct NG4 <: MatrixNG

   cfn::Int
   thisterm::Int
   haveterm::Bool
   a1::Int
   a::Int
   b1::Int
   b::Int
   NG4(a1, a, b1, b) = new(0, 0, false, a1, a, b1, b)

end

mutable struct NG8 <: MatrixNG

   cfn::Int
   thisterm::Int
   haveterm::Bool
   a12::Int
   a1::Int
   a2::Int
   a::Int
   b12::Int
   b1::Int
   b2::Int
   b::Int
   NG8(a12, a1, a2, a, b12, b1, b2, b) = new(0, 0, false, a12, a1, a2, a, b12, b1, b2, b)

end

function needterm(m::NG4)::Bool

   m.b1 == m.b == 0 && return false
   (m.b1 == 0 || m.b == 0) && return true
   (m.thisterm = m.a ÷ m.b) != m.a1 ÷ m.b1 && return true
   m.a, m.b = m.b, m.a - m.b * m.thisterm
   m.a1, m.b1, m.haveterm = m.b1, m.a1 - m.b1 * m.thisterm, true
   return false

end

consumeterm(m::NG4) = (m.a = m.a1; m.b = m.b1) function consumeterm(m::NG4, n)

   m.a, m.a1 = m.a1, m.a + m.a1 * n
   m.b, m.b1 = m.b1, m.b + m.b1 * n

end

function needterm(m::NG8)::Bool

   m.b1 == m.b == m.b2 == m.b12 == 0 && return false
   if m.b == 0
       m.cfn = m.b2 == 0 ? 0 : 1
       return true
   elseif m.b2 == 0
       m.cfn = 1
       return true
   elseif m.b1 == 0
       m.cfn = 0
       return true
   end
   ab = m.a / m.b
   a1b1 = m.a1 / m.b1
   a2b2 = m.a2 / m.b2
   if m.b12 == 0
       m.cfn = abs(a1b1 - ab) > abs(a2b2 - ab) ? 0 : 1
       return true
   end
   m.thisterm = m.a ÷ m.b
   if m.thisterm == m.a1 ÷ m.b1 == m.a2 ÷ m.b2 == m.a12 ÷ m.b12
       m.a, m.b = m.b, m.a - m.b * m.thisterm
       m.a1, m.b1 = m.b1, m.a1 - m.b1 * m.thisterm
       m.a2, m.b2 = m.b2, m.a2 - m.b2 * m.thisterm
       m.a12, m.b12, m.haveterm = m.b12, m.a12 - m.b12 * m.thisterm, true
       return false
   end
   m.cfn = abs(a1b1 - ab) > abs(a2b2 - ab) ? 0 : 1
   return true

end

function consumeterm(m::NG8)

   if m.cfn == 0
       m.a, m.a2 = m.a1, m.a12
       m.b, m.b2 = m.b1, m.b12
   else
       m.a, m.a1 = m.a2, m.a12
       m.b, m.b1 = m.b2, m.b12
   end

end function consumeterm(m::NG8, n)

   if m.cfn == 0
       m.a, m.a1 = m.a1, m.a + m.a1 * n
       m.a2, m.a12 = m.a12, m.a2 + m.a12 * n
       m.b, m.b1 = m.b1, m.b + m.b1 * n
       m.b2, m.b12 = m.b12, m.b2 + m.b12 * n
   else
       m.a, m.a2 = m.a2, m.a + m.a2 * n
       m.a1, m.a12 = m.a12, m.a1 + m.a12 * n
       m.b, m.b2 = m.b2, m.b + m.b2 * n
       m.b1, m.b12 = m.b12, m.b1 + m.b12 * n
   end

end

abstract type ContinuedFraction end

mutable struct R2cf <: ContinuedFraction

   n1::Int
   n2::Int

end

function nextterm(x::R2cf)

   term = x.n1 ÷ x.n2
   x.n1, x.n2 = x.n2, x.n1 - term * x.n2
   return term

end

moreterms(x::R2cf) = abs(x.n2) > 0

mutable struct NG <: ContinuedFraction

   ng::MatrixNG
   n::Vector{ContinuedFraction}

end NG(ng, n1::ContinuedFraction) = NG(ng, [n1]) NG(ng, n1::ContinuedFraction, n2) = NG(ng, [n1, n2]) nextterm(x::NG) = (x.ng.haveterm = false; x.ng.thisterm)

function moreterms(x::NG)::Bool

   while needterm(x.ng)
       if moreterms(x.n[x.ng.cfn + 1])
           consumeterm(x.ng, nextterm(x.n[x.ng.cfn + 1]))
       else
           consumeterm(x.ng)
       end
   end
   return x.ng.haveterm

end

function testcfs()

   function test(desc, cfs)
       println("TESTING -> $desc")
       for cf in cfs
           while moreterms(cf)
               print(nextterm(cf), " ")
           end
           println()
       end
       println()
   end
   a  = NG8(0, 1, 1, 0, 0, 0, 0, 1)
   n2 = R2cf(22, 7)
   n1 = R2cf(1, 2)
   a3 = NG4(2, 1, 0, 2)
   n3 = R2cf(22, 7)
   test("[3;7] + [0;2]", [NG(a, n1, n2), NG(a3, n3)])
   b  = NG8(1, 0, 0, 0, 0, 0, 0, 1)
   b1 = R2cf(13, 11)
   b2 = R2cf(22, 7)
   test("[1;5,2] * [3;7]", [NG(b, b1, b2), R2cf(286, 77)])
   c = NG8(0, 1, -1, 0, 0, 0, 0, 1)
   c1 = R2cf(13, 11)
   c2 = R2cf(22, 7)
   test("[1;5,2] - [3;7]", [NG(c, c1, c2), R2cf(-151, 77)])
   d = NG8(0, 1, 0, 0, 0, 0, 1, 0)
   d1 = R2cf(22 * 22, 7 * 7)
   d2 = R2cf(22, 7)
   test("Divide [] by [3;7]", [NG(d, d1, d2)])
   na = NG8(0, 1, 1, 0, 0, 0, 0, 1)
   a1 = R2cf(2, 7)
   a2 = R2cf(13, 11)
   aa = NG(na, a1, a2)
   nb = NG8(0, 1, -1, 0, 0, 0, 0, 1)
   b3 = R2cf(2, 7)
   b4 = R2cf(13, 11)
   bb = NG(nb, b3, b4)
   nc = NG8(1, 0, 0, 0, 0, 0, 0, 1)
   desc = "([0;3,2] + [1;5,2]) * ([0;3,2] - [1;5,2])"
   test(desc, [NG(nc, aa, bb), R2cf(-7797, 5929)])

end

testcfs()

</lang>

Output:
TESTING -> [3;7] + [0;2]
3 1 1 1 4
3 1 1 1 4 

TESTING -> [1;5,2] * [3;7]
3 1 2 2
3 1 2 2

TESTING -> [1;5,2] - [3;7]
-1 -1 -24 -1 -2
-1 -1 -24 -1 -2

TESTING -> Divide [] by [3;7]
3 7

TESTING -> ([0;3,2] + [1;5,2]) * ([0;3,2] - [1;5,2])
-1 -3 -5 -1 -2 -1 -26 -3
-1 -3 -5 -1 -2 -1 -26 -3

Kotlin

Translation of: C++

The C++ entry uses a number of classes which have been coded in other "Continued Fraction" tasks. I've pulled all these into my Kotlin translation and unified the tests so that the whole thing can, hopefully, be understood and run as a single program. <lang scala>// version 1.2.10

import kotlin.math.abs

abstract class MatrixNG {

   var cfn = 0
   var thisTerm = 0
   var haveTerm = false
   abstract fun consumeTerm()
   abstract fun consumeTerm(n: Int)
   abstract fun needTerm(): Boolean

}

class NG4(

   var a1: Int, var a: Int, var b1: Int,  var b: Int

) : MatrixNG() {

   private var t = 0
   override fun needTerm(): Boolean {
       if (b1 == 0 && b == 0) return false
       if (b1 == 0 || b == 0) return true
       thisTerm = a / b
       if (thisTerm ==  a1 / b1) {
           t = a;   a = b;   b = t - b  * thisTerm
           t = a1; a1 = b1; b1 = t - b1 * thisTerm      
           haveTerm = true
           return false
       }
       return true
   }
   override fun consumeTerm() {
       a = a1
       b = b1
   }
   override fun consumeTerm(n: Int) {
       t = a; a = a1; a1 = t + a1 * n 
       t = b; b = b1; b1 = t + b1 * n
   }

}

class NG8(

   var a12: Int, var a1: Int, var a2: Int, var a: Int,
   var b12: Int, var b1: Int, var b2: Int, var b: Int

) : MatrixNG() {

   private var t = 0
   private var ab = 0.0
   private var a1b1 = 0.0
   private var a2b2 = 0.0
   private var a12b12 = 0.0
   fun chooseCFN() = if (abs(a1b1 - ab) > abs(a2b2-ab)) 0 else 1
   override fun needTerm(): Boolean {
       if (b1 == 0 && b == 0 && b2 == 0 && b12 == 0) return false
       if (b == 0) {
           cfn = if (b2 == 0) 0 else 1
           return true
       }
       else ab = a.toDouble() / b
       if (b2 == 0) {
           cfn = 1
           return true
       } 
       else a2b2 = a2.toDouble() / b2
       if (b1 == 0) {
           cfn = 0
           return true
       }
       else a1b1 = a1.toDouble() / b1
       if (b12 == 0) {
           cfn = chooseCFN()
           return true
       }
       else a12b12 = a12.toDouble() / b12
       thisTerm = ab.toInt()
       if (thisTerm == a1b1.toInt() && thisTerm == a2b2.toInt() &&
           thisTerm == a12b12.toInt()) {
           t = a;     a = b;     b = t -   b * thisTerm
           t = a1;   a1 = b1;   b1 = t -  b1 * thisTerm
           t = a2;   a2 = b2;   b2 = t -  b2 * thisTerm
           t = a12; a12 = b12; b12 = t - b12 * thisTerm
           haveTerm = true
           return false
       }
       cfn = chooseCFN()
       return true
   }
   override fun consumeTerm() {
       if (cfn == 0) {
           a = a1; a2 = a12
           b = b1; b2 = b12
       }
       else {
           a = a2; a1 = a12
           b = b2; b1 = b12
       }
   }
   override fun consumeTerm(n: Int) {
       if (cfn == 0) {
           t = a;   a = a1;   a1 = t +  a1 * n
           t = a2; a2 = a12; a12 = t + a12 * n
           t = b;   b = b1;   b1 = t +  b1 * n
           t = b2; b2 = b12; b12 = t + b12 * n
       }
       else {
           t = a;   a = a2;   a2 = t +  a2 * n
           t = a1; a1 = a12; a12 = t + a12 * n
           t = b;   b = b2;   b2 = t +  b2 * n
           t = b1; b1 = b12; b12 = t + b12 * n
       }
   }

}

interface ContinuedFraction {

   fun nextTerm(): Int
   fun moreTerms(): Boolean

}

class R2cf(var n1: Int, var n2: Int) : ContinuedFraction {

   override fun nextTerm(): Int {
       val thisTerm = n1 /n2
       val t2 = n2
       n2 = n1 - thisTerm * n2
       n1 = t2
       return thisTerm
   }
   override fun moreTerms() = abs(n2) > 0

}

class NG : ContinuedFraction {

   val ng: MatrixNG
   val n: List<ContinuedFraction> 
   constructor(ng: NG4, n1: ContinuedFraction) {
       this.ng = ng
       n = listOf(n1)
   }
   constructor(ng: NG8, n1: ContinuedFraction, n2: ContinuedFraction) {
       this.ng = ng
       n = listOf(n1, n2)
   }
   override fun nextTerm(): Int {
       ng.haveTerm = false
       return ng.thisTerm
   }
   override fun moreTerms(): Boolean {
       while (ng.needTerm()) {
           if (n[ng.cfn].moreTerms())
               ng.consumeTerm(n[ng.cfn].nextTerm())
           else
               ng.consumeTerm()
       }
       return ng.haveTerm
   }

}

fun test(desc: String, vararg cfs: ContinuedFraction) {

   println("TESTING -> $desc")
   for (cf in cfs) {
       while (cf.moreTerms()) print ("${cf.nextTerm()} ")
       println()
   }
   println()

}

fun main(args: Array<String>) {

   val a  = NG8(0, 1, 1, 0, 0, 0, 0, 1)
   val n2 = R2cf(22, 7)
   val n1 = R2cf(1, 2)
   val a3 = NG4(2, 1, 0, 2)
   val n3 = R2cf(22, 7)
   test("[3;7] + [0;2]", NG(a, n1, n2), NG(a3, n3))
   val b  = NG8(1, 0, 0, 0, 0, 0, 0, 1)
   val b1 = R2cf(13, 11)
   val b2 = R2cf(22, 7)
   test("[1;5,2] * [3;7]", NG(b, b1, b2), R2cf(286, 77))
   val c = NG8(0, 1, -1, 0, 0, 0, 0, 1)
   val c1 = R2cf(13, 11)
   val c2 = R2cf(22, 7)
   test("[1;5,2] - [3;7]", NG(c, c1, c2), R2cf(-151, 77))
   val d = NG8(0, 1, 0, 0, 0, 0, 1, 0)
   val d1 = R2cf(22 * 22, 7 * 7)
   val d2 = R2cf(22,7)
   test("Divide [] by [3;7]", NG(d, d1, d2))
   val na = NG8(0, 1, 1, 0, 0, 0, 0, 1)
   val a1 = R2cf(2, 7)
   val a2 = R2cf(13, 11)
   val aa = NG(na, a1, a2)
   val nb = NG8(0, 1, -1, 0, 0, 0, 0, 1)
   val b3 = R2cf(2, 7)
   val b4 = R2cf(13, 11)
   val bb = NG(nb, b3, b4)
   val nc = NG8(1, 0, 0, 0, 0, 0, 0, 1)
   val desc = "([0;3,2] + [1;5,2]) * ([0;3,2] - [1;5,2])"
   test(desc, NG(nc, aa, bb), R2cf(-7797, 5929))

}</lang>

Output:
TESTING -> [3;7] + [0;2]
3 1 1 1 4 
3 1 1 1 4 

TESTING -> [1;5,2] * [3;7]
3 1 2 2 
3 1 2 2 

TESTING -> [1;5,2] - [3;7]
-1 -1 -24 -1 -2 
-1 -1 -24 -1 -2 

TESTING -> Divide [] by [3;7]
3 7 

TESTING -> ([0;3,2] + [1;5,2]) * ([0;3,2] - [1;5,2])
-1 -3 -5 -1 -2 -1 -26 -3 
-1 -3 -5 -1 -2 -1 -26 -3 

Phix

Library: Phix/Class

(self-contained)

class full_matrix
  --
  -- Used by apply_full_matrix()
  -- Note that each instance of full_matrix should be discarded after use.
  --
  integer a12, a1, a2, a,
          b12, b1, b2, b
 
  function need_term()
    if b12==0 or b1==0 or b2==0 or b==0 then
        return true
    end if
    atom ab = a/b
    return ab!=a1/b1 or ab!=a1/b2 or ab!=a12/b12
  end function
 
  function which_term()
    -- returns true for cf1, false for cf2
    if b==0 and b2==0 then return true end if
    if b==0 or b2==0 then return false end if
    if b1==0 then return true end if
    atom ab = a/b
    return abs(a1/b1-ab) > abs(a2/b2-ab)
  end function
 
  function next_term()
    integer t = floor(a/b)
    sequence newas = {b12,b1,b2,b},
             newbs = {a12-b12*t,a1-b1*t,a2-b2*t,a-b*t}
    {a12,a1,a2,a} = newas
    {b12,b1,b2,b} = newbs
    return t
  end function
 
  procedure in_term(bool is_cf1, object t={})
    if integer(t) then
        sequence newas = iff(is_cf1?{a2+a12*t, a+a1*t, a12, a1}
                                   :{a1+a12*t, a12, a+a2*t, a2}),
                 newbs = iff(is_cf1?{b2+b12*t, b+b1*t, b12, b1}
                                   :{b1+b12*t, b12, b+b2*t, b2})
        {a12, a1, a2, a} = newas
        {b12, b1, b2, b} = newbs
    elsif is_cf1 then
        {a2, a, b2, b} = {a12, a1, b12, b1}
    else
        {a1, a, b1, b} = {a12, a2, b12, b2}
    end if
  end procedure
 
  function done()
    return b12==0 and b1==0 and b2==0 and b==0
  end function
 
end class
 
function apply_full_matrix(sequence ctrl, cf1, cf2)
  --
  -- If ctrl is {a12, a1, a2, a,
  --             b12, b1, b2, b}
  --
  -- Then the result of apply_full_matrix(ctrl,cf1,cf2) would be
  --
  --        (a12*cf1*cf2 + a1*cf1 + a2*cf2 + a)
  --        -----------------------------------
  --        (b12*cf1*cf2 + b1*cf1 + b2*cf2 + b)
  --
  -- For instance:
  --        { 0, 1, 1, 0,       calculates cf1 + cf2
  --          0, 0, 0, 1}         (divided by 1)
  --
  --        { 0, 1,-1, 0,       calculates cf1 - cf2
  --          0, 0, 0, 1}         (divided by 1)
  --
  --        { 1, 0, 0, 0,       calculates cf1 * cf2
  --          0, 0, 0, 1}         (divided by 1)
  --
  --        { 0, 1, 0, 0,       calculates cf1
  --          0, 0, 1, 0}          divided by cf2
  --
    full_matrix fm = new(ctrl)
    sequence res = {}
    integer l1 = length(cf1), dx1=1, 
            l2 = length(cf2), dx2=1
    while true do   
        if fm.need_term() then
            bool is_cf1 = fm.which_term()
            object t = {}
            if is_cf1 then
                if dx1<=l1 then
                    t = cf1[dx1]
                    dx1 += 1
                end if
            else
                if dx2<=l2 then
                    t = cf2[dx2]
                    dx2 += 1
                end if
            end if
            fm.in_term(is_cf1,t)
        else
            res &= fm.next_term()
        end if
        if fm.done() then exit end if
    end while
    return res
end function
 
function r2cf(sequence rat, integer count=20)
    sequence s = {}
    atom {num,den} = rat
    while den!=0 and length(s)<count do
        s &= trunc(num/den)
        {num,den} = {den,num-s[$]*den}
    end while
    return s
end function
 
function cf2s(sequence cf)
    sequence s = join(apply(cf,sprint),",") -- eg "1,5,2"
    return "["&substitute(s,",",";",1)&"]"  -- => "[1;5,2]"
end function
 
include mpfr.e
 
function cf2r(sequence cf)
    mpq res = mpq_init(), -- 0/1
        cfn = mpq_init()
    for n=length(cf) to 1 by -1 do
        mpq_set_si(cfn,cf[n])
        mpq_add(res,res,cfn)
        if n=1 then exit end if
        mpq_inv(res,res)
    end for
    mpz num = mpz_init(),
        den = mpz_init()
    mpq_get_num(num,res)
    mpq_get_den(den,res)
    mpfr x = mpfr_init()
    mpfr_set_q(x,res)
    string xs = mpfr_sprintf("%.15Rf",x),
           ns = mpz_get_str(num),
           ds = mpz_get_str(den),
            s = sprintf("%s (%s/%s)",{xs,ns,ds})
    return s
end function
 
constant fmAdd = { 0, 1, 1, 0,  0, 0, 0, 1},
         fmSub = { 0, 1,-1, 0,  0, 0, 0, 1},
         fmMul = { 1, 0, 0, 0,  0, 0, 0, 1},
         fmDiv = { 0, 1, 0, 0,  0, 0, 1, 0},
         tests = {{"+",{22, 7},{ 1,2},fmAdd,22/7+1/2},
                  {"-",{13,11},{22,7},fmSub,13/11-22/7},
                  {"*",{13,11},{22,7},fmMul,13/11*22/7},
                  {"/",{22*22,7*7},{22,7},fmDiv,22/7}}
 
for i=1 to length(tests) do
    {string op, sequence rat1, sequence rat2, sequence m, atom eres2} = tests[i]
    sequence cf1 = r2cf(rat1),
             cf2 = r2cf(rat2),
             cfr = apply_full_matrix(m,cf1,cf2)
    string bop = sprintf("%s %s %s",{cf2s(cf1),op,cf2s(cf2)})
    printf(1,"%s is %s -> %s (est %g)\n",{bop,cf2s(cfr),cf2r(cfr),eres2})
end for
Output:
[3;7] + [0;2] is [3;1,1,1,4] -> 3.642857142857143 (51/14) (est 3.64286)
[1;5,2] - [3;7] is [-2;25,1,2] -> -1.961038961038961 (-151/77) (est -1.96104)
[1;5,2] * [3;7] is [3;1,2,2] -> 3.714285714285714 (26/7) (est 3.71429)
[9;1,7,6] / [3;7] is [3;7] -> 3.142857142857143 (22/7) (est 3.14286)

Raku

(formerly Perl 6)

Works with: Rakudo version 2016.01

The NG2 object can work with infinitely long continued fractions, it does lazy evaluation. By default, it is limited to returning the first 30 terms. Pass in a limit value if you want something other than default.

<lang perl6>class NG2 {

   has ( $!a12, $!a1, $!a2, $!a, $!b12, $!b1, $!b2, $!b );
   # Public methods
   method operator($!a12, $!a1, $!a2, $!a, $!b12, $!b1, $!b2, $!b ) { self }
   method apply(@cf1, @cf2, :$limit = 30) {
       my @cfs = [@cf1], [@cf2];
       gather {
           while @cfs[0] or @cfs[1] {
               my $term;
               (take $term if $term = self!extract) unless self!needterm;
               my $from = self!from;
               $from = @cfs[$from] ?? $from !! $from +^ 1;
               self!inject($from, @cfs[$from].shift);
           }
           take self!drain while $!b;
       }[ ^$limit ].grep: *.defined;
   }
   # Private methods
   method !inject ($n, $t) {
       multi sub xform(0, $t, $x12, $x1, $x2, $x) { $x2 + $x12 * $t, $x + $x1 * $t, $x12, $x1 }
       multi sub xform(1, $t, $x12, $x1, $x2, $x) { $x1 + $x12 * $t, $x12, $x + $x2 * $t, $x2 }
       ( $!a12, $!a1, $!a2, $!a ) = xform($n, $t, $!a12, $!a1, $!a2, $!a );
       ( $!b12, $!b1, $!b2, $!b ) = xform($n, $t, $!b12, $!b1, $!b2, $!b );
   }
   method !extract {
       my $t = $!a div $!b;
       ( $!a12, $!a1, $!a2, $!a, $!b12, $!b1, $!b2, $!b ) =
         $!b12, $!b1, $!b2, $!b,
                                 $!a12 - $!b12 * $t,
                                        $!a1 - $!b1 * $t,
                                              $!a2 - $!b2 * $t,
                                                    $!a - $!b * $t;
       $t;
   }
   method !from {
       return $!b == $!b2 == 0 ?? 0 !!
          $!b == 0 || $!b2 == 0 ?? 1 !!
          abs($!a1*$!b*$!b2 - $!a*$!b1*$!b2) > abs($!a2*$!b*$!b1 - $!a*$!b1*$!b2) ?? 0 !! 1;
   }
   method !needterm {
       so !([&&] $!b12, $!b1, $!b2, $!b) or $!a/$!b != $!a1/$!b1 != $!a2/$!b2 != $!a12/$!b1;
   }
   method !noterms($which) {
       $which ?? (($!a1, $!a, $!b1, $!b ) = $!a12, $!a2, $!b12, $!b2)
              !! (($!a2, $!a, $!b2, $!b ) = $!a12, $!a1, $!b12, $!b1);
   }
   method !drain {
   self!noterms(self!from) if self!needterm;
   self!extract;
   }

}

sub r2cf(Rat $x is copy) { # Rational to continued fraction

   gather loop {
   $x -= take $x.floor;
   last unless $x;
   $x = 1 / $x;
   }

}

sub cf2r(@a) { # continued fraction to Rational

   my $x = @a[* - 1].FatRat; # Use FatRats for arbitrary precision
   $x = @a[$_- 1] + 1 / $x for reverse 1 ..^ @a;
   $x

}

  1. format continued fraction for pretty printing

sub ppcf(@cf) { "[{ @cf.join(',').subst(',',';') }]" }

  1. format Rational for pretty printing. Use FatRats for arbitrary precision

sub pprat($a) { $a.FatRat.denominator == 1 ?? $a !! $a.FatRat.nude.join('/') }

my %ops = ( # convenience hash of NG matrix operators

   '+' => (0,1,1,0,0,0,0,1),
   '-' => (0,1,-1,0,0,0,0,1),
   '*' => (1,0,0,0,0,0,0,1),
   '/' => (0,1,0,0,0,0,1,0)

);

sub test_NG2 ($rat1, $op, $rat2) {

   my @cf1 = $rat1.&r2cf;
   my @cf2 = $rat2.&r2cf;
   my @result = NG2.new.operator(|%ops{$op}).apply( @cf1, @cf2 );
   say "{$rat1.&pprat} $op {$rat2.&pprat} => {@cf1.&ppcf} $op ",
       "{@cf2.&ppcf} = {@result.&ppcf} => {@result.&cf2r.&pprat}\n";

}

  1. Testing

test_NG2(|$_) for

  [   22/7, '+',  1/2 ],
  [  23/11, '*', 22/7 ],
  [  13/11, '-', 22/7 ],
  [ 484/49, '/', 22/7 ];


  1. Sometimes you may want to limit the terms in the continued fraction to something other than default.
  2. Here a lazy infinite continued fraction for √2, then multiply it by itself. We'll limit the result
  3. to 6 terms for brevity’s' sake. We'll then convert that continued fraction back to an arbitrary precision
  4. FatRat Rational number. (Raku stores FatRats internally as a ratio of two arbitrarily long integers.
  5. We need to exercise a little caution because they can eat up all of your memory if allowed to grow unchecked,
  6. hence the limit of 6 terms in continued fraction.) We'll then convert that number to a normal precision
  7. Rat, which is accurate to the nearest 1 / 2^64,

say "√2 expressed as a continued fraction, then squared: "; my @root2 = lazy flat 1, 2 xx *; my @result = NG2.new.operator(|%ops{'*'}).apply( @root2, @root2, limit => 6 ); say @root2.&ppcf, "² = \n"; say @result.&ppcf; say "\nConverted back to an arbitrary (ludicrous) precision Rational: "; say @result.&cf2r.nude.join(" /\n"); say "\nCoerced to a standard precision Rational: ", @result.&cf2r.Num.Rat;</lang>

Output:
22/7 + 1/2 => [3;7] + [0;2] = [3;1,1,1,4] => 51/14

23/11 * 22/7 => [2;11] * [3;7] = [6;1,1,3] => 46/7

13/11 - 22/7 => [1;5,2] - [3;7] = [-2;25,1,2] => -151/77

484/49 / 22/7 => [9;1,7,6] / [3;7] = [3;7] => 22/7

√2 expressed as a continued fraction, then squared: 
[1;2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,...]² = 

[1;1,-58451683124983302025,-1927184886226364356176,-65467555105469489418600,-2223969688699736275876224]

Converted back to an arbitrary (ludicrous) precision Rational: 
32802382178012409621354320392819425499699206367450594986122623570838188983519955166754002 /
16401191089006204810536863200564985394427741343927508600629139291039556821665755787817601

Coerced to a standard precision Rational: 2

Tcl

This uses the Generator class, R2CF class and printcf procedure from the r2cf task.

Works with: Tcl version 8.6

<lang tcl>oo::class create NG2 {

   variable a b a1 b1 a2 b2 a12 b12 cf1 cf2
   superclass Generator
   constructor {args} {

lassign $args a12 a1 a2 a b12 b1 b2 b next

   }
   method operands {N1 N2} {

set cf1 $N1 set cf2 $N2 return [self]

   }
   method Ingress1 t {

lassign [list [expr {$a2+$a12*$t}] [expr {$a+$a1*$t}] $a12 $a1 \ [expr {$b2+$b12*$t}] [expr {$b+$b1*$t}] $b12 $b1] \ a12 a1 a2 a b12 b1 b2 b

   }
   method Exhaust1 {} {

lassign [list $a12 $a1 $a12 $a1 $b12 $b1 $b12 $b1] \ a12 a1 a2 a b12 b1 b2 b

   }
   method Ingress2 t {

lassign [list [expr {$a1+$a12*$t}] $a12 [expr {$a+$a2*$t}] $a2 \ [expr {$b1+$b12*$t}] $b12 [expr {$b+$b2*$t}] $b2] \ a12 a1 a2 a b12 b1 b2 b

   }
   method Exhaust2 {} {

lassign [list $a12 $a12 $a2 $a2 $b12 $b12 $b2 $b2] \ a12 a1 a2 a b12 b1 b2 b

   }
   method Egress {} {

set t [expr {$a/$b}] lassign [list $b12 $b1 $b2 $b \ [expr {$a12 - $b12*$t}] [expr {$a1 - $b1*$t}] \ [expr {$a2 - $b2*$t}] [expr {$a - $b*$t}]] \ a12 a1 a2 a b12 b1 b2 b return $t

   }
   method DoIngress1 {} {

try {tailcall my Ingress1 [$cf1]} on break {} {} oo::objdefine [self] forward DoIngress1 my Exhaust1 set cf1 "" tailcall my Exhaust1

   }
   method DoIngress2 {} {

try {tailcall my Ingress2 [$cf2]} on break {} {} oo::objdefine [self] forward DoIngress2 my Exhaust2 set cf2 "" tailcall my Exhaust2

   }
   method Ingress {} {

if {$b==0} { if {$b2 == 0} { tailcall my DoIngress1 } else { tailcall my DoIngress2 } } if {!$b2} { tailcall my DoIngress2 } if {!$b1} { tailcall my DoIngress1 } if {[my FirstSource?]} { tailcall my DoIngress1 } else { tailcall my DoIngress2 }

   }
   method FirstSource? {} {

expr {abs($a1*$b*$b2 - $a*$b1*$b2) > abs($a2*$b*$b1 - $a*$b1*$b2)}

   }
   method NeedTerm? {} {

expr { ($b*$b1*$b2*$b12==0) ||  !($a/$b == $a1/$b1 && $a/$b == $a2/$b2 && $a/$b == $a12/$b12) }

   }
   method Done? {} {

expr {$b==0 && $b1==0 && $b2==0 && $b12==0}

   }
   method Produce {} {

# Until we've drained both continued fractions... while {$cf1 ne "" || $cf2 ne ""} { if {[my NeedTerm?]} { my Ingress } else { yield [my Egress] } } # Drain our internal state while {![my Done?]} { yield [my Egress] }

   }

}</lang> Demonstrating: <lang tcl>set op [[NG2 new 0 1 1 0 0 0 0 1] operands [R2CF new 1/2] [R2CF new 22/7]] printcf "\[3;7\] + \[0;2\]" $op

set op [[NG2 new 1 0 0 0 0 0 0 1] operands [R2CF new 13/11] [R2CF new 22/7]] printcf "\[1:5,2\] * \[3;7\]" $op

set op [[NG2 new 0 1 -1 0 0 0 0 1] operands [R2CF new 13/11] [R2CF new 22/7]] printcf "\[1:5,2\] - \[3;7\]" $op

set op [[NG2 new 0 1 0 0 0 0 1 0] operands [R2CF new 484/49] [R2CF new 22/7]] printcf "div test" $op

set op1 [[NG2 new 0 1 1 0 0 0 0 1] operands [R2CF new 2/7] [R2CF new 13/11]] set op2 [[NG2 new 0 1 -1 0 0 0 0 1] operands [R2CF new 2/7] [R2CF new 13/11]] set op3 [[NG2 new 1 0 0 0 0 0 0 1] operands $op1 $op2] printcf "layered test" $op3</lang>

Output:
[3;7] + [0;2]  -> 3,1,1,1,4
[1:5,2] * [3;7]-> 3,1,2,2
[1:5,2] - [3;7]-> -2,25,1,2
div test       -> 3,7
layered test   -> -2,1,2,5,1,2,1,26,3

Wren

Translation of: Kotlin

<lang ecmascript>class MatrixNG {

   construct new() {
      _cfn = 0
      _thisTerm = 0
      _haveTerm = false
   }
   cfn     { _cfn }
   cfn=(v) { _cfn = v }
   thisTerm     { _thisTerm }
   thisTerm=(v) { _thisTerm = v }
   haveTerm     { _haveTerm }
   haveTerm=(v) { _haveTerm = v }
   consumeTerm() {}
   consumeTerm(n) {}
   needTerm() {}

}

class NG4 is MatrixNG {

   construct new(a1, a, b1, b) {
       super()
       _a1 = a1
       _a  = a
       _b1 = b1
       _b  = b
       _t  = 0
   }
   needTerm() {
       if (_b1 == 0 && _b == 0) return false
       if (_b1 == 0 || _b == 0) return true
       thisTerm = (_a / _b).truncate
       if (thisTerm ==  (_a1 / _b1).truncate) {
           _t = _a
           _a = _b
           _b = _t - _b  * thisTerm
           _t = _a1
           _a1 = _b1
           _b1 = _t - _b1 * thisTerm
           haveTerm = true
           return false
       }
       return true
   }
   consumeTerm() {
       _a = _a1
       _b = _b1
   }
   consumeTerm(n) {
       _t = _a
       _a = _a1
       _a1 = _t + _a1 * n
       _t = _b
       _b = _b1
       _b1 = _t + _b1 * n
   }

}

class NG8 is MatrixNG {

   construct new(a12, a1, a2, a, b12, b1, b2, b) {
       super()
       _a12 = a12
       _a1  = a1
       _a2  = a2
       _a   = a
       _b12 = b12
       _b1  = b1
       _b2  = b2
       _b   = b
       _t   = 0
       _ab  = 0
       _a1b1 = 0
       _a2b2 = 0
       _a12b12 = 0
   }
   chooseCFN() { ((_a1b1 - _ab).abs > (_a2b2 - _ab).abs) ? 0 : 1 }
   needTerm() {
       if (_b1 == 0 && _b == 0 && _b2 == 0 && _b12 == 0) return false
       if (_b == 0) {
           cfn = (_b2 == 0) ? 0 : 1
           return true
       } else _ab = _a/_b
       if (_b2 == 0) {
           cfn = 1
           return true
       } else _a2b2 = _a2/_b2
       if (_b1 == 0) {
           cfn = 0
           return true
       } else _a1b1 = _a1/_b1
       if (_b12 == 0) {
           cfn = chooseCFN()
           return true
       } else _a12b12 = _a12/_b12
       thisTerm = _ab.truncate
       if (thisTerm == _a1b1.truncate && thisTerm == _a2b2.truncate &&
           thisTerm == _a12b12.truncate) {
           _t = _a     
           _a = _b
           _b = _t - _b * thisTerm
           _t = _a1
           _a1 = _b1
           _b1 = _t - _b1 * thisTerm
           _t = _a2  
           _a2 = _b2
           _b2 = _t - _b2 * thisTerm
           _t = _a12
           _a12 = _b12
           _b12 = _t - _b12 * thisTerm
           haveTerm = true
           return false
       }
       cfn = chooseCFN()
       return true
   }
   consumeTerm() {
       if (cfn == 0) {
           _a  = _a1
           _a2 = _a12
           _b  = _b1
           _b2 = _b12
       } else {
           _a  = _a2
           _a1 = _a12
           _b  = _b2
           _b1 = _b12
       }
   }
   consumeTerm(n) {
       if (cfn == 0) {
           _t = _a      
           _a = _a1
           _a1 = _t + _a1 * n
           _t = _a2
           _a2 = _a12
           _a12 = _t + _a12 * n
           _t = _b
           _b = _b1
           _b1 = _t + _b1 * n
           _t = _b2
           _b2 = _b12
           _b12 = _t + _b12 * n
       } else {
           _t = _a      
           _a = _a2
           _a2 = _t + _a2 * n
           _t = _a1
           _a1 = _a12
           _a12 = _t + _a12 * n
           _t = _b
           _b = _b2
           _b2 = _t +  _b2 * n
           _t = _b1
           _b1 = _b12
           _b12 = _t + _b12 * n
       }
   }

}

class ContinuedFraction {

   nextTerm() {}
   moreTerms() {}

}

class R2cf is ContinuedFraction {

   construct new(n1, n2) {
       _n1 = n1
       _n2 = n2
   }
   nextTerm() {
       var thisTerm = (_n1/_n2).truncate
       var t2 = _n2
       _n2 = _n1 - thisTerm * _n2
       _n1 = t2
       return thisTerm
   }
   moreTerms() { _n2.abs > 0 }

}

class NG is ContinuedFraction {

   construct new(ng, n1) {
       _ng = ng
       _n = [n1]
   }
   construct new(ng, n1, n2) {
       _ng = ng
       _n = [n1, n2]
   }
   nextTerm() {
       _ng.haveTerm = false
       return _ng.thisTerm
   }
   moreTerms() {
       while (_ng.needTerm()) {
           if (_n[_ng.cfn].moreTerms()) {
               _ng.consumeTerm(_n[_ng.cfn].nextTerm())
           } else {
               _ng.consumeTerm()
           }
       }
       return _ng.haveTerm
   }

}

var test = Fn.new { |desc, cfs|

   System.print("TESTING -> %(desc)")
   for (cf in cfs) {
       while (cf.moreTerms()) System.write("%(cf.nextTerm()) ")
       System.print()
   }
   System.print()

}

var a = NG8.new(0, 1, 1, 0, 0, 0, 0, 1) var n2 = R2cf.new(22, 7) var n1 = R2cf.new(1, 2) var a3 = NG4.new(2, 1, 0, 2) var n3 = R2cf.new(22, 7) test.call("[3;7] + [0;2]", [NG.new(a, n1, n2), NG.new(a3, n3)])

var b = NG8.new(1, 0, 0, 0, 0, 0, 0, 1) var b1 = R2cf.new(13, 11) var b2 = R2cf.new(22, 7) test.call("[1;5,2] * [3;7]", [NG.new(b, b1, b2), R2cf.new(286, 77)])

var c = NG8.new(0, 1, -1, 0, 0, 0, 0, 1) var c1 = R2cf.new(13, 11) var c2 = R2cf.new(22, 7) test.call("[1;5,2] - [3;7]", [NG.new(c, c1, c2), R2cf.new(-151, 77)])

var d = NG8.new(0, 1, 0, 0, 0, 0, 1, 0) var d1 = R2cf.new(22 * 22, 7 * 7) var d2 = R2cf.new(22,7) test.call("Divide [] by [3;7]", [NG.new(d, d1, d2)])

var na = NG8.new(0, 1, 1, 0, 0, 0, 0, 1) var a1 = R2cf.new(2, 7) var a2 = R2cf.new(13, 11) var aa = NG.new(na, a1, a2) var nb = NG8.new(0, 1, -1, 0, 0, 0, 0, 1) var b3 = R2cf.new(2, 7) var b4 = R2cf.new(13, 11) var bb = NG.new(nb, b3, b4) var nc = NG8.new(1, 0, 0, 0, 0, 0, 0, 1) var desc = "([0;3,2] + [1;5,2]) * ([0;3,2] - [1;5,2])" test.call(desc, [NG.new(nc, aa, bb), R2cf.new(-7797, 5929)])</lang>

Output:
TESTING -> [3;7] + [0;2]
3 1 1 1 4 
3 1 1 1 4 

TESTING -> [1;5,2] * [3;7]
3 1 2 2 
3 1 2 2 

TESTING -> [1;5,2] - [3;7]
-1 -1 -24 -1 -2 
-1 -1 -24 -1 -2 

TESTING -> Divide [] by [3;7]
3 7 

TESTING -> ([0;3,2] + [1;5,2]) * ([0;3,2] - [1;5,2])
-1 -3 -5 -1 -2 -1 -26 -3 
-1 -3 -5 -1 -2 -1 -26 -3