Skip to content

Commit 1adcc76

Browse files
committed
Release v5.0
1 parent f9ccdb0 commit 1adcc76

24 files changed

+3250
-3055
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
.DS_Store
22
node_modules
3-
package-lock.json

.travis.yml

Lines changed: 0 additions & 4 deletions
This file was deleted.

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2023 Robert Eisele
3+
Copyright (c) 2025 Robert Eisele
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 111 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,86 +4,108 @@
44
[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
55

66

7-
Tired of inprecise numbers represented by doubles, which have to store rational and irrational numbers like PI or sqrt(2) the same way? Obviously the following problem is preventable:
7+
Are you frustrated by the imprecision of floating-point numbers like doubles, which store both rational and irrational numbers such as π or √2 in the same limited way? This often leads to preventable issues like:
88

99
```javascript
1010
1 / 98 * 98 // = 0.9999999999999999
1111
```
1212

13-
If you need more precision or just want a fraction as a result, just include *Fraction.js*:
13+
If you require greater precision or prefer to work with fractions instead of decimals, you can easily integrate *Fraction.js* into your project:
1414

1515
```javascript
16-
var Fraction = require('fraction.js');
17-
// or
1816
import Fraction from 'fraction.js';
17+
// or
18+
var Fraction = require('fraction.js');
1919
```
2020

21-
and give it a trial:
21+
Here’s an example of how it resolves the issue:
2222

2323
```javascript
2424
Fraction(1).div(98).mul(98) // = 1
2525
```
2626

27-
Internally, numbers are represented as *numerator / denominator*, which adds just a little overhead. However, the library is written with performance and accuracy in mind, which makes it the perfect basis for [Polynomial.js](https://github.com/infusion/Polynomial.js) and [Math.js](https://github.com/josdejong/mathjs).
27+
Internally, *Fraction.js* represents numbers as *numerator/denominator*, adding only minimal overhead. The library is optimized for both performance and precision, making it an excellent foundation for other libs like [Polynomial.js](https://github.com/infusion/Polynomial.js) and [Math.js](https://github.com/josdejong/mathjs).
28+
29+
## Convert Decimal to Fraction
30+
31+
One of the core functionalities of *Fraction.js* is its ability to convert decimals into fractions with ease:
2832

29-
Convert decimal to fraction
30-
===
31-
The simplest job for fraction.js is to get a fraction out of a decimal:
3233
```javascript
33-
var x = new Fraction(1.88);
34-
var res = x.toFraction(true); // String "1 22/25"
34+
let x = new Fraction(1.88);
35+
let res = x.toFraction(true); // Returns "1 22/25" as a string
3536
```
3637

37-
Examples / Motivation
38-
===
39-
A simple example might be
38+
This 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?
39+
40+
```javascript
41+
let x = new Fraction(0.33333);
42+
let res = x.simplify(0.001) // Error < 0.001
43+
.toFraction(); // Returns "1/3" as a string
44+
```
45+
46+
## Precision
47+
48+
With the growing adoption of native `BigInt` support in JavaScript, libraries like *Fraction.js* have embraced it for handling arbitrary precision. This enables enhanced performance and accuracy in mathematical operations involving large integers, offering a more reliable solution for applications requiring precision beyond the typical constraints of floating-point `Number` types.
49+
50+
## Examples / Motivation
51+
52+
A simple example of using *Fraction.js* might look like this:
4053

4154
```javascript
4255
var f = new Fraction("9.4'31'"); // 9.4313131313131...
4356
f.mul([-4, 3]).mod("4.'8'"); // 4.88888888888888...
4457
```
45-
The result is
58+
59+
The result can then be displayed as:
4660

4761
```javascript
4862
console.log(f.toFraction()); // -4154 / 1485
4963
```
50-
You could of course also access the sign (s), numerator (n) and denominator (d) on your own:
64+
65+
Additionally, you can access the internal components of the fraction, such as the sign (s), numerator (n), and denominator (d). Keep in mind that these values are stored as `BigInt`:
66+
5167
```javascript
52-
f.s * f.n / f.d = -1 * 4154 / 1485 = -2.797306...
68+
Number(f.s) * Number(f.n) / Number(f.d) = -1 * 4154 / 1485 = -2.797306...
5369
```
5470

55-
If you would try to calculate it yourself, you would come up with something like:
71+
If you attempted to calculate this manually using floating-point arithmetic, you'd get something like:
5672

5773
```javascript
5874
(9.4313131 * (-4 / 3)) % 4.888888 = -2.797308133...
5975
```
6076

61-
Quite okay, but yea - not as accurate as it could be.
77+
While 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.
78+
79+
### Laplace Probability
80+
81+
A simple example of using *Fraction.js* to calculate probabilities. Let’s find the probability of throwing specific outcomes with a fair die:
6282

83+
- **P({3})**: The probability of rolling a 3.
84+
- **P({1, 4})**: The probability of rolling either 1 or 4.
85+
- **P({2, 4, 6})**: The probability of rolling 2, 4, or 6.
6386

64-
Laplace Probability
65-
===
66-
Simple example. What's the probability of throwing a 3, and 1 or 4, and 2 or 4 or 6 with a fair dice?
87+
#### P({3}):
6788

68-
P({3}):
6989
```javascript
70-
var p = new Fraction([3].length, 6).toString(); // 0.1(6)
90+
var p = new Fraction([3].length, 6).toString(); // "0.1(6)"
7191
```
7292

73-
P({1, 4}):
93+
#### P({1, 4}):
94+
7495
```javascript
75-
var p = new Fraction([1, 4].length, 6).toString(); // 0.(3)
96+
var p = new Fraction([1, 4].length, 6).toString(); // "0.(3)"
7697
```
7798

78-
P({2, 4, 6}):
99+
#### P({2, 4, 6}):
100+
79101
```javascript
80-
var p = new Fraction([2, 4, 6].length, 6).toString(); // 0.5
102+
var p = new Fraction([2, 4, 6].length, 6).toString(); // "0.5"
81103
```
82104

83-
Convert degrees/minutes/seconds to precise rational representation:
84-
===
105+
###Convert degrees/minutes/seconds to precise rational representation:
85106

86107
57+45/60+17/3600
108+
87109
```javascript
88110
var deg = 57; // 57°
89111
var min = 45; // 45 Minutes
@@ -93,8 +115,8 @@ new Fraction(deg).add(min, 60).add(sec, 3600).toString() // -> 57.7547(2)
93115
```
94116

95117

96-
Rational approximation of irrational numbers
97-
===
118+
###Rational approximation of irrational numbers
119+
98120

99121
Now it's getting messy ;d To 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*.
100122

@@ -111,7 +133,7 @@ for (var n = 0; n <= 10; n++) {
111133

112134
console.log(n + "\t" + a + "\t" + b + "\t" + c + "\t" + x);
113135

114-
if (c.add(2).pow(2) < 5) {
136+
if (c.add(2).pow(2).valueOf() < 5) {
115137
a = c;
116138
x = "1";
117139
} else {
@@ -139,21 +161,21 @@ n a[n] b[n] c[n] x[n]
139161
9 15/64 121/512 241/1024 0
140162
10 241/1024 121/512 483/2048 1
141163
```
164+
142165
Thus 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))
143166

167+
I 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).
144168

145-
I published another example on how to approximate PI with fraction.js on my [blog](http://www.xarg.org/2014/03/precise-calculations-in-javascript/) (Still not the best idea to approximate irrational numbers, but it illustrates the capabilities of Fraction.js perfectly).
146169

170+
###Get the exact fractional part of a number
147171

148-
Get the exact fractional part of a number
149-
---
150172
```javascript
151173
var f = new Fraction("-6.(3416)");
152-
console.log("" + f.mod(1).abs()); // 0.(3416)
174+
console.log(f.mod(1).abs().toFraction()); // = 3416/9999
153175
```
154176

155-
Mathematical correct modulo
156-
---
177+
###Mathematical correct modulo
178+
157179
The 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:
158180

159181
```javascript
@@ -174,29 +196,29 @@ It turns out that Fraction.js outperforms almost any fmod() implementation, incl
174196
The 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.
175197

176198

177-
Parser
178-
===
199+
##Parser
200+
179201

180202
Any function (see below) as well as the constructor of the *Fraction* class parses its input and reduce it to the smallest term.
181203

182204
You can pass either Arrays, Objects, Integers, Doubles or Strings.
183205

184-
Arrays / Objects
185-
---
206+
###Arrays / Objects
207+
186208
```javascript
187209
new Fraction(numerator, denominator);
188210
new Fraction([numerator, denominator]);
189211
new Fraction({n: numerator, d: denominator});
190212
```
191213

192-
Integers
193-
---
214+
###Integers
215+
194216
```javascript
195217
new Fraction(123);
196218
```
197219

198-
Doubles
199-
---
220+
###Doubles
221+
200222
```javascript
201223
new Fraction(55.4);
202224
```
@@ -206,8 +228,8 @@ new Fraction(55.4);
206228
The 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.
207229

208230

209-
Strings
210-
---
231+
###Strings
232+
211233
```javascript
212234
new Fraction("123.45");
213235
new Fraction("123/45"); // A rational number represented as two decimals, separated by a slash
@@ -219,14 +241,14 @@ new Fraction("123.45'6'"); // Note the quotes, see below!
219241
new Fraction("123.45(6)"); // Note the brackets, see below!
220242
```
221243

222-
Two arguments
223-
---
244+
###Two arguments
245+
224246
```javascript
225247
new Fraction(3, 2); // 3/2 = 1.5
226248
```
227249

228-
Repeating decimal places
229-
---
250+
### Repeating decimal places
251+
230252
*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)
231253

232254
Assume 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:
@@ -275,8 +297,8 @@ if (x !== null) {
275297
}
276298
```
277299

278-
Attributes
279-
===
300+
##Attributes
301+
280302

281303
The 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.
282304

@@ -288,8 +310,8 @@ console.log(f.s); // Sign: -1
288310
```
289311

290312

291-
Functions
292-
===
313+
##Functions
314+
293315

294316
Fraction abs()
295317
---
@@ -386,17 +408,17 @@ Generates an exact string representation of the actual object. For repeated deci
386408

387409
**Note:** As `valueOf()` and `toString()` are provided, `toString()` is only called implicitly in a real string context. Using the plus-operator like `"123" + new Fraction` will call valueOf(), because JavaScript tries to combine two primitives first and concatenates them later, as string will be the more dominant type. `alert(new Fraction)` or `String(new Fraction)` on the other hand will do what you expect. If you really want to have control, you should call `toString()` or `valueOf()` explicitly!
388410

389-
String toLatex(excludeWhole=false)
411+
String toLatex(showMixed=false)
390412
---
391-
Generates an exact LaTeX representation of the actual object. You can see a [live demo](http://www.xarg.org/2014/03/precise-calculations-in-javascript/) on my blog.
413+
Generates 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.
392414

393-
The optional boolean parameter indicates if you want to exclude the whole part. "1 1/3" instead of "4/3"
415+
The optional boolean parameter indicates if you want to show the a mixed fraction. "1 1/3" instead of "4/3"
394416

395-
String toFraction(excludeWhole=false)
417+
String toFraction(showMixed=false)
396418
---
397419
Gets a string representation of the fraction
398420

399-
The optional boolean parameter indicates if you want to exclude the whole part. "1 1/3" instead of "4/3"
421+
The optional boolean parameter indicates if you want to showa mixed fraction. "1 1/3" instead of "4/3"
400422

401423
Array toContinued()
402424
---
@@ -412,55 +434,58 @@ Fraction clone()
412434
Creates a copy of the actual Fraction object
413435

414436

415-
Exceptions
416-
===
417-
If a really hard error occurs (parsing error, division by zero), *fraction.js* throws exceptions! Please make sure you handle them correctly.
437+
##Exceptions
438+
439+
If a really hard error occurs (parsing error, division by zero), *Fraction.js* throws exceptions! Please make sure you handle them correctly.
418440

419441

442+
##Installation
420443

421-
Installation
422-
===
423444
Installing fraction.js is as easy as cloning this repo or use the following command:
424445

425-
```
446+
```bash
426447
npm install fraction.js
427448
```
428449

429-
Using Fraction.js with the browser
430-
===
450+
##Using Fraction.js with the browser
451+
431452
```html
432-
<script src="fraction.js"></script>
453+
<script src="fraction.min.js"></script>
433454
<script>
434455
console.log(Fraction("123/456"));
435456
</script>
436457
```
437458

438-
Using Fraction.js with TypeScript
439-
===
459+
##Using Fraction.js with TypeScript
460+
440461
```js
441462
import Fraction from "fraction.js";
442463
console.log(Fraction("123/456"));
443464
```
444465

445-
Coding Style
446-
===
447-
As 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.
448466

467+
##Coding Style
468+
469+
As 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.
449470

450-
Precision
451-
===
452-
Fraction.js tries to circumvent floating point errors, by having an internal representation of numerator and denominator. As it relies on JavaScript, there is also a limit. The biggest number representable is `Number.MAX_SAFE_INTEGER / 1` and the smallest is `-1 / Number.MAX_SAFE_INTEGER`, with `Number.MAX_SAFE_INTEGER=9007199254740991`. If this is not enough, there is `bigfraction.js` shipped experimentally, which relies on `BigInt` and should become the new Fraction.js eventually.
471+
##Building the library
453472

454-
Testing
455-
===
456-
If you plan to enhance the library, make sure you add test cases and all the previous tests are passing. You can test the library with
473+
After cloning the Git repository run:
457474

475+
```bash
476+
npm install
477+
npm run build
458478
```
459-
npm test
479+
480+
##Run a test
481+
482+
Testing the source against the shipped test suite is as easy as
483+
484+
```bash
485+
npm run test
460486
```
461487

488+
## Copyright and licensing
462489

463-
Copyright and licensing
464-
===
465-
Copyright (c) 2023, [Robert Eisele](https://raw.org/)
490+
Copyright (c) 2025, [Robert Eisele](https://raw.org/)
466491
Licensed under the MIT license.

0 commit comments

Comments
 (0)