continuedfraction.js 0.0.1 → 0.1.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Robert Eisele
3
+ Copyright (c) 2026 Robert Eisele
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -4,7 +4,9 @@
4
4
  [![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
5
5
 
6
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.
7
+ ContinuedFraction.js is published as [`continuedfraction.js`](https://www.npmjs.com/package/continuedfraction.js). It generates simple and generalized continued fractions and evaluates a bounded number of terms to an exact [Fraction.js](https://github.com/rawify/Fraction.js) convergent.
8
+
9
+ Use it to inspect continued-fraction terms or construct rational approximations of square roots, real values, rational values, φ, e, π, and 4/π. Use Fraction.js directly when the input is already rational and no term sequence is needed. It is not an arbitrary-precision transcendental-function package: each result is a rational convergent chosen by the requested term count.
8
10
 
9
11
  ## Features
10
12
 
@@ -12,15 +14,19 @@ A lightweight JavaScript library sitting on the shoulders of [Fraction.js](https
12
14
  - Convert any real number or rational to its continued‑fraction
13
15
  - Infinite generators for classic constants: φ (golden ratio), e, π, 4/π
14
16
  - Evaluate (simple or generalized) continued fractions to a `Fraction`
17
+ - Enumerate exact convergents or collect a bounded number of terms
18
+ - Strict TypeScript types for terms, sources, and coefficients
15
19
 
16
- ## Example
20
+ ## Quick example
21
+
22
+ ```javascript
23
+ import ContinuedFraction from 'continuedfraction.js';
17
24
 
18
- ```js
19
25
  const frac = ContinuedFraction.eval(
20
26
  ContinuedFraction.fromFraction(3021, 203),
21
- 10 // Max Steps
27
+ 10
22
28
  );
23
- console.log(frac.toString()); // "3021/203"
29
+ console.log(frac.toFraction()); // "3021/203"
24
30
  ```
25
31
 
26
32
  ## Installation
@@ -43,27 +49,115 @@ Alternatively, download or clone the repository:
43
49
  git clone https://github.com/rawify/ContinuedFraction.js
44
50
  ```
45
51
 
46
- ## Usage
52
+ ## Usage and runtime
53
+
54
+ `ContinuedFraction` is a static class and cannot be instantiated. Use its methods directly.
55
+
56
+ ### CommonJS
57
+
58
+ ```javascript
59
+ const ContinuedFraction = require('continuedfraction.js');
60
+ const terms = ContinuedFraction.toArray(ContinuedFraction.sqrt(2), 8);
61
+ ```
62
+
63
+ ### ES modules
64
+
65
+ ```javascript
66
+ import ContinuedFraction, { ContinuedFraction as NamedContinuedFraction } from 'continuedfraction.js';
67
+ const terms = ContinuedFraction.toArray(ContinuedFraction.sqrt(2), 8);
68
+ ```
47
69
 
48
- Include the `continuedfraction.min.js` file in your project:
70
+ ### Standalone browser script
49
71
 
50
72
  ```html
51
- <script src="path/to/continuedfraction.min.js"></script>
73
+ <script src="https://cdn.jsdelivr.net/npm/continuedfraction.js@0.1.0/dist/continuedfraction.min.js"></script>
52
74
  <script>
53
- var x = ContinuedFraction.sqrt(2);
75
+ const terms = ContinuedFraction.toArray(ContinuedFraction.sqrt(2), 8);
54
76
  </script>
55
77
  ```
56
78
 
57
- Or in a Node.js project:
79
+ ### Native browser module
80
+
81
+ ```html
82
+ <script type="module">
83
+ import ContinuedFraction from 'https://cdn.jsdelivr.net/npm/continuedfraction.js@0.1.0/dist/continuedfraction.mjs';
84
+ const terms = ContinuedFraction.toArray(ContinuedFraction.sqrt(2), 8);
85
+ </script>
86
+ ```
87
+
88
+ The package supports Node.js 20 or newer. Its CommonJS build uses the declared Fraction.js dependency; the ESM and standalone browser builds are self-contained. CommonJS also exposes `.default` and `.ContinuedFraction` aliases for compatibility.
89
+
90
+ ## Recipes
91
+
92
+ ### Approximate an irrational square root
93
+
94
+ `sqrt()` generates the periodic simple continued fraction; `eval()` consumes at most the requested number of terms.
58
95
 
59
96
  ```javascript
60
- const ContinuedFraction = require('continuedfraction.js');
97
+ import ContinuedFraction from 'continuedfraction.js';
98
+
99
+ const approximation = ContinuedFraction.eval(
100
+ ContinuedFraction.sqrt(2),
101
+ 8
102
+ );
103
+
104
+ console.log(approximation.toFraction()); // "577/408"
105
+ console.log(approximation.valueOf()); // 1.4142156862745099
106
+ ```
107
+
108
+ `sqrt(N)` expects a non-negative safe integer and throws `RangeError` otherwise. Perfect squares terminate after one term; non-squares produce an infinite generator.
109
+
110
+ ### Inspect and reconstruct a rational value
111
+
112
+ Rational expansions terminate. Fraction.js represents their terms as `BigInt`, so convert them before JSON serialization when the values are known to fit safely in `Number`.
113
+
114
+ ```javascript
115
+ import ContinuedFraction from 'continuedfraction.js';
116
+
117
+ const terms = [...ContinuedFraction.fromFraction(415, 93)];
118
+ const restored = ContinuedFraction.eval(
119
+ ContinuedFraction.fromFraction(415, 93),
120
+ 10
121
+ );
122
+
123
+ console.log(terms.map(Number)); // [4, 2, 6, 7]
124
+ console.log(restored.toFraction()); // "415/93"
125
+ ```
126
+
127
+ Do not convert large `BigInt` terms to `Number` unless they are within the safe-integer range.
128
+
129
+ ### Build convergents for e and a perfect square
130
+
131
+ Generator functions can be passed directly to `eval()`. This creates a new generator for each evaluation.
132
+
133
+ ```javascript
134
+ import ContinuedFraction from 'continuedfraction.js';
135
+
136
+ const e = ContinuedFraction.eval(ContinuedFraction.E, 10);
137
+ const squareTerms = [...ContinuedFraction.sqrt(49)];
138
+
139
+ console.log(e.toFraction()); // "1457/536"
140
+ console.log(squareTerms.map(Number)); // [7]
61
141
  ```
62
142
 
63
- or
143
+ Always bound iteration over `E()`, `PHI()`, `PI()`, `FOUR_OVER_PI()`, or a non-square `sqrt()` generator. Spreading an infinite generator never completes.
144
+
145
+ ### Inspect every convergent
146
+
147
+ `convergents()` yields exact Fraction.js values lazily. `fromTerms()` turns an existing sequence into a generator, while `toArray()` safely collects a bounded prefix.
64
148
 
65
149
  ```javascript
66
150
  import ContinuedFraction from 'continuedfraction.js';
151
+
152
+ const convergents = ContinuedFraction.toArray(
153
+ ContinuedFraction.convergents(
154
+ ContinuedFraction.fromTerms([1, 2, 2, 2])
155
+ ),
156
+ 4
157
+ );
158
+
159
+ console.log(convergents.map((value) => value.toFraction()));
160
+ // ["1", "3/2", "7/5", "17/12"]
67
161
  ```
68
162
 
69
163
  ## ContinuedFraction API
@@ -75,30 +169,40 @@ Import the static utility class and use its generators and evaluator:
75
169
  const sqrtGen = ContinuedFraction.sqrt(23);
76
170
  console.log(sqrtGen.next().value); // 4
77
171
  console.log(sqrtGen.next().value); // 1, 3, 1, 8, …
172
+ ```
78
173
 
174
+ ```javascript
79
175
  // 2) Continued‑fraction of a decimal
80
176
  let cnt = 0;
81
177
  for (let piCf of ContinuedFraction.fromNumber(Math.PI)) {
82
178
  console.log(piCf);
83
179
  if (cnt++ >= 10) break;
84
180
  }
181
+ ```
85
182
 
183
+ ```javascript
86
184
  // 3) Golden ratio φ terms
87
185
  const phiGen = ContinuedFraction.PHI();
88
186
  console.log(phiGen.next().value); // 1, and forever 1…
187
+ ```
89
188
 
189
+ ```javascript
90
190
  // 4) Evaluate the first 10 terms of e’s CF to a Fraction
91
191
  const approxE = ContinuedFraction.eval(ContinuedFraction.E, 10);
92
- console.log(approxE.toString()); // e ≈ “193/71”
192
+ console.log(approxE.toFraction()); // "1457/536"
193
+ ```
93
194
 
195
+ ```javascript
94
196
  // 5) Generalized CF for π, 4/π
95
197
  const genPi = ContinuedFraction.PI();
96
198
  console.log(genPi.next().value); // { a: 3, b: 0 }
97
199
  console.log(genPi.next().value); // { a: 6, b: 1 }
200
+ ```
98
201
 
202
+ ```javascript
99
203
  // 6) Continued‑fraction from two integers
100
204
  const halfCf = ContinuedFraction.fromFraction(1, 2);
101
- console.log([...halfCf]); // [0, 2]
205
+ console.log([...halfCf]); // [0n, 2n]
102
206
  ```
103
207
 
104
208
  ### Methods
@@ -106,28 +210,35 @@ console.log([...halfCf]); // [0, 2]
106
210
  | Method | Signature | Description |
107
211
  | ------------------------ | ----------------------------------------------------------------- | ----------------------------------------------------------------------- |
108
212
  | `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 |
213
+ | `fromNumber(n)` | `Generator<bigint>` | CF terms of any real via Fraction.js |
214
+ | `fromFraction(a, b?)` | `Generator<bigint>` | CF terms of a rational value or a/b |
215
+ | `fromTerms(terms)` | `Generator<Term>` | Yield an existing finite or infinite term sequence |
111
216
  | `PHI()` | `Generator<number>` | Infinite 1’s for the golden ratio |
112
217
  | `FOUR_OVER_PI()` | `Generator<CFTerm>` | Generalized CF terms for 4/π |
113
218
  | `PI()` | `Generator<CFTerm>` | Generalized CF terms for π |
114
219
  | `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.
220
+ | `toArray(source, steps)` | `Term[]` | Collect at most `steps` terms; the default is `10` |
221
+ | `convergents(source)` | `Generator<Fraction>` | Yield every exact convergent lazily |
222
+ | `eval(source, steps)` | `Fraction` | Evaluate up to `steps` terms; the default is `10` |
120
223
 
121
224
  ## Building the library
122
225
 
123
- After cloning the Git repository run:
226
+ The source is strict TypeScript. The build emits CommonJS, ESM, a standalone browser bundle, source maps, and format-specific declarations.
124
227
 
125
- ```
228
+ After cloning the Git repository, run:
229
+
230
+ ```bash
126
231
  npm install
127
232
  npm run build
128
233
  ```
129
234
 
235
+ Run all runtime and type-level tests with:
236
+
237
+ ```bash
238
+ npm test
239
+ ```
240
+
130
241
  ## Copyright and Licensing
131
242
 
132
- Copyright (c) 2025, [Robert Eisele](https://raw.org/)
243
+ Copyright (c) 2026, [Robert Eisele](https://raw.org/)
133
244
  Licensed under the MIT license.
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @license ContinuedFraction.js v0.1.0
3
+ * https://github.com/rawify/ContinuedFraction.js
4
+ *
5
+ * Copyright (c) 2026, Robert Eisele (https://raw.org/)
6
+ * Licensed under the MIT license.
7
+ **/
8
+ import { type Fraction as FractionValue } from 'fraction.js';
9
+ /** A value accepted by Fraction.js as a continued-fraction coefficient. */
10
+ export type Coefficient = number | string | bigint | FractionValue;
11
+ /** A term of a generalized continued fraction. */
12
+ export interface CFTerm {
13
+ /** The a_n coefficient. */
14
+ a: Coefficient;
15
+ /** The b_n coefficient. */
16
+ b: Coefficient;
17
+ }
18
+ /** A simple or generalized continued-fraction term. */
19
+ export type ContinuedFractionTerm = Coefficient | CFTerm;
20
+ /** A term iterator or a function that creates one. */
21
+ export type ContinuedFractionSource<T = ContinuedFractionTerm> = Iterator<T> | (() => Iterator<T>);
22
+ /**
23
+ * Utility class for generating and evaluating continued fractions.
24
+ * All methods are static; the class cannot be instantiated.
25
+ */
26
+ export declare class ContinuedFraction {
27
+ private constructor();
28
+ /**
29
+ * Infinite generator for the continued-fraction terms of sqrt(N).
30
+ * sqrt(N) = [a0; (a1, a2, ..., a_p)], with a period boundary at ak = 2*a0.
31
+ * For perfect squares, yields only a0 = floor(sqrt(N)) and then returns.
32
+ *
33
+ * @param N Integer whose square-root CF expansion is desired (N >= 0).
34
+ * @yields Next continued-fraction term of sqrt(N).
35
+ */
36
+ static sqrt(N: number): Generator<number, void, unknown>;
37
+ /**
38
+ * Generator for continued-fraction terms of any real number via Fraction.js.
39
+ *
40
+ * @param n The real number to convert (as number, string, or bigint).
41
+ * @yields Next continued-fraction term of n.
42
+ */
43
+ static fromNumber(n: Coefficient): Generator<bigint, void, unknown>;
44
+ /**
45
+ * Generator for continued-fraction terms of a rational a/b via Fraction.js.
46
+ *
47
+ * @param a Numerator, Fraction, or complete fraction string.
48
+ * @param b Optional denominator.
49
+ * @yields Next continued-fraction term of a/b.
50
+ */
51
+ static fromFraction(a: Coefficient, b?: Coefficient): Generator<bigint, void, unknown>;
52
+ /**
53
+ * Yields a finite sequence of simple or generalized terms unchanged.
54
+ *
55
+ * @param terms Continued-fraction terms.
56
+ * @yields Each supplied term in order.
57
+ */
58
+ static fromTerms<T extends ContinuedFractionTerm>(terms: Iterable<T>): Generator<T, void, unknown>;
59
+ /**
60
+ * Infinite generator of the golden ratio phi = [1; 1, 1, 1, ...].
61
+ *
62
+ * @yields Always 1.
63
+ */
64
+ static PHI(): Generator<number, never, unknown>;
65
+ /**
66
+ * Infinite generator for Brouncker's generalized continued fraction of 4/pi:
67
+ * 4/pi = 1 + 1^2/(2 + 3^2/(2 + 5^2/(2 + ...)))
68
+ *
69
+ * @yields Term pair (a_n, b_n) of the generalized continued fraction.
70
+ * - first: a_0 = 1
71
+ * - then: a_n = 2, b_n = (2n-1)^2 (n >= 1)
72
+ */
73
+ static FOUR_OVER_PI(): Generator<CFTerm, never, unknown>;
74
+ /**
75
+ * Infinite generator for a generalized continued fraction of pi:
76
+ * pi = 3 + 1^2/(6 + 3^2/(6 + 5^2/(6 + ...)))
77
+ *
78
+ * @yields Term pair (a_n, b_n) of the generalized continued fraction.
79
+ * - first: a_0 = 3
80
+ * - then: a_n = 6, b_n = (2n-1)^2 (n >= 1)
81
+ */
82
+ static PI(): Generator<CFTerm, never, unknown>;
83
+ /**
84
+ * Infinite generator of e = [2; 1, 2, 1, 1, 4, 1, ...].
85
+ * Terms follow the pattern [2; (1, 2m, 1) for m = 1, 2, 3, ...].
86
+ *
87
+ * @yields Next continued-fraction term of e.
88
+ */
89
+ static E(): Generator<number, never, unknown>;
90
+ /**
91
+ * Collects at most `steps` terms from a continued fraction.
92
+ *
93
+ * @param source Continued-fraction term iterator or a function returning one.
94
+ * @param steps Maximum number of terms to collect.
95
+ * @returns Collected terms in source order.
96
+ */
97
+ static toArray<T>(source: ContinuedFractionSource<T>, steps?: number): T[];
98
+ /**
99
+ * Generates every convergent of a simple or generalized continued fraction.
100
+ *
101
+ * @param source Continued-fraction term iterator or a function returning one.
102
+ * @yields Exact convergents as Fraction instances.
103
+ */
104
+ static convergents(source: ContinuedFractionSource): Generator<FractionValue, void, unknown>;
105
+ /**
106
+ * Evaluates a simple or generalized continued fraction generator.
107
+ * For generalized fractions terms are objects `{ a, b }`; otherwise they are coefficients.
108
+ *
109
+ * @param source Continued-fraction term iterator or a function returning one.
110
+ * @param steps Number of terms to evaluate.
111
+ * @returns Rational approximation as Fraction.
112
+ */
113
+ static eval(source: ContinuedFractionSource, steps?: number): FractionValue;
114
+ }
115
+ export default ContinuedFraction;
@@ -0,0 +1,16 @@
1
+ import type { CFTerm as CFTermType, Coefficient as CoefficientType, ContinuedFraction as ContinuedFractionType, ContinuedFractionSource as ContinuedFractionSourceType, ContinuedFractionTerm as ContinuedFractionTermType } from './continuedfraction.d.mts';
2
+
3
+ declare const ContinuedFraction: typeof ContinuedFractionType & {
4
+ readonly default: typeof ContinuedFractionType;
5
+ readonly ContinuedFraction: typeof ContinuedFractionType;
6
+ };
7
+
8
+ declare namespace ContinuedFraction {
9
+ type CFTerm = CFTermType;
10
+ type Coefficient = CoefficientType;
11
+ type ContinuedFraction = ContinuedFractionType;
12
+ type ContinuedFractionSource<T = ContinuedFractionTermType> = ContinuedFractionSourceType<T>;
13
+ type ContinuedFractionTerm = ContinuedFractionTermType;
14
+ }
15
+
16
+ export = ContinuedFraction;