continuedfraction.js 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +133 -0
- package/continuedfraction.d.ts +80 -0
- package/dist/continuedfraction.js +179 -0
- package/dist/continuedfraction.min.js +10 -0
- package/dist/continuedfraction.mjs +177 -0
- package/package.json +59 -0
- package/src/continuedfraction.js +179 -0
- package/tests/continued.js +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Robert Eisele
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# ContinuedFraction.js
|
|
2
|
+
|
|
3
|
+
[](https://npmjs.org/package/continuedfraction.js "View this project on npm")
|
|
4
|
+
[](http://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
A lightweight JavaScript library sitting on the shoulders of [Fraction.js](https://github.com/rawify/Fraction.js) for generating and evaluating **standard** and **generalized** continued fractions. It is built with generator-based sequences and convergent recurrences for fast execution.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Generate the simple continued‑fraction expansion of √N
|
|
12
|
+
- Convert any real number or rational to its continued‑fraction
|
|
13
|
+
- Infinite generators for classic constants: φ (golden ratio), e, π, 4/π
|
|
14
|
+
- Evaluate (simple or generalized) continued fractions to a `Fraction`
|
|
15
|
+
|
|
16
|
+
## Example
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
const frac = ContinuedFraction.eval(
|
|
20
|
+
ContinuedFraction.fromFraction(3021, 203),
|
|
21
|
+
10 // Max Steps
|
|
22
|
+
);
|
|
23
|
+
console.log(frac.toString()); // → "3021/203"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
You can install `ContinuedFraction.js` via npm:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install continuedfraction.js
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or with yarn:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
yarn add continuedfraction.js
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Alternatively, download or clone the repository:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/rawify/ContinuedFraction.js
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
|
|
48
|
+
Include the `continuedfraction.min.js` file in your project:
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<script src="path/to/continuedfraction.min.js"></script>
|
|
52
|
+
<script>
|
|
53
|
+
var x = ContinuedFraction.sqrt(2);
|
|
54
|
+
</script>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or in a Node.js project:
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
const ContinuedFraction = require('continuedfraction.js');
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
or
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
import ContinuedFraction from 'continuedfraction.js';
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## ContinuedFraction API
|
|
70
|
+
|
|
71
|
+
Import the static utility class and use its generators and evaluator:
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
// 1) Continued‑fraction terms of √23
|
|
75
|
+
const sqrtGen = ContinuedFraction.sqrt(23);
|
|
76
|
+
console.log(sqrtGen.next().value); // 4
|
|
77
|
+
console.log(sqrtGen.next().value); // 1, 3, 1, 8, …
|
|
78
|
+
|
|
79
|
+
// 2) Continued‑fraction of a decimal
|
|
80
|
+
let cnt = 0;
|
|
81
|
+
for (let piCf of ContinuedFraction.fromNumber(Math.PI)) {
|
|
82
|
+
console.log(piCf);
|
|
83
|
+
if (cnt++ >= 10) break;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 3) Golden ratio φ terms
|
|
87
|
+
const phiGen = ContinuedFraction.PHI();
|
|
88
|
+
console.log(phiGen.next().value); // 1, and forever 1…
|
|
89
|
+
|
|
90
|
+
// 4) Evaluate the first 10 terms of e’s CF to a Fraction
|
|
91
|
+
const approxE = ContinuedFraction.eval(ContinuedFraction.E, 10);
|
|
92
|
+
console.log(approxE.toString()); // e ≈ “193/71”
|
|
93
|
+
|
|
94
|
+
// 5) Generalized CF for π, 4/π
|
|
95
|
+
const genPi = ContinuedFraction.PI();
|
|
96
|
+
console.log(genPi.next().value); // { a: 3, b: 0 }
|
|
97
|
+
console.log(genPi.next().value); // { a: 6, b: 1 }
|
|
98
|
+
|
|
99
|
+
// 6) Continued‑fraction from two integers
|
|
100
|
+
const halfCf = ContinuedFraction.fromFraction(1, 2);
|
|
101
|
+
console.log([...halfCf]); // [0, 2]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Methods
|
|
105
|
+
|
|
106
|
+
| Method | Signature | Description |
|
|
107
|
+
| ------------------------ | ----------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
108
|
+
| `sqrt(N: number)` | `Generator<number>` | Simple CF terms of √N |
|
|
109
|
+
| `fromNumber(n)` | `Generator<number>` | CF terms of any real via Fraction.js |
|
|
110
|
+
| `fromFraction(a, b)` | `Generator<number>` | CF terms of the rational a/b |
|
|
111
|
+
| `PHI()` | `Generator<number>` | Infinite 1’s for the golden ratio |
|
|
112
|
+
| `FOUR_OVER_PI()` | `Generator<CFTerm>` | Generalized CF terms for 4/π |
|
|
113
|
+
| `PI()` | `Generator<CFTerm>` | Generalized CF terms for π |
|
|
114
|
+
| `E()` | `Generator<number>` | CF expansion of e |
|
|
115
|
+
| `eval(generator, steps)` | `(Generator|() => Generator, steps?: number) ⇒ Fraction` | Evaluate (generalized) continued fraction to a `Fraction` approximation |
|
|
116
|
+
|
|
117
|
+
## Coding Style
|
|
118
|
+
|
|
119
|
+
As every library I publish, ContinuedFraction is also built to be as small as possible after compressing it with Google Closure Compiler in advanced mode. Thus the coding style orientates a little on maxing-out the compression rate. Please make sure you keep this style if you plan to extend the library.
|
|
120
|
+
|
|
121
|
+
## Building the library
|
|
122
|
+
|
|
123
|
+
After cloning the Git repository run:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
npm install
|
|
127
|
+
npm run build
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Copyright and Licensing
|
|
131
|
+
|
|
132
|
+
Copyright (c) 2025, [Robert Eisele](https://raw.org/)
|
|
133
|
+
Licensed under the MIT license.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
|
|
2
|
+
import type Fraction from 'fraction.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A term of a generalized continued fraction.
|
|
6
|
+
*/
|
|
7
|
+
export interface CFTerm {
|
|
8
|
+
/** The aₙ coefficient */
|
|
9
|
+
a: number;
|
|
10
|
+
/** The bₙ coefficient */
|
|
11
|
+
b: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Utility class for generating continued-fraction expansions of various constants.
|
|
16
|
+
* All methods are static.
|
|
17
|
+
*/
|
|
18
|
+
export default class ContinuedFraction {
|
|
19
|
+
/**
|
|
20
|
+
* Infinite generator for the continued‐fraction terms of √N.
|
|
21
|
+
* @param N Integer whose square‐root CF expansion is desired (N ≥ 0)
|
|
22
|
+
* @yields Next continued‐fraction term of √N
|
|
23
|
+
*/
|
|
24
|
+
static sqrt(N: number): Generator<number, void, unknown>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Generator for continued‐fraction terms of any real number via Fraction.js.
|
|
28
|
+
* @param n The real number to convert (as number, string, or bigint)
|
|
29
|
+
* @yields Next continued‐fraction term of n
|
|
30
|
+
*/
|
|
31
|
+
static fromNumber(n: number | string | bigint): Generator<number, void, unknown>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Generator for continued‐fraction terms of a rational a/b via Fraction.js.
|
|
35
|
+
* @param a Numerator (number, string, bigint, or Fraction)
|
|
36
|
+
* @param b Denominator (number, string, or bigint)
|
|
37
|
+
* @yields Next continued‐fraction term of a/b
|
|
38
|
+
*/
|
|
39
|
+
static fromFraction(
|
|
40
|
+
a: number | string | bigint | Fraction,
|
|
41
|
+
b: number | string | bigint
|
|
42
|
+
): Generator<number, void, unknown>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Infinite generator of the golden ratio φ = [1; 1, 1, 1, …].
|
|
46
|
+
* @yields Always 1
|
|
47
|
+
*/
|
|
48
|
+
static PHI(): Generator<number, void, unknown>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Infinite generator for the generalized continued‐fraction terms of 4/π.
|
|
52
|
+
* @yields Term pairs { a, b } for the continued‐fraction
|
|
53
|
+
*/
|
|
54
|
+
static FOUR_OVER_PI(): Generator<CFTerm, void, unknown>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Infinite generator for the generalized continued‐fraction terms of π.
|
|
58
|
+
* @yields Term pairs { a, b } for the continued‐fraction
|
|
59
|
+
*/
|
|
60
|
+
static PI(): Generator<CFTerm, void, unknown>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Infinite generator of e = [2; 1, 2, 1, 1, 4, 1, …].
|
|
64
|
+
* @yields Next continued‐fraction term of e
|
|
65
|
+
*/
|
|
66
|
+
static E(): Generator<number, void, unknown>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Evaluate a (simple or generalized) continued fraction generator.
|
|
70
|
+
* @param generator A CF term generator or a function returning one
|
|
71
|
+
* @param steps Number of terms to include (default 10)
|
|
72
|
+
* @returns Rational approximation as a Fraction
|
|
73
|
+
*/
|
|
74
|
+
static eval(
|
|
75
|
+
generator:
|
|
76
|
+
| Generator<number | CFTerm, any, any>
|
|
77
|
+
| (() => Generator<number | CFTerm, any, any>),
|
|
78
|
+
steps?: number
|
|
79
|
+
): Fraction;
|
|
80
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const Fraction = require('fraction.js');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Utility class for generating continued-fraction expansions of various constants.
|
|
8
|
+
*/
|
|
9
|
+
const ContinuedFraction = {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Infinite generator for the continued-fraction terms of sqrt(N).
|
|
13
|
+
* √N = [a0; (a1, a2, ..., a_p)], where the period ends when ak = 2*a0.
|
|
14
|
+
* For perfect squares, yields only a0 = floor(sqrt(N)) and then returns.
|
|
15
|
+
*
|
|
16
|
+
* @param {number} N - Integer whose square root CF expansion is desired (N ≥ 0).
|
|
17
|
+
* @yields {number} - Next continued-fraction term of √N.
|
|
18
|
+
*/
|
|
19
|
+
"sqrt": function* (N) {
|
|
20
|
+
|
|
21
|
+
const a0 = Math.floor(Math.sqrt(N));
|
|
22
|
+
yield a0;
|
|
23
|
+
if (a0 * a0 === N) return; // perfect square: single-term CF
|
|
24
|
+
|
|
25
|
+
//while (true) {
|
|
26
|
+
let nk = 0;
|
|
27
|
+
let dk = 1;
|
|
28
|
+
let ak = a0;
|
|
29
|
+
|
|
30
|
+
do {
|
|
31
|
+
nk = ak * dk - nk;
|
|
32
|
+
dk = (N - nk * nk) / dk; // remains integer by construction
|
|
33
|
+
ak = Math.floor((a0 + nk) / dk);
|
|
34
|
+
yield ak;
|
|
35
|
+
} while (/* 2 * a0 !== ak */ true);
|
|
36
|
+
//}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Generator for continued-fraction terms of any real number via Fraction.js.
|
|
41
|
+
*
|
|
42
|
+
* @exports
|
|
43
|
+
* @param {number|string|BigInt} n - The real number to convert (as number or string).
|
|
44
|
+
* @yields {number} - Next continued-fraction term of n.
|
|
45
|
+
*/
|
|
46
|
+
"fromNumber": function* (n) {
|
|
47
|
+
|
|
48
|
+
yield* Fraction(n)['toContinued']();
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Generator for continued-fraction terms of a rational a/b via Fraction.js.
|
|
53
|
+
*
|
|
54
|
+
* @param {number|string|BigInt|Fraction} a - Numerator.
|
|
55
|
+
* @param {number|string|BigInt} b - Denominator.
|
|
56
|
+
* @yields {number} - Next continued-fraction term of a/b.
|
|
57
|
+
*/
|
|
58
|
+
"fromFraction": function* (a, b) {
|
|
59
|
+
|
|
60
|
+
yield* Fraction(a, b)['toContinued']();
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Infinite generator of the golden ratio φ = [1; 1, 1, 1, …].
|
|
65
|
+
*
|
|
66
|
+
* @yields {number} - Always 1.
|
|
67
|
+
*/
|
|
68
|
+
"PHI": function* () {
|
|
69
|
+
|
|
70
|
+
while (true) {
|
|
71
|
+
yield 1;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Infinite generator for Continued‐fraction terms of 4/π:
|
|
77
|
+
* 4/π = 1 + 1²/(3 + 2²/(5 + 3²/(7 + …)))
|
|
78
|
+
* @yields {{a:number,b:number}} - Term pair (aₙ, bₙ) of the generalized continued fraction.
|
|
79
|
+
* - first: a₀ = 1
|
|
80
|
+
* - then: aₙ = 2n+1, bₙ = n² (n ≥ 1)
|
|
81
|
+
*/
|
|
82
|
+
"FOUR_OVER_PI": function* () {
|
|
83
|
+
|
|
84
|
+
yield { "a": 1, "b": 0 }; // a₀ = 1
|
|
85
|
+
|
|
86
|
+
for (let n = 0; true; n++) {
|
|
87
|
+
yield { "a": 2, "b": (n * 2 + 1) ** 2 };
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Infinite generator for Continued‐fraction terms of π:
|
|
93
|
+
* π = 3 + 1²/(6 + 3²/(6 + 5²/(6 + …)))
|
|
94
|
+
* @yields {{a:number,b:number}} - Term pair (aₙ, bₙ) of the generalized continued fraction.
|
|
95
|
+
* - first: a₀ = 3
|
|
96
|
+
* - then: aₙ = 6, bₙ = (2n-1)² (n ≥ 1)
|
|
97
|
+
*/
|
|
98
|
+
"PI": function* () {
|
|
99
|
+
|
|
100
|
+
yield { "a": 3, "b": 0 }; // a₀ = 3
|
|
101
|
+
|
|
102
|
+
for (let n = 1; true; n++) {
|
|
103
|
+
yield { "a": 6, "b": (n * 2 - 1) ** 2 };
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Infinite generator of e = [2; 1, 2, 1, 1, 4, 1, …].
|
|
109
|
+
* Terms follow the pattern [2; (1,2m,1) for m = 1,2,3,…].
|
|
110
|
+
*
|
|
111
|
+
* @yields {number} - Next continued-fraction term of e.
|
|
112
|
+
*/
|
|
113
|
+
"E": function* () {
|
|
114
|
+
|
|
115
|
+
yield 2; // a₀ = 2
|
|
116
|
+
|
|
117
|
+
for (let m = 1; ; m++) {
|
|
118
|
+
yield 1;
|
|
119
|
+
yield 2 * m;
|
|
120
|
+
yield 1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Alternative:
|
|
124
|
+
yield { a: 2, b: 0 }; // a₀ = 2
|
|
125
|
+
yield { a: 1, b: 1 }; // a₁ = 1
|
|
126
|
+
|
|
127
|
+
for (let m = 2; ; m++) {
|
|
128
|
+
yield { a: n, b: m - 1 };
|
|
129
|
+
}
|
|
130
|
+
*/
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Evaluate a (simple or generalized) continued fraction generator.
|
|
135
|
+
* For generalized: terms are objects { a, b }, else regular numbers.
|
|
136
|
+
*
|
|
137
|
+
* @param {Generator|Function} generator - Continued fraction term generator.
|
|
138
|
+
* @param {number} steps - Number of terms to evaluate.
|
|
139
|
+
* @returns {Fraction} - Rational approximation as Fraction.
|
|
140
|
+
*/
|
|
141
|
+
"eval": function (generator, steps = 10) {
|
|
142
|
+
|
|
143
|
+
if (typeof generator === "function") {
|
|
144
|
+
generator = generator();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// pull off a₀ (with its b₀)
|
|
148
|
+
const first = generator['next']();
|
|
149
|
+
if (first['done']) return Fraction(0);
|
|
150
|
+
|
|
151
|
+
const a0 = Fraction(first['value']['a'] ?? first['value']);
|
|
152
|
+
|
|
153
|
+
// initialize convergents p₋₁/q₋₁ = 1/0, p₀/q₀ = a₀/1
|
|
154
|
+
let pCurr = a0, qCurr = Fraction(1);
|
|
155
|
+
let pPrev = Fraction(1), qPrev = Fraction(0);
|
|
156
|
+
|
|
157
|
+
// run through a₁… up to `steps-1` more
|
|
158
|
+
for (let k = 1; k < steps; k++) {
|
|
159
|
+
const { value, done } = generator['next']();
|
|
160
|
+
if (done) break;
|
|
161
|
+
|
|
162
|
+
const ak = Fraction(value['a'] ?? value),
|
|
163
|
+
bk = Fraction(value['b'] ?? 1);
|
|
164
|
+
|
|
165
|
+
// pₖ = aₖ·pₖ₋₁ + bₖ·pₖ₋₂
|
|
166
|
+
// qₖ = aₖ·qₖ₋₁ + bₖ·qₖ₋₂
|
|
167
|
+
[pPrev, pCurr] = [pCurr, ak['mul'](pCurr)['add'](bk['mul'](pPrev))];
|
|
168
|
+
[qPrev, qCurr] = [qCurr, ak['mul'](qCurr)['add'](bk['mul'](qPrev))];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// final convergent = pCurr/qCurr
|
|
172
|
+
return pCurr['div'](qCurr);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
Object.defineProperty(ContinuedFraction, "__esModule", { 'value': true });
|
|
177
|
+
ContinuedFraction['default'] = ContinuedFraction;
|
|
178
|
+
ContinuedFraction['ContinuedFraction'] = ContinuedFraction;
|
|
179
|
+
module['exports'] = ContinuedFraction;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
ContinuedFraction.js v0.0.1 4/18/2025
|
|
3
|
+
https://github.com/rawify/ContinuedFraction.js
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2025, Robert Eisele (https://raw.org/)
|
|
6
|
+
Licensed under the MIT license.
|
|
7
|
+
*/
|
|
8
|
+
'use strict';(function(n){const e={sqrt:function*(a){const c=Math.floor(Math.sqrt(a));yield c;if(c*c!==a){var b=0,d=1,f=c;do b=f*d-b,d=(a-b*b)/d,f=Math.floor((c+b)/d),yield f;while(1)}},fromNumber:function*(a){yield*Fraction(a).toContinued()},fromFraction:function*(a,c){yield*Fraction(a,c).toContinued()},PHI:function*(){for(;;)yield 1},FOUR_OVER_PI:function*(){yield{a:1,b:0};for(let a=0;;a++)yield{a:2,b:(2*a+1)**2}},PI:function*(){yield{a:3,b:0};for(let a=1;;a++)yield{a:6,b:(2*a-1)**2}},E:function*(){yield 2;
|
|
9
|
+
for(let a=1;;a++)yield 1,yield 2*a,yield 1},eval:function(a,c=10){"function"===typeof a&&(a=a());var b=a.next();if(b.done)return Fraction(0);b=Fraction(b.value.a??b.value);let d=Fraction(1),f=Fraction(1),h=Fraction(0);for(let k=1;k<c;k++){const {value:g,done:p}=a.next();if(p)break;const l=Fraction(g.a??g),m=Fraction(g.b??1);[f,b]=[b,l.mul(b).add(m.mul(f))];[h,d]=[d,l.mul(d).add(m.mul(h))]}return b.div(d)}};"function"===typeof define&&define.amd?define([],function(){return e}):"object"===typeof exports?
|
|
10
|
+
(Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=e,e.ContinuedFraction=e,module.exports=e):n.ContinuedFraction=e})(this);
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
import Fraction from 'fraction.js';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Utility class for generating continued-fraction expansions of various constants.
|
|
8
|
+
*/
|
|
9
|
+
const ContinuedFraction = {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Infinite generator for the continued-fraction terms of sqrt(N).
|
|
13
|
+
* √N = [a0; (a1, a2, ..., a_p)], where the period ends when ak = 2*a0.
|
|
14
|
+
* For perfect squares, yields only a0 = floor(sqrt(N)) and then returns.
|
|
15
|
+
*
|
|
16
|
+
* @param {number} N - Integer whose square root CF expansion is desired (N ≥ 0).
|
|
17
|
+
* @yields {number} - Next continued-fraction term of √N.
|
|
18
|
+
*/
|
|
19
|
+
"sqrt": function* (N) {
|
|
20
|
+
|
|
21
|
+
const a0 = Math.floor(Math.sqrt(N));
|
|
22
|
+
yield a0;
|
|
23
|
+
if (a0 * a0 === N) return; // perfect square: single-term CF
|
|
24
|
+
|
|
25
|
+
//while (true) {
|
|
26
|
+
let nk = 0;
|
|
27
|
+
let dk = 1;
|
|
28
|
+
let ak = a0;
|
|
29
|
+
|
|
30
|
+
do {
|
|
31
|
+
nk = ak * dk - nk;
|
|
32
|
+
dk = (N - nk * nk) / dk; // remains integer by construction
|
|
33
|
+
ak = Math.floor((a0 + nk) / dk);
|
|
34
|
+
yield ak;
|
|
35
|
+
} while (/* 2 * a0 !== ak */ true);
|
|
36
|
+
//}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Generator for continued-fraction terms of any real number via Fraction.js.
|
|
41
|
+
*
|
|
42
|
+
* @exports
|
|
43
|
+
* @param {number|string|BigInt} n - The real number to convert (as number or string).
|
|
44
|
+
* @yields {number} - Next continued-fraction term of n.
|
|
45
|
+
*/
|
|
46
|
+
"fromNumber": function* (n) {
|
|
47
|
+
|
|
48
|
+
yield* Fraction(n)['toContinued']();
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Generator for continued-fraction terms of a rational a/b via Fraction.js.
|
|
53
|
+
*
|
|
54
|
+
* @param {number|string|BigInt|Fraction} a - Numerator.
|
|
55
|
+
* @param {number|string|BigInt} b - Denominator.
|
|
56
|
+
* @yields {number} - Next continued-fraction term of a/b.
|
|
57
|
+
*/
|
|
58
|
+
"fromFraction": function* (a, b) {
|
|
59
|
+
|
|
60
|
+
yield* Fraction(a, b)['toContinued']();
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Infinite generator of the golden ratio φ = [1; 1, 1, 1, …].
|
|
65
|
+
*
|
|
66
|
+
* @yields {number} - Always 1.
|
|
67
|
+
*/
|
|
68
|
+
"PHI": function* () {
|
|
69
|
+
|
|
70
|
+
while (true) {
|
|
71
|
+
yield 1;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Infinite generator for Continued‐fraction terms of 4/π:
|
|
77
|
+
* 4/π = 1 + 1²/(3 + 2²/(5 + 3²/(7 + …)))
|
|
78
|
+
* @yields {{a:number,b:number}} - Term pair (aₙ, bₙ) of the generalized continued fraction.
|
|
79
|
+
* - first: a₀ = 1
|
|
80
|
+
* - then: aₙ = 2n+1, bₙ = n² (n ≥ 1)
|
|
81
|
+
*/
|
|
82
|
+
"FOUR_OVER_PI": function* () {
|
|
83
|
+
|
|
84
|
+
yield { "a": 1, "b": 0 }; // a₀ = 1
|
|
85
|
+
|
|
86
|
+
for (let n = 0; true; n++) {
|
|
87
|
+
yield { "a": 2, "b": (n * 2 + 1) ** 2 };
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Infinite generator for Continued‐fraction terms of π:
|
|
93
|
+
* π = 3 + 1²/(6 + 3²/(6 + 5²/(6 + …)))
|
|
94
|
+
* @yields {{a:number,b:number}} - Term pair (aₙ, bₙ) of the generalized continued fraction.
|
|
95
|
+
* - first: a₀ = 3
|
|
96
|
+
* - then: aₙ = 6, bₙ = (2n-1)² (n ≥ 1)
|
|
97
|
+
*/
|
|
98
|
+
"PI": function* () {
|
|
99
|
+
|
|
100
|
+
yield { "a": 3, "b": 0 }; // a₀ = 3
|
|
101
|
+
|
|
102
|
+
for (let n = 1; true; n++) {
|
|
103
|
+
yield { "a": 6, "b": (n * 2 - 1) ** 2 };
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Infinite generator of e = [2; 1, 2, 1, 1, 4, 1, …].
|
|
109
|
+
* Terms follow the pattern [2; (1,2m,1) for m = 1,2,3,…].
|
|
110
|
+
*
|
|
111
|
+
* @yields {number} - Next continued-fraction term of e.
|
|
112
|
+
*/
|
|
113
|
+
"E": function* () {
|
|
114
|
+
|
|
115
|
+
yield 2; // a₀ = 2
|
|
116
|
+
|
|
117
|
+
for (let m = 1; ; m++) {
|
|
118
|
+
yield 1;
|
|
119
|
+
yield 2 * m;
|
|
120
|
+
yield 1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Alternative:
|
|
124
|
+
yield { a: 2, b: 0 }; // a₀ = 2
|
|
125
|
+
yield { a: 1, b: 1 }; // a₁ = 1
|
|
126
|
+
|
|
127
|
+
for (let m = 2; ; m++) {
|
|
128
|
+
yield { a: n, b: m - 1 };
|
|
129
|
+
}
|
|
130
|
+
*/
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Evaluate a (simple or generalized) continued fraction generator.
|
|
135
|
+
* For generalized: terms are objects { a, b }, else regular numbers.
|
|
136
|
+
*
|
|
137
|
+
* @param {Generator|Function} generator - Continued fraction term generator.
|
|
138
|
+
* @param {number} steps - Number of terms to evaluate.
|
|
139
|
+
* @returns {Fraction} - Rational approximation as Fraction.
|
|
140
|
+
*/
|
|
141
|
+
"eval": function (generator, steps = 10) {
|
|
142
|
+
|
|
143
|
+
if (typeof generator === "function") {
|
|
144
|
+
generator = generator();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// pull off a₀ (with its b₀)
|
|
148
|
+
const first = generator['next']();
|
|
149
|
+
if (first['done']) return Fraction(0);
|
|
150
|
+
|
|
151
|
+
const a0 = Fraction(first['value']['a'] ?? first['value']);
|
|
152
|
+
|
|
153
|
+
// initialize convergents p₋₁/q₋₁ = 1/0, p₀/q₀ = a₀/1
|
|
154
|
+
let pCurr = a0, qCurr = Fraction(1);
|
|
155
|
+
let pPrev = Fraction(1), qPrev = Fraction(0);
|
|
156
|
+
|
|
157
|
+
// run through a₁… up to `steps-1` more
|
|
158
|
+
for (let k = 1; k < steps; k++) {
|
|
159
|
+
const { value, done } = generator['next']();
|
|
160
|
+
if (done) break;
|
|
161
|
+
|
|
162
|
+
const ak = Fraction(value['a'] ?? value),
|
|
163
|
+
bk = Fraction(value['b'] ?? 1);
|
|
164
|
+
|
|
165
|
+
// pₖ = aₖ·pₖ₋₁ + bₖ·pₖ₋₂
|
|
166
|
+
// qₖ = aₖ·qₖ₋₁ + bₖ·qₖ₋₂
|
|
167
|
+
[pPrev, pCurr] = [pCurr, ak['mul'](pCurr)['add'](bk['mul'](pPrev))];
|
|
168
|
+
[qPrev, qCurr] = [qCurr, ak['mul'](qCurr)['add'](bk['mul'](qPrev))];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// final convergent = pCurr/qCurr
|
|
172
|
+
return pCurr['div'](qCurr);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
ContinuedFraction as default, ContinuedFraction
|
|
177
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "continuedfraction.js",
|
|
3
|
+
"title": "ContinuedFraction.js",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"homepage": "https://github.com/rawify/ContinuedFraction.js",
|
|
6
|
+
"bugs": "https://github.com/rawify/ContinuedFraction.js/issues",
|
|
7
|
+
"description": "The RAW continued fractions library",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"math",
|
|
10
|
+
"continued fraction",
|
|
11
|
+
"fraction",
|
|
12
|
+
"bigint"
|
|
13
|
+
],
|
|
14
|
+
"private": false,
|
|
15
|
+
"main": "./dist/continuedfraction.js",
|
|
16
|
+
"module": "./dist/continuedfraction.mjs",
|
|
17
|
+
"types": "./continuedfraction.d.ts",
|
|
18
|
+
"browser": "./dist/continuedfraction.min.js",
|
|
19
|
+
"unpkg": "./dist/continuedfraction.min.js",
|
|
20
|
+
"readmeFilename": "README.md",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./continuedfraction.d.ts",
|
|
24
|
+
"require": "./dist/continuedfraction.js",
|
|
25
|
+
"import": "./dist/continuedfraction.mjs"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git@github.com:rawify/ContinuedFraction.js.git"
|
|
31
|
+
},
|
|
32
|
+
"funding": {
|
|
33
|
+
"type": "github",
|
|
34
|
+
"url": "https://github.com/sponsors/rawify"
|
|
35
|
+
},
|
|
36
|
+
"author": {
|
|
37
|
+
"name": "Robert Eisele",
|
|
38
|
+
"email": "robert@raw.org",
|
|
39
|
+
"url": "https://raw.org/"
|
|
40
|
+
},
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": "*"
|
|
44
|
+
},
|
|
45
|
+
"directories": {
|
|
46
|
+
"test": "tests"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "crude-build ContinuedFraction",
|
|
50
|
+
"test": "mocha tests/*.js"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"crude-build": "^0.1.0",
|
|
54
|
+
"mocha": "^11.1.0"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"fraction.js": "^5.2.2"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license ContinuedFraction.js v0.0.1 4/18/2025
|
|
3
|
+
* https://github.com/rawify/ContinuedFraction.js
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2025, Robert Eisele (https://raw.org/)
|
|
6
|
+
* Licensed under the MIT license.
|
|
7
|
+
**/
|
|
8
|
+
|
|
9
|
+
import Fraction from 'fraction.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Utility class for generating continued-fraction expansions of various constants.
|
|
13
|
+
*/
|
|
14
|
+
const ContinuedFraction = {
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Infinite generator for the continued-fraction terms of sqrt(N).
|
|
18
|
+
* √N = [a0; (a1, a2, ..., a_p)], where the period ends when ak = 2*a0.
|
|
19
|
+
* For perfect squares, yields only a0 = floor(sqrt(N)) and then returns.
|
|
20
|
+
*
|
|
21
|
+
* @param {number} N - Integer whose square root CF expansion is desired (N ≥ 0).
|
|
22
|
+
* @yields {number} - Next continued-fraction term of √N.
|
|
23
|
+
*/
|
|
24
|
+
"sqrt": function* (N) {
|
|
25
|
+
|
|
26
|
+
const a0 = Math.floor(Math.sqrt(N));
|
|
27
|
+
yield a0;
|
|
28
|
+
if (a0 * a0 === N) return; // perfect square: single-term CF
|
|
29
|
+
|
|
30
|
+
//while (true) {
|
|
31
|
+
let nk = 0;
|
|
32
|
+
let dk = 1;
|
|
33
|
+
let ak = a0;
|
|
34
|
+
|
|
35
|
+
do {
|
|
36
|
+
nk = ak * dk - nk;
|
|
37
|
+
dk = (N - nk * nk) / dk; // remains integer by construction
|
|
38
|
+
ak = Math.floor((a0 + nk) / dk);
|
|
39
|
+
yield ak;
|
|
40
|
+
} while (/* 2 * a0 !== ak */ true);
|
|
41
|
+
//}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generator for continued-fraction terms of any real number via Fraction.js.
|
|
46
|
+
*
|
|
47
|
+
* @exports
|
|
48
|
+
* @param {number|string|BigInt} n - The real number to convert (as number or string).
|
|
49
|
+
* @yields {number} - Next continued-fraction term of n.
|
|
50
|
+
*/
|
|
51
|
+
"fromNumber": function* (n) {
|
|
52
|
+
|
|
53
|
+
yield* Fraction(n)['toContinued']();
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Generator for continued-fraction terms of a rational a/b via Fraction.js.
|
|
58
|
+
*
|
|
59
|
+
* @param {number|string|BigInt|Fraction} a - Numerator.
|
|
60
|
+
* @param {number|string|BigInt} b - Denominator.
|
|
61
|
+
* @yields {number} - Next continued-fraction term of a/b.
|
|
62
|
+
*/
|
|
63
|
+
"fromFraction": function* (a, b) {
|
|
64
|
+
|
|
65
|
+
yield* Fraction(a, b)['toContinued']();
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Infinite generator of the golden ratio φ = [1; 1, 1, 1, …].
|
|
70
|
+
*
|
|
71
|
+
* @yields {number} - Always 1.
|
|
72
|
+
*/
|
|
73
|
+
"PHI": function* () {
|
|
74
|
+
|
|
75
|
+
while (true) {
|
|
76
|
+
yield 1;
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Infinite generator for Continued‐fraction terms of 4/π:
|
|
82
|
+
* 4/π = 1 + 1²/(3 + 2²/(5 + 3²/(7 + …)))
|
|
83
|
+
* @yields {{a:number,b:number}} - Term pair (aₙ, bₙ) of the generalized continued fraction.
|
|
84
|
+
* - first: a₀ = 1
|
|
85
|
+
* - then: aₙ = 2n+1, bₙ = n² (n ≥ 1)
|
|
86
|
+
*/
|
|
87
|
+
"FOUR_OVER_PI": function* () {
|
|
88
|
+
|
|
89
|
+
yield { "a": 1, "b": 0 }; // a₀ = 1
|
|
90
|
+
|
|
91
|
+
for (let n = 0; true; n++) {
|
|
92
|
+
yield { "a": 2, "b": (n * 2 + 1) ** 2 };
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Infinite generator for Continued‐fraction terms of π:
|
|
98
|
+
* π = 3 + 1²/(6 + 3²/(6 + 5²/(6 + …)))
|
|
99
|
+
* @yields {{a:number,b:number}} - Term pair (aₙ, bₙ) of the generalized continued fraction.
|
|
100
|
+
* - first: a₀ = 3
|
|
101
|
+
* - then: aₙ = 6, bₙ = (2n-1)² (n ≥ 1)
|
|
102
|
+
*/
|
|
103
|
+
"PI": function* () {
|
|
104
|
+
|
|
105
|
+
yield { "a": 3, "b": 0 }; // a₀ = 3
|
|
106
|
+
|
|
107
|
+
for (let n = 1; true; n++) {
|
|
108
|
+
yield { "a": 6, "b": (n * 2 - 1) ** 2 };
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Infinite generator of e = [2; 1, 2, 1, 1, 4, 1, …].
|
|
114
|
+
* Terms follow the pattern [2; (1,2m,1) for m = 1,2,3,…].
|
|
115
|
+
*
|
|
116
|
+
* @yields {number} - Next continued-fraction term of e.
|
|
117
|
+
*/
|
|
118
|
+
"E": function* () {
|
|
119
|
+
|
|
120
|
+
yield 2; // a₀ = 2
|
|
121
|
+
|
|
122
|
+
for (let m = 1; ; m++) {
|
|
123
|
+
yield 1;
|
|
124
|
+
yield 2 * m;
|
|
125
|
+
yield 1;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* Alternative:
|
|
129
|
+
yield { a: 2, b: 0 }; // a₀ = 2
|
|
130
|
+
yield { a: 1, b: 1 }; // a₁ = 1
|
|
131
|
+
|
|
132
|
+
for (let m = 2; ; m++) {
|
|
133
|
+
yield { a: n, b: m - 1 };
|
|
134
|
+
}
|
|
135
|
+
*/
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Evaluate a (simple or generalized) continued fraction generator.
|
|
140
|
+
* For generalized: terms are objects { a, b }, else regular numbers.
|
|
141
|
+
*
|
|
142
|
+
* @param {Generator|Function} generator - Continued fraction term generator.
|
|
143
|
+
* @param {number} steps - Number of terms to evaluate.
|
|
144
|
+
* @returns {Fraction} - Rational approximation as Fraction.
|
|
145
|
+
*/
|
|
146
|
+
"eval": function (generator, steps = 10) {
|
|
147
|
+
|
|
148
|
+
if (typeof generator === "function") {
|
|
149
|
+
generator = generator();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// pull off a₀ (with its b₀)
|
|
153
|
+
const first = generator['next']();
|
|
154
|
+
if (first['done']) return Fraction(0);
|
|
155
|
+
|
|
156
|
+
const a0 = Fraction(first['value']['a'] ?? first['value']);
|
|
157
|
+
|
|
158
|
+
// initialize convergents p₋₁/q₋₁ = 1/0, p₀/q₀ = a₀/1
|
|
159
|
+
let pCurr = a0, qCurr = Fraction(1);
|
|
160
|
+
let pPrev = Fraction(1), qPrev = Fraction(0);
|
|
161
|
+
|
|
162
|
+
// run through a₁… up to `steps-1` more
|
|
163
|
+
for (let k = 1; k < steps; k++) {
|
|
164
|
+
const { value, done } = generator['next']();
|
|
165
|
+
if (done) break;
|
|
166
|
+
|
|
167
|
+
const ak = Fraction(value['a'] ?? value),
|
|
168
|
+
bk = Fraction(value['b'] ?? 1);
|
|
169
|
+
|
|
170
|
+
// pₖ = aₖ·pₖ₋₁ + bₖ·pₖ₋₂
|
|
171
|
+
// qₖ = aₖ·qₖ₋₁ + bₖ·qₖ₋₂
|
|
172
|
+
[pPrev, pCurr] = [pCurr, ak['mul'](pCurr)['add'](bk['mul'](pPrev))];
|
|
173
|
+
[qPrev, qCurr] = [qCurr, ak['mul'](qCurr)['add'](bk['mul'](qPrev))];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// final convergent = pCurr/qCurr
|
|
177
|
+
return pCurr['div'](qCurr);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
|
|
2
|
+
const ContinuedFraction = require("continuedfraction.js");
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
|
|
5
|
+
function get(gen, num = 10) {
|
|
6
|
+
|
|
7
|
+
const res = [];
|
|
8
|
+
for (let i = 0; i < num; i++) {
|
|
9
|
+
let x = gen.next();
|
|
10
|
+
if (x.done) break;
|
|
11
|
+
res.push(x.value);
|
|
12
|
+
}
|
|
13
|
+
return res;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const tests = [
|
|
17
|
+
|
|
18
|
+
{ label: "sqrt(2)", generator: ContinuedFraction.sqrt(2), expect: [1, 2, 2, 2, 2, 2, 2, 2, 2, 2] },
|
|
19
|
+
{ label: "sqrt(3)", generator: ContinuedFraction.sqrt(3), expect: [1, 1, 2, 1, 2, 1, 2, 1, 2, 1] },
|
|
20
|
+
{ label: "sqrt(5)", generator: ContinuedFraction.sqrt(5), expect: [2, 4, 4, 4, 4, 4, 4, 4, 4, 4] },
|
|
21
|
+
{ label: "sqrt(7)", generator: ContinuedFraction.sqrt(7), expect: [2, 1, 1, 1, 4, 1, 1, 1, 4, 1] },
|
|
22
|
+
|
|
23
|
+
{ label: "fromNumber(23.43)", generator: ContinuedFraction.fromNumber(23.43), expect: [23, 2, 3, 14] },
|
|
24
|
+
{ label: "fromNumber(77)", generator: ContinuedFraction.fromNumber(77), expect: [77] },
|
|
25
|
+
|
|
26
|
+
{ label: "PHI", generator: ContinuedFraction.PHI(), expect: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] },
|
|
27
|
+
{ label: "PI", generator: ContinuedFraction.PI(), expect: [{ a: 3, b: 0 }, { a: 6, b: 1 }, { a: 6, b: 9 }, { a: 6, b: 25 }, { a: 6, b: 49 }, { a: 6, b: 81 }, { a: 6, b: 121 },{ a: 6, b: 169 },{ a: 6, b: 225 },{ a: 6, b: 289 }] },
|
|
28
|
+
{ label: "FOUR_OVER_PI", generator: ContinuedFraction.FOUR_OVER_PI(), expect: [{ a: 1, b: 0 }, { a: 2, b: 1 }, { a: 2, b: 9 }, { a: 2, b: 25 }, { a: 2, b: 49 }, { a: 2, b: 81 }, { a: 2, b: 121 },{ a: 2, b: 169 },{ a: 2, b: 225 },{ a: 2, b: 289 }] },
|
|
29
|
+
{ label: "E", generator: ContinuedFraction.E(), expect: [2, 1, 2, 1, 1, 4, 1, 1, 6, 1] },
|
|
30
|
+
|
|
31
|
+
{ label: "eval(Fraction(271/13))", input: ContinuedFraction.eval(ContinuedFraction.fromFraction("271/13"), 10).toFraction(), expect: "271/13" },
|
|
32
|
+
{ label: "eval(PHI)", input: ContinuedFraction.eval(ContinuedFraction.PHI, 21).toFraction(), expect: "17711/10946" }
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
describe('Continued Fraction', function () {
|
|
36
|
+
|
|
37
|
+
for (var i = 0; i < tests.length; i++) {
|
|
38
|
+
|
|
39
|
+
(function (test) {
|
|
40
|
+
|
|
41
|
+
it(test.label, function () {
|
|
42
|
+
if (test.generator)
|
|
43
|
+
assert.deepEqual(get(test.generator, 10), test.expect);
|
|
44
|
+
else
|
|
45
|
+
assert.deepEqual(test.input, test.expect);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
})(tests[i]);
|
|
49
|
+
}
|
|
50
|
+
});
|