simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

README.md (15812B)


      1 # Fraction.js - ℚ in JavaScript
      2 
      3 [![NPM Package](https://nodei.co/npm-dl/fraction.js.png?months=6&height=1)](https://npmjs.org/package/fraction.js)
      4 
      5 [![Build Status](https://travis-ci.org/infusion/Fraction.js.svg?branch=master)](https://travis-ci.org/infusion/Fraction.js)
      6 [![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
      7 
      8 
      9 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:
     10 
     11 ```javascript
     12 1 / 98 * 98 // = 0.9999999999999999
     13 ```
     14 
     15 If you need more precision or just want a fraction as a result, have a look at *Fraction.js*:
     16 
     17 ```javascript
     18 var Fraction = require('fraction.js');
     19 
     20 Fraction(1).div(98).mul(98) // = 1
     21 ```
     22 
     23 Internally, numbers are represented as *numerator / denominator*, which adds just a little overhead. However, the library is written with performance in mind and outperforms any other implementation, as you can see [here](http://jsperf.com/convert-a-rational-number-to-a-babylonian-fractions/28). This basic data-type makes it the perfect basis for [Polynomial.js](https://github.com/infusion/Polynomial.js) and [Math.js](https://github.com/josdejong/mathjs).
     24 
     25 Convert decimal to fraction
     26 ===
     27 The simplest job for fraction.js is to get a fraction out of a decimal:
     28 ```javascript
     29 var x = new Fraction(1.88);
     30 var res = x.toFraction(true); // String "1 22/25"
     31 ```
     32 
     33 Examples / Motivation
     34 ===
     35 A simple example might be
     36 
     37 ```javascript
     38 var f = new Fraction("9.4'31'"); // 9.4313131313131...
     39 f.mul([-4, 3]).mod("4.'8'"); // 4.88888888888888...
     40 ```
     41 The result is
     42 
     43 ```javascript
     44 console.log(f.toFraction()); // -4154 / 1485
     45 ```
     46 You could of course also access the sign (s), numerator (n) and denominator (d) on your own:
     47 ```javascript
     48 f.s * f.n / f.d = -1 * 4154 / 1485 = -2.797306...
     49 ```
     50 
     51 If you would try to calculate it yourself, you would come up with something like:
     52 
     53 ```javascript
     54 (9.4313131 * (-4 / 3)) % 4.888888 = -2.797308133...
     55 ```
     56 
     57 Quite okay, but yea - not as accurate as it could be.
     58 
     59 
     60 Laplace Probability
     61 ===
     62 Simple example. What's the probability of throwing a 3, and 1 or 4, and 2 or 4 or 6 with a fair dice?
     63 
     64 P({3}):
     65 ```javascript
     66 var p = new Fraction([3].length, 6).toString(); // 0.1(6)
     67 ```
     68 
     69 P({1, 4}):
     70 ```javascript
     71 var p = new Fraction([1, 4].length, 6).toString(); // 0.(3)
     72 ```
     73 
     74 P({2, 4, 6}):
     75 ```javascript
     76 var p = new Fraction([2, 4, 6].length, 6).toString(); // 0.5
     77 ```
     78 
     79 Convert degrees/minutes/seconds to precise rational representation:
     80 ===
     81 
     82 57+45/60+17/3600
     83 ```javascript
     84 var deg = 57; // 57°
     85 var min = 45; // 45 Minutes
     86 var sec = 17; // 17 Seconds
     87 
     88 new Fraction(deg).add(min, 60).add(sec, 3600).toString() // -> 57.7547(2)
     89 ```
     90 
     91 Rounding a fraction to the closest tape measure value
     92 === 
     93 
     94 A tape measure is usually divided in parts of `1/16`. Rounding a given fraction to the closest value on a tape measure can be determined by
     95 
     96 ```javascript
     97 function closestTapeMeasure(frac) {
     98 
     99     /*
    100     k/16 ≤ a/b < (k+1)/16
    101     ⇔ k ≤ 16*a/b < (k+1)
    102     ⇔ k = floor(16*a/b)
    103     */
    104     return new Fraction(Math.round(16 * Fraction(frac).valueOf()), 16);
    105 }
    106 // closestTapeMeasure("1/3") // 5/16
    107 ```
    108 
    109 Rational approximation of irrational numbers
    110 ===
    111 
    112 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*.
    113 
    114 Then the following algorithm will generate the rational number besides the binary representation.
    115 
    116 ```javascript
    117 var x = "/", s = "";
    118 
    119 var a = new Fraction(0),
    120     b = new Fraction(1);
    121 for (var n = 0; n <= 10; n++) {
    122 
    123   var c = a.add(b).div(2);
    124 
    125   console.log(n + "\t" + a + "\t" + b + "\t" + c + "\t" + x);
    126 
    127   if (c.add(2).pow(2) < 5) {
    128     a = c;
    129     x = "1";
    130   } else {
    131     b = c;
    132     x = "0";
    133   }
    134   s+= x;
    135 }
    136 console.log(s)
    137 ```
    138 
    139 The result is
    140 
    141 ```
    142 n   a[n]        b[n]        c[n]            x[n]
    143 0   0/1         1/1         1/2             /
    144 1   0/1         1/2         1/4             0
    145 2   0/1         1/4         1/8             0
    146 3   1/8         1/4         3/16            1
    147 4   3/16        1/4         7/32            1
    148 5   7/32        1/4         15/64           1
    149 6   15/64       1/4         31/128          1
    150 7   15/64       31/128      61/256          0
    151 8   15/64       61/256      121/512         0
    152 9   15/64       121/512     241/1024        0
    153 10  241/1024    121/512     483/2048        1
    154 ```
    155 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))
    156 
    157 
    158 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).
    159 
    160 
    161 Get the exact fractional part of a number
    162 ---
    163 ```javascript
    164 var f = new Fraction("-6.(3416)");
    165 console.log("" + f.mod(1).abs()); // Will print 0.(3416)
    166 ```
    167 
    168 Mathematical correct modulo
    169 ---
    170 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:
    171 
    172 ```javascript
    173 var a = -1;
    174 var b = 10.99;
    175 
    176 console.log(new Fraction(a)
    177   .mod(b)); // Not correct, usual Modulo
    178 
    179 console.log(new Fraction(a)
    180   .mod(b).add(b).mod(b)); // Correct! Mathematical Modulo
    181 ```
    182 
    183 fmod() impreciseness circumvented
    184 ---
    185 It 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.
    186 
    187 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.
    188 
    189 
    190 Parser
    191 ===
    192 
    193 Any function (see below) as well as the constructor of the *Fraction* class parses its input and reduce it to the smallest term.
    194 
    195 You can pass either Arrays, Objects, Integers, Doubles or Strings.
    196 
    197 Arrays / Objects
    198 ---
    199 ```javascript
    200 new Fraction(numerator, denominator);
    201 new Fraction([numerator, denominator]);
    202 new Fraction({n: numerator, d: denominator});
    203 ```
    204 
    205 Integers
    206 ---
    207 ```javascript
    208 new Fraction(123);
    209 ```
    210 
    211 Doubles
    212 ---
    213 ```javascript
    214 new 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 
    219 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.
    220 
    221 
    222 Strings
    223 ---
    224 ```javascript
    225 new Fraction("123.45");
    226 new Fraction("123/45"); // A rational number represented as two decimals, separated by a slash
    227 new Fraction("123:45"); // A rational number represented as two decimals, separated by a colon
    228 new Fraction("4 123/45"); // A rational number represented as a whole number and a fraction
    229 new Fraction("123.'456'"); // Note the quotes, see below!
    230 new Fraction("123.(456)"); // Note the brackets, see below!
    231 new Fraction("123.45'6'"); // Note the quotes, see below!
    232 new Fraction("123.45(6)"); // Note the brackets, see below!
    233 ```
    234 
    235 Two arguments
    236 ---
    237 ```javascript
    238 new 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 
    245 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:
    246 
    247 ```javascript
    248 var f = new Fraction("123.32");
    249 console.log("Bam: " + f.div("33.6(567)"));
    250 ```
    251 
    252 To 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
    255 function 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 
    285 var f, x = formatDecimal("13.0123123123"); // = 13.0(123)
    286 if (x !== null) {
    287   f = new Fraction(x);
    288 }
    289 ```
    290 
    291 Attributes
    292 ===
    293 
    294 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.
    295 
    296 ```javascript
    297 var f = new Fraction('-1/2');
    298 console.log(f.n); // Numerator: 1
    299 console.log(f.d); // Denominator: 2
    300 console.log(f.s); // Sign: -1
    301 ```
    302 
    303 
    304 Functions
    305 ===
    306 
    307 Fraction abs()
    308 ---
    309 Returns the actual number without any sign information
    310 
    311 Fraction neg()
    312 ---
    313 Returns the actual number with flipped sign in order to get the additive inverse
    314 
    315 Fraction add(n)
    316 ---
    317 Returns the sum of the actual number and the parameter n
    318 
    319 Fraction sub(n)
    320 ---
    321 Returns the difference of the actual number and the parameter n
    322 
    323 Fraction mul(n)
    324 ---
    325 Returns the product of the actual number and the parameter n
    326 
    327 Fraction div(n)
    328 ---
    329 Returns the quotient of the actual number and the parameter n
    330 
    331 Fraction pow(exp)
    332 ---
    333 Returns the power of the actual number, raised to an possible rational exponent. If the result becomes non-rational the function returns `null`.
    334 
    335 Fraction mod(n)
    336 ---
    337 Returns 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 will. 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).
    338 
    339 Fraction mod()
    340 ---
    341 Returns the modulus (rest of the division) of the actual object (numerator mod denominator)
    342 
    343 Fraction gcd(n)
    344 ---
    345 Returns the fractional greatest common divisor
    346 
    347 Fraction lcm(n)
    348 ---
    349 Returns the fractional least common multiple
    350 
    351 Fraction ceil([places=0-16])
    352 ---
    353 Returns the ceiling of a rational number with Math.ceil
    354 
    355 Fraction floor([places=0-16])
    356 ---
    357 Returns the floor of a rational number with Math.floor
    358 
    359 Fraction round([places=0-16])
    360 ---
    361 Returns the rational number rounded with Math.round
    362 
    363 Fraction inverse()
    364 ---
    365 Returns the multiplicative inverse of the actual number (n / d becomes d / n) in order to get the reciprocal
    366 
    367 Fraction simplify([eps=0.001])
    368 ---
    369 Simplifies the rational number under a certain error threshold. Ex. `0.333` will be `1/3` with `eps=0.001`
    370 
    371 boolean equals(n)
    372 ---
    373 Check if two numbers are equal
    374 
    375 int compare(n)
    376 ---
    377 Compare two numbers.
    378 ```
    379 result < 0: n is greater than actual number
    380 result > 0: n is smaller than actual number
    381 result = 0: n is equal to the actual number
    382 ```
    383 
    384 boolean divisible(n)
    385 ---
    386 Check if two numbers are divisible (n divides this)
    387 
    388 double valueOf()
    389 ---
    390 Returns a decimal representation of the fraction
    391 
    392 String toString([decimalPlaces=15])
    393 ---
    394 Generates an exact string representation of the actual object. For repeated decimal places all digits are collected within brackets, like `1/3 = "0.(3)"`. For all other numbers, up to `decimalPlaces` significant digits are collected - which includes trailing zeros if the number is getting truncated. However, `1/2 = "0.5"` without trailing zeros of course.
    395 
    396 **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!
    397 
    398 String toLatex(excludeWhole=false)
    399 ---
    400 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.
    401 
    402 The optional boolean parameter indicates if you want to exclude the whole part. "1 1/3" instead of "4/3"
    403 
    404 String toFraction(excludeWhole=false)
    405 ---
    406 Gets a string representation of the fraction
    407 
    408 The optional boolean parameter indicates if you want to exclude the whole part. "1 1/3" instead of "4/3"
    409 
    410 Array toContinued()
    411 ---
    412 Gets an array of the fraction represented as a continued fraction. The first element always contains the whole part.
    413 
    414 ```javascript
    415 var f = new Fraction('88/33');
    416 var c = f.toContinued(); // [2, 1, 2]
    417 ```
    418 
    419 Fraction clone()
    420 ---
    421 Creates a copy of the actual Fraction object
    422 
    423 
    424 Exceptions
    425 ===
    426 If a really hard error occurs (parsing error, division by zero), *fraction.js* throws exceptions! Please make sure you handle them correctly.
    427 
    428 
    429 
    430 Installation
    431 ===
    432 Installing fraction.js is as easy as cloning this repo or use one of the following commands:
    433 
    434 ```
    435 bower install fraction.js
    436 ```
    437 or
    438 
    439 ```
    440 npm install fraction.js
    441 ```
    442 
    443 Using Fraction.js with the browser
    444 ===
    445 ```html
    446 <script src="fraction.js"></script>
    447 <script>
    448     console.log(Fraction("123/456"));
    449 </script>
    450 ```
    451 
    452 Using Fraction.js with require.js
    453 ===
    454 ```html
    455 <script src="require.js"></script>
    456 <script>
    457 requirejs(['fraction.js'],
    458 function(Fraction) {
    459     console.log(Fraction("123/456"));
    460 });
    461 </script>
    462 ```
    463 
    464 Using Fraction.js with TypeScript
    465 ===
    466 ```js
    467 import Fraction from "fraction.js";
    468 console.log(Fraction("123/456"));
    469 ```
    470 
    471 Coding Style
    472 ===
    473 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.
    474 
    475 
    476 Precision
    477 ===
    478 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. 
    479 
    480 Testing
    481 ===
    482 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
    483 
    484 ```
    485 npm test
    486 ```
    487 
    488 
    489 Copyright and licensing
    490 ===
    491 Copyright (c) 2014-2019, [Robert Eisele](https://www.xarg.org/)
    492 Dual licensed under the MIT or GPL Version 2 licenses.