source: node_modules/fraction.js/README.md@ e4c61dd

Last change on this file since e4c61dd was 2058e5c, checked in by istevanoska <ilinastevanoska@…>, 6 months ago

Working / before login

  • Property mode set to 100644
File size: 16.4 KB
Line 
1# Fraction.js - ℚ in JavaScript
2
3[![NPM Package](https://img.shields.io/npm/v/fraction.js.svg?style=flat)](https://npmjs.org/package/fraction.js "View this project on npm")
4[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
5
6Do you find the limitations of floating-point arithmetic frustrating, especially when rational and irrational numbers like π or √2 are stored within the same finite precision? This can lead to avoidable inaccuracies such as:
7
8```javascript
91 / 98 * 98 // Results in 0.9999999999999999
10```
11
12For applications requiring higher precision or where working with fractions is preferable, consider incorporating *Fraction.js* into your project.
13
14The library effectively addresses precision issues, as demonstrated below:
15
16```javascript
17Fraction(1).div(98).mul(98) // Returns 1
18```
19
20*Fraction.js* uses a `BigInt` representation for both the numerator and denominator, ensuring minimal performance overhead while maximizing accuracy. Its design is optimized for precision, making it an ideal choice as a foundational library for other math tools, such as [Polynomial.js](https://github.com/rawify/Polynomial.js) and [Math.js](https://github.com/josdejong/mathjs).
21
22## Convert Decimal to Fraction
23
24One of the core features of *Fraction.js* is its ability to seamlessly convert decimal numbers into fractions.
25
26```javascript
27let x = new Fraction(1.88);
28let res = x.toFraction(true); // Returns "1 22/25" as a string
29```
30
31This is particularly useful when you need precise fraction representations instead of dealing with the limitations of floating-point arithmetic. What if you allow some error tolerance?
32
33```javascript
34let x = new Fraction(0.33333);
35let res = x.simplify(0.001) // Error < 0.001
36 .toFraction(); // Returns "1/3" as a string
37```
38
39## Precision
40
41As native `BigInt` support in JavaScript becomes more common, libraries like *Fraction.js* use it to handle calculations with higher precision. This improves the speed and accuracy of math operations with large numbers, providing a better solution for tasks that need more precision than floating-point numbers can offer.
42
43## Examples / Motivation
44
45A simple example of using *Fraction.js* might look like this:
46
47```javascript
48var f = new Fraction("9.4'31'"); // 9.4313131313131...
49f.mul([-4, 3]).mod("4.'8'"); // 4.88888888888888...
50```
51
52The result can then be displayed as:
53
54```javascript
55console.log(f.toFraction()); // -4154 / 1485
56```
57
58Additionally, you can access the internal attributes of the fraction, such as the sign (s), numerator (n), and denominator (d). Keep in mind that these values are stored as `BigInt`:
59
60```javascript
61Number(f.s) * Number(f.n) / Number(f.d) = -1 * 4154 / 1485 = -2.797306...
62```
63
64If you attempted to calculate this manually using floating-point arithmetic, you'd get something like:
65
66```javascript
67(9.4313131 * (-4 / 3)) % 4.888888 = -2.797308133...
68```
69
70While the result is reasonably close, it’s not as accurate as the fraction-based approach that *Fraction.js* provides, especially when dealing with repeating decimals or complex operations. This highlights the value of precision that the library brings.
71
72### Laplace Probability
73
74Here's a straightforward example of using *Fraction.js* to calculate probabilities. Let's determine the probability of rolling a specific outcome on a fair die:
75
76- **P({3})**: The probability of rolling a 3.
77- **P({1, 4})**: The probability of rolling either 1 or 4.
78- **P({2, 4, 6})**: The probability of rolling 2, 4, or 6.
79
80#### P({3}):
81
82```javascript
83var p = new Fraction([3].length, 6).toString(); // "0.1(6)"
84```
85
86#### P({1, 4}):
87
88```javascript
89var p = new Fraction([1, 4].length, 6).toString(); // "0.(3)"
90```
91
92#### P({2, 4, 6}):
93
94```javascript
95var p = new Fraction([2, 4, 6].length, 6).toString(); // "0.5"
96```
97
98### Convert degrees/minutes/seconds to precise rational representation:
99
10057+45/60+17/3600
101
102```javascript
103var deg = 57; // 57°
104var min = 45; // 45 Minutes
105var sec = 17; // 17 Seconds
106
107new Fraction(deg).add(min, 60).add(sec, 3600).toString() // -> 57.7547(2)
108```
109
110
111### Rational approximation of irrational numbers
112
113To approximate a number like *sqrt(5) - 2* with a numerator and denominator, you can reformat the equation as follows: *pow(n / d + 2, 2) = 5*.
114
115Then the following algorithm will generate the rational number besides the binary representation.
116
117```javascript
118var x = "/", s = "";
119
120var a = new Fraction(0),
121 b = new Fraction(1);
122for (var n = 0; n <= 10; n++) {
123
124 var c = a.add(b).div(2);
125
126 console.log(n + "\t" + a + "\t" + b + "\t" + c + "\t" + x);
127
128 if (c.add(2).pow(2).valueOf() < 5) {
129 a = c;
130 x = "1";
131 } else {
132 b = c;
133 x = "0";
134 }
135 s+= x;
136}
137console.log(s)
138```
139
140The result is
141
142```
143n a[n] b[n] c[n] x[n]
1440 0/1 1/1 1/2 /
1451 0/1 1/2 1/4 0
1462 0/1 1/4 1/8 0
1473 1/8 1/4 3/16 1
1484 3/16 1/4 7/32 1
1495 7/32 1/4 15/64 1
1506 15/64 1/4 31/128 1
1517 15/64 31/128 61/256 0
1528 15/64 61/256 121/512 0
1539 15/64 121/512 241/1024 0
15410 241/1024 121/512 483/2048 1
155```
156
157Thus the approximation after 11 iterations of the bisection method is *483 / 2048* and the binary representation is 0.00111100011 (see [WolframAlpha](http://www.wolframalpha.com/input/?i=sqrt%285%29-2+binary))
158
159I published another example on how to approximate PI with fraction.js on my [blog](https://raw.org/article/rational-numbers-in-javascript/) (Still not the best idea to approximate irrational numbers, but it illustrates the capabilities of Fraction.js perfectly).
160
161
162### Get the exact fractional part of a number
163
164```javascript
165var f = new Fraction("-6.(3416)");
166console.log(f.mod(1).abs().toFraction()); // = 3416/9999
167```
168
169### Mathematical correct modulo
170
171The behaviour on negative congruences is different to most modulo implementations in computer science. Even the *mod()* function of Fraction.js behaves in the typical way. To solve the problem of having the mathematical correct modulo with Fraction.js you could come up with this:
172
173```javascript
174var a = -1;
175var b = 10.99;
176
177console.log(new Fraction(a)
178 .mod(b)); // Not correct, usual Modulo
179
180console.log(new Fraction(a)
181 .mod(b).add(b).mod(b)); // Correct! Mathematical Modulo
182```
183
184fmod() imprecision circumvented
185---
186It turns out that Fraction.js outperforms almost any fmod() implementation, including JavaScript itself, [php.js](http://phpjs.org/functions/fmod/), C++, Python, Java and even Wolframalpha due to the fact that numbers like 0.05, 0.1, ... are infinite decimal in base 2.
187
188The equation *fmod(4.55, 0.05)* gives *0.04999999999999957*, wolframalpha says *1/20*. The correct answer should be **zero**, as 0.05 divides 4.55 without any remainder.
189
190
191## Parser
192
193Any function (see below) as well as the constructor of the *Fraction* class parses its input and reduce it to the smallest term.
194
195You can pass either Arrays, Objects, Integers, Doubles or Strings.
196
197### Arrays / Objects
198
199```javascript
200new Fraction(numerator, denominator);
201new Fraction([numerator, denominator]);
202new Fraction({n: numerator, d: denominator});
203```
204
205### Integers
206
207```javascript
208new Fraction(123);
209```
210
211### Doubles
212
213```javascript
214new Fraction(55.4);
215```
216
217**Note:** If you pass a double as it is, Fraction.js will perform a number analysis based on Farey Sequences. If you concern performance, cache Fraction.js objects and pass arrays/objects.
218
219The method is really precise, but too large exact numbers, like 1234567.9991829 will result in a wrong approximation. If you want to keep the number as it is, convert it to a string, as the string parser will not perform any further observations. If you have problems with the approximation, in the file `examples/approx.js` is a different approximation algorithm, which might work better in some more specific use-cases.
220
221
222### Strings
223
224```javascript
225new Fraction("123.45");
226new Fraction("123/45"); // A rational number represented as two decimals, separated by a slash
227new Fraction("123:45"); // A rational number represented as two decimals, separated by a colon
228new Fraction("4 123/45"); // A rational number represented as a whole number and a fraction
229new Fraction("123.'456'"); // Note the quotes, see below!
230new Fraction("123.(456)"); // Note the brackets, see below!
231new Fraction("123.45'6'"); // Note the quotes, see below!
232new Fraction("123.45(6)"); // Note the brackets, see below!
233```
234
235### Two arguments
236
237```javascript
238new Fraction(3, 2); // 3/2 = 1.5
239```
240
241### Repeating decimal places
242
243*Fraction.js* can easily handle repeating decimal places. For example *1/3* is *0.3333...*. There is only one repeating digit. As you can see in the examples above, you can pass a number like *1/3* as "0.'3'" or "0.(3)", which are synonym. There are no tests to parse something like 0.166666666 to 1/6! If you really want to handle this number, wrap around brackets on your own with the function below for example: 0.1(66666666)
244
245Assume you want to divide 123.32 / 33.6(567). [WolframAlpha](http://www.wolframalpha.com/input/?i=123.32+%2F+%2812453%2F370%29) states that you'll get a period of 1776 digits. *Fraction.js* comes to the same result. Give it a try:
246
247```javascript
248var f = new Fraction("123.32");
249console.log("Bam: " + f.div("33.6(567)"));
250```
251
252To automatically make a number like "0.123123123" to something more Fraction.js friendly like "0.(123)", I hacked this little brute force algorithm in a 10 minutes. Improvements are welcome...
253
254```javascript
255function formatDecimal(str) {
256
257 var comma, pre, offset, pad, times, repeat;
258
259 if (-1 === (comma = str.indexOf(".")))
260 return str;
261
262 pre = str.substr(0, comma + 1);
263 str = str.substr(comma + 1);
264
265 for (var i = 0; i < str.length; i++) {
266
267 offset = str.substr(0, i);
268
269 for (var j = 0; j < 5; j++) {
270
271 pad = str.substr(i, j + 1);
272
273 times = Math.ceil((str.length - offset.length) / pad.length);
274
275 repeat = new Array(times + 1).join(pad); // Silly String.repeat hack
276
277 if (0 === (offset + repeat).indexOf(str)) {
278 return pre + offset + "(" + pad + ")";
279 }
280 }
281 }
282 return null;
283}
284
285var f, x = formatDecimal("13.0123123123"); // = 13.0(123)
286if (x !== null) {
287 f = new Fraction(x);
288}
289```
290
291## Attributes
292
293
294The Fraction object allows direct access to the numerator, denominator and sign attributes. It is ensured that only the sign-attribute holds sign information so that a sign comparison is only necessary against this attribute.
295
296```javascript
297var f = new Fraction('-1/2');
298console.log(f.n); // Numerator: 1
299console.log(f.d); // Denominator: 2
300console.log(f.s); // Sign: -1
301```
302
303
304## Functions
305
306### Fraction abs()
307
308Returns the actual number without any sign information
309
310### Fraction neg()
311
312Returns the actual number with flipped sign in order to get the additive inverse
313
314### Fraction add(n)
315
316Returns the sum of the actual number and the parameter n
317
318### Fraction sub(n)
319
320Returns the difference of the actual number and the parameter n
321
322### Fraction mul(n)
323
324Returns the product of the actual number and the parameter n
325
326### Fraction div(n)
327
328Returns the quotient of the actual number and the parameter n
329
330### Fraction pow(exp)
331
332Returns the power of the actual number, raised to an possible rational exponent. If the result becomes non-rational the function returns `null`.
333
334### Fraction log(base)
335
336Returns the logarithm of the actual number to a given rational base. If the result becomes non-rational the function returns `null`.
337
338### Fraction mod(n)
339
340Returns the modulus (rest of the division) of the actual object and n (this % n). It's a much more precise [fmod()](#fmod-impreciseness-circumvented) if you like. Please note that *mod()* is just like the modulo operator of most programming languages. If you want a mathematical correct modulo, see [here](#mathematical-correct-modulo).
341
342### Fraction mod()
343
344Returns the modulus (rest of the division) of the actual object (numerator mod denominator)
345
346### Fraction gcd(n)
347
348Returns the fractional greatest common divisor
349
350### Fraction lcm(n)
351
352Returns the fractional least common multiple
353
354### Fraction ceil([places=0-16])
355
356Returns the ceiling of a rational number with Math.ceil
357
358### Fraction floor([places=0-16])
359
360Returns the floor of a rational number with Math.floor
361
362### Fraction round([places=0-16])
363
364Returns the rational number rounded with Math.round
365
366### Fraction roundTo(multiple)
367
368Rounds a fraction to the closest multiple of another fraction.
369
370### Fraction inverse()
371
372Returns the multiplicative inverse of the actual number (n / d becomes d / n) in order to get the reciprocal
373
374### Fraction simplify([eps=0.001])
375
376Simplifies the rational number under a certain error threshold. Ex. `0.333` will be `1/3` with `eps=0.001`
377
378### boolean equals(n)
379
380Check if two rational numbers are equal
381
382### boolean lt(n)
383
384Check if this rational number is less than another
385
386### boolean lte(n)
387
388Check if this rational number is less than or equal another
389
390### boolean gt(n)
391
392Check if this rational number is greater than another
393
394### boolean gte(n)
395
396Check if this rational number is greater than or equal another
397
398### int compare(n)
399
400Compare two numbers.
401```
402result < 0: n is greater than actual number
403result > 0: n is smaller than actual number
404result = 0: n is equal to the actual number
405```
406
407### boolean divisible(n)
408
409Check if two numbers are divisible (n divides this)
410
411### double valueOf()
412
413Returns a decimal representation of the fraction
414
415### String toString([decimalPlaces=15])
416
417Generates an exact string representation of the given object. For repeating decimal places, digits within repeating cycles are enclosed in parentheses, e.g., `1/3 = "0.(3)"`. For other numbers, the string will include up to the specified `decimalPlaces` significant digits, including any trailing zeros if truncation occurs. For example, `1/2` will be represented as `"0.5"`, without additional trailing zeros.
418
419**Note:** Since both `valueOf()` and `toString()` are provided, `toString()` will only be invoked implicitly when the object is used in a string context. For instance, when using the plus operator like `"123" + new Fraction`, `valueOf()` will be called first, as JavaScript attempts to combine primitives before concatenating them, with the string type taking precedence. However, `alert(new Fraction)` or `String(new Fraction)` will behave as expected. To ensure specific behavior, explicitly call either `toString()` or `valueOf()`.
420
421### String toLatex(showMixed=false)
422
423Generates an exact LaTeX representation of the actual object. You can see a [live demo](https://raw.org/article/rational-numbers-in-javascript/) on my blog.
424
425The optional boolean parameter indicates if you want to show the a mixed fraction. "1 1/3" instead of "4/3"
426
427### String toFraction(showMixed=false)
428
429Gets a string representation of the fraction
430
431The optional boolean parameter indicates if you want to showa mixed fraction. "1 1/3" instead of "4/3"
432
433### Array toContinued()
434
435Gets an array of the fraction represented as a continued fraction. The first element always contains the whole part.
436
437```javascript
438var f = new Fraction('88/33');
439var c = f.toContinued(); // [2, 1, 2]
440```
441
442### Fraction clone()
443
444Creates a copy of the actual Fraction object
445
446
447## Exceptions
448
449If a really hard error occurs (parsing error, division by zero), *Fraction.js* throws exceptions! Please make sure you handle them correctly.
450
451
452## Installation
453
454You can install `Fraction.js` via npm:
455
456```bash
457npm install fraction.js
458```
459
460Or with yarn:
461
462```bash
463yarn add fraction.js
464```
465
466Alternatively, download or clone the repository:
467
468```bash
469git clone https://github.com/rawify/Fraction.js
470```
471
472## Usage
473
474Include the `fraction.min.js` file in your project:
475
476```html
477<script src="path/to/fraction.min.js"></script>
478<script>
479 var x = new Fraction("13/4");
480</script>
481```
482
483Or in a Node.js project:
484
485```javascript
486const Fraction = require('fraction.js');
487```
488
489or
490
491```javascript
492import Fraction from 'fraction.js';
493```
494
495
496## Coding Style
497
498As every library I publish, Fraction.js 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.
499
500## Building the library
501
502After cloning the Git repository run:
503
504```bash
505npm install
506npm run build
507```
508
509## Run a test
510
511Testing the source against the shipped test suite is as easy as
512
513```bash
514npm run test
515```
516
517## Copyright and Licensing
518
519Copyright (c) 2025, [Robert Eisele](https://raw.org/)
520Licensed under the MIT license.
Note: See TracBrowser for help on using the repository browser.