simple-squiggle

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

bigfraction.js (21076B)


      1 /**
      2  * @license Fraction.js v4.2.0 23/05/2021
      3  * https://www.xarg.org/2014/03/rational-numbers-in-javascript/
      4  *
      5  * Copyright (c) 2021, Robert Eisele (robert@xarg.org)
      6  * Dual licensed under the MIT or GPL Version 2 licenses.
      7  **/
      8 
      9 
     10 /**
     11  *
     12  * This class offers the possibility to calculate fractions.
     13  * You can pass a fraction in different formats. Either as array, as double, as string or as an integer.
     14  *
     15  * Array/Object form
     16  * [ 0 => <nominator>, 1 => <denominator> ]
     17  * [ n => <nominator>, d => <denominator> ]
     18  *
     19  * Integer form
     20  * - Single integer value
     21  *
     22  * Double form
     23  * - Single double value
     24  *
     25  * String form
     26  * 123.456 - a simple double
     27  * 123/456 - a string fraction
     28  * 123.'456' - a double with repeating decimal places
     29  * 123.(456) - synonym
     30  * 123.45'6' - a double with repeating last place
     31  * 123.45(6) - synonym
     32  *
     33  * Example:
     34  *
     35  * let f = new Fraction("9.4'31'");
     36  * f.mul([-4, 3]).div(4.9);
     37  *
     38  */
     39 
     40 (function(root) {
     41 
     42   "use strict";
     43 
     44   // Set Identity function to downgrade BigInt to Number if needed
     45   if (!BigInt) BigInt = function(n) { if (isNaN(n)) throw new Error(""); return n; };
     46 
     47   const C_ONE = BigInt(1);
     48   const C_ZERO = BigInt(0);
     49   const C_TEN = BigInt(10);
     50   const C_TWO = BigInt(2);
     51   const C_FIVE = BigInt(5);
     52 
     53   // Maximum search depth for cyclic rational numbers. 2000 should be more than enough.
     54   // Example: 1/7 = 0.(142857) has 6 repeating decimal places.
     55   // If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits
     56   const MAX_CYCLE_LEN = 2000;
     57 
     58   // Parsed data to avoid calling "new" all the time
     59   const P = {
     60     "s": C_ONE,
     61     "n": C_ZERO,
     62     "d": C_ONE
     63   };
     64 
     65   function assign(n, s) {
     66 
     67     try {
     68       n = BigInt(n);
     69     } catch (e) {
     70       throw Fraction['InvalidParameter'];
     71     }
     72     return n * s;
     73   }
     74 
     75   // Creates a new Fraction internally without the need of the bulky constructor
     76   function newFraction(n, d) {
     77 
     78     if (d === C_ZERO) {
     79       throw Fraction['DivisionByZero'];
     80     }
     81 
     82     const f = Object.create(Fraction.prototype);
     83     f["s"] = n < C_ZERO ? -C_ONE : C_ONE;
     84 
     85     n = n < C_ZERO ? -n : n;
     86 
     87     const a = gcd(n, d);
     88 
     89     f["n"] = n / a;
     90     f["d"] = d / a;
     91     return f;
     92   }
     93 
     94   function factorize(num) {
     95 
     96     const factors = {};
     97 
     98     let n = num;
     99     let i = C_TWO;
    100     let s = C_FIVE - C_ONE;
    101 
    102     while (s <= n) {
    103 
    104       while (n % i === C_ZERO) {
    105         n/= i;
    106         factors[i] = (factors[i] || C_ZERO) + C_ONE;
    107       }
    108       s+= C_ONE + C_TWO * i++;
    109     }
    110 
    111     if (n !== num) {
    112       if (n > 1)
    113         factors[n] = (factors[n] || C_ZERO) + C_ONE;
    114     } else {
    115       factors[num] = (factors[num] || C_ZERO) + C_ONE;
    116     }
    117     return factors;
    118   }
    119 
    120   const parse = function(p1, p2) {
    121 
    122     let n = C_ZERO, d = C_ONE, s = C_ONE;
    123 
    124     if (p1 === undefined || p1 === null) {
    125       /* void */
    126     } else if (p2 !== undefined) {
    127       n = BigInt(p1);
    128       d = BigInt(p2);
    129       s = n * d;
    130 
    131       if (n % C_ONE !== C_ZERO || d % C_ONE !== C_ZERO) {
    132         throw Fraction['NonIntegerParameter'];
    133       }
    134 
    135     } else if (typeof p1 === "object") {
    136       if ("d" in p1 && "n" in p1) {
    137         n = BigInt(p1["n"]);
    138         d = BigInt(p1["d"]);
    139         if ("s" in p1)
    140           n*= BigInt(p1["s"]);
    141       } else if (0 in p1) {
    142         n = BigInt(p1[0]);
    143         if (1 in p1)
    144           d = BigInt(p1[1]);
    145       } else if (p1 instanceof BigInt) {
    146         n = BigInt(p1);
    147       } else {
    148         throw Fraction['InvalidParameter'];
    149       }
    150       s = n * d;
    151     } else if (typeof p1 === "bigint") {
    152       n = p1;
    153       s = p1;
    154       d = BigInt(1);
    155     } else if (typeof p1 === "number") {
    156 
    157       if (isNaN(p1)) {
    158         throw Fraction['InvalidParameter'];
    159       }
    160 
    161       if (p1 < 0) {
    162         s = -C_ONE;
    163         p1 = -p1;
    164       }
    165 
    166       if (p1 % 1 === 0) {
    167         n = BigInt(p1);
    168       } else if (p1 > 0) { // check for != 0, scale would become NaN (log(0)), which converges really slow
    169 
    170         let z = 1;
    171 
    172         let A = 0, B = 1;
    173         let C = 1, D = 1;
    174 
    175         let N = 10000000;
    176 
    177         if (p1 >= 1) {
    178           z = 10 ** Math.floor(1 + Math.log10(p1));
    179           p1/= z;
    180         }
    181 
    182         // Using Farey Sequences
    183 
    184         while (B <= N && D <= N) {
    185           let M = (A + C) / (B + D);
    186 
    187           if (p1 === M) {
    188             if (B + D <= N) {
    189               n = A + C;
    190               d = B + D;
    191             } else if (D > B) {
    192               n = C;
    193               d = D;
    194             } else {
    195               n = A;
    196               d = B;
    197             }
    198             break;
    199 
    200           } else {
    201 
    202             if (p1 > M) {
    203               A+= C;
    204               B+= D;
    205             } else {
    206               C+= A;
    207               D+= B;
    208             }
    209 
    210             if (B > N) {
    211               n = C;
    212               d = D;
    213             } else {
    214               n = A;
    215               d = B;
    216             }
    217           }
    218         }
    219         n = BigInt(n) * BigInt(z);
    220         d = BigInt(d);
    221 
    222       }
    223 
    224     } else if (typeof p1 === "string") {
    225 
    226       let ndx = 0;
    227 
    228       let v = C_ZERO, w = C_ZERO, x = C_ZERO, y = C_ONE, z = C_ONE;
    229 
    230       let match = p1.match(/\d+|./g);
    231 
    232       if (match === null)
    233         throw Fraction['InvalidParameter'];
    234 
    235       if (match[ndx] === '-') {// Check for minus sign at the beginning
    236         s = -C_ONE;
    237         ndx++;
    238       } else if (match[ndx] === '+') {// Check for plus sign at the beginning
    239         ndx++;
    240       }
    241 
    242       if (match.length === ndx + 1) { // Check if it's just a simple number "1234"
    243         w = assign(match[ndx++], s);
    244       } else if (match[ndx + 1] === '.' || match[ndx] === '.') { // Check if it's a decimal number
    245 
    246         if (match[ndx] !== '.') { // Handle 0.5 and .5
    247           v = assign(match[ndx++], s);
    248         }
    249         ndx++;
    250 
    251         // Check for decimal places
    252         if (ndx + 1 === match.length || match[ndx + 1] === '(' && match[ndx + 3] === ')' || match[ndx + 1] === "'" && match[ndx + 3] === "'") {
    253           w = assign(match[ndx], s);
    254           y = C_TEN ** BigInt(match[ndx].length);
    255           ndx++;
    256         }
    257 
    258         // Check for repeating places
    259         if (match[ndx] === '(' && match[ndx + 2] === ')' || match[ndx] === "'" && match[ndx + 2] === "'") {
    260           x = assign(match[ndx + 1], s);
    261           z = C_TEN ** BigInt(match[ndx + 1].length) - C_ONE;
    262           ndx+= 3;
    263         }
    264 
    265       } else if (match[ndx + 1] === '/' || match[ndx + 1] === ':') { // Check for a simple fraction "123/456" or "123:456"
    266         w = assign(match[ndx], s);
    267         y = assign(match[ndx + 2], C_ONE);
    268         ndx+= 3;
    269       } else if (match[ndx + 3] === '/' && match[ndx + 1] === ' ') { // Check for a complex fraction "123 1/2"
    270         v = assign(match[ndx], s);
    271         w = assign(match[ndx + 2], s);
    272         y = assign(match[ndx + 4], C_ONE);
    273         ndx+= 5;
    274       }
    275 
    276       if (match.length <= ndx) { // Check for more tokens on the stack
    277         d = y * z;
    278         s = /* void */
    279         n = x + d * v + z * w;
    280       } else {
    281         throw Fraction['InvalidParameter'];
    282       }
    283 
    284     } else {
    285       throw Fraction['InvalidParameter'];
    286     }
    287 
    288     if (d === C_ZERO) {
    289       throw Fraction['DivisionByZero'];
    290     }
    291 
    292     P["s"] = s < C_ZERO ? -C_ONE : C_ONE;
    293     P["n"] = n < C_ZERO ? -n : n;
    294     P["d"] = d < C_ZERO ? -d : d;
    295   };
    296 
    297   function modpow(b, e, m) {
    298 
    299     let r = C_ONE;
    300     for (; e > C_ZERO; b = (b * b) % m, e >>= C_ONE) {
    301 
    302       if (e & C_ONE) {
    303         r = (r * b) % m;
    304       }
    305     }
    306     return r;
    307   }
    308 
    309   function cycleLen(n, d) {
    310 
    311     for (; d % C_TWO === C_ZERO;
    312       d/= C_TWO) {
    313     }
    314 
    315     for (; d % C_FIVE === C_ZERO;
    316       d/= C_FIVE) {
    317     }
    318 
    319     if (d === C_ONE) // Catch non-cyclic numbers
    320       return C_ZERO;
    321 
    322     // If we would like to compute really large numbers quicker, we could make use of Fermat's little theorem:
    323     // 10^(d-1) % d == 1
    324     // However, we don't need such large numbers and MAX_CYCLE_LEN should be the capstone,
    325     // as we want to translate the numbers to strings.
    326 
    327     let rem = C_TEN % d;
    328     let t = 1;
    329 
    330     for (; rem !== C_ONE; t++) {
    331       rem = rem * C_TEN % d;
    332 
    333       if (t > MAX_CYCLE_LEN)
    334         return C_ZERO; // Returning 0 here means that we don't print it as a cyclic number. It's likely that the answer is `d-1`
    335     }
    336     return BigInt(t);
    337   }
    338 
    339   function cycleStart(n, d, len) {
    340 
    341     let rem1 = C_ONE;
    342     let rem2 = modpow(C_TEN, len, d);
    343 
    344     for (let t = 0; t < 300; t++) { // s < ~log10(Number.MAX_VALUE)
    345       // Solve 10^s == 10^(s+t) (mod d)
    346 
    347       if (rem1 === rem2)
    348         return BigInt(t);
    349 
    350       rem1 = rem1 * C_TEN % d;
    351       rem2 = rem2 * C_TEN % d;
    352     }
    353     return 0;
    354   }
    355 
    356   function gcd(a, b) {
    357 
    358     if (!a)
    359       return b;
    360     if (!b)
    361       return a;
    362 
    363     while (1) {
    364       a%= b;
    365       if (!a)
    366         return b;
    367       b%= a;
    368       if (!b)
    369         return a;
    370     }
    371   }
    372 
    373   /**
    374    * Module constructor
    375    *
    376    * @constructor
    377    * @param {number|Fraction=} a
    378    * @param {number=} b
    379    */
    380   function Fraction(a, b) {
    381 
    382     parse(a, b);
    383 
    384     if (this instanceof Fraction) {
    385       a = gcd(P["d"], P["n"]); // Abuse a
    386       this["s"] = P["s"];
    387       this["n"] = P["n"] / a;
    388       this["d"] = P["d"] / a;
    389     } else {
    390       return newFraction(P['s'] * P['n'], P['d']);
    391     }
    392   }
    393 
    394   Fraction['DivisionByZero'] = new Error("Division by Zero");
    395   Fraction['InvalidParameter'] = new Error("Invalid argument");
    396   Fraction['NonIntegerParameter'] = new Error("Parameters must be integer");
    397 
    398   Fraction.prototype = {
    399 
    400     "s": C_ONE,
    401     "n": C_ZERO,
    402     "d": C_ONE,
    403 
    404     /**
    405      * Calculates the absolute value
    406      *
    407      * Ex: new Fraction(-4).abs() => 4
    408      **/
    409     "abs": function() {
    410 
    411       return newFraction(this["n"], this["d"]);
    412     },
    413 
    414     /**
    415      * Inverts the sign of the current fraction
    416      *
    417      * Ex: new Fraction(-4).neg() => 4
    418      **/
    419     "neg": function() {
    420 
    421       return newFraction(-this["s"] * this["n"], this["d"]);
    422     },
    423 
    424     /**
    425      * Adds two rational numbers
    426      *
    427      * Ex: new Fraction({n: 2, d: 3}).add("14.9") => 467 / 30
    428      **/
    429     "add": function(a, b) {
    430 
    431       parse(a, b);
    432       return newFraction(
    433         this["s"] * this["n"] * P["d"] + P["s"] * this["d"] * P["n"],
    434         this["d"] * P["d"]
    435       );
    436     },
    437 
    438     /**
    439      * Subtracts two rational numbers
    440      *
    441      * Ex: new Fraction({n: 2, d: 3}).add("14.9") => -427 / 30
    442      **/
    443     "sub": function(a, b) {
    444 
    445       parse(a, b);
    446       return newFraction(
    447         this["s"] * this["n"] * P["d"] - P["s"] * this["d"] * P["n"],
    448         this["d"] * P["d"]
    449       );
    450     },
    451 
    452     /**
    453      * Multiplies two rational numbers
    454      *
    455      * Ex: new Fraction("-17.(345)").mul(3) => 5776 / 111
    456      **/
    457     "mul": function(a, b) {
    458 
    459       parse(a, b);
    460       return newFraction(
    461         this["s"] * P["s"] * this["n"] * P["n"],
    462         this["d"] * P["d"]
    463       );
    464     },
    465 
    466     /**
    467      * Divides two rational numbers
    468      *
    469      * Ex: new Fraction("-17.(345)").inverse().div(3)
    470      **/
    471     "div": function(a, b) {
    472 
    473       parse(a, b);
    474       return newFraction(
    475         this["s"] * P["s"] * this["n"] * P["d"],
    476         this["d"] * P["n"]
    477       );
    478     },
    479 
    480     /**
    481      * Clones the actual object
    482      *
    483      * Ex: new Fraction("-17.(345)").clone()
    484      **/
    485     "clone": function() {
    486       return newFraction(this['s'] * this['n'], this['d']);
    487     },
    488 
    489     /**
    490      * Calculates the modulo of two rational numbers - a more precise fmod
    491      *
    492      * Ex: new Fraction('4.(3)').mod([7, 8]) => (13/3) % (7/8) = (5/6)
    493      **/
    494     "mod": function(a, b) {
    495 
    496       if (a === undefined) {
    497         return newFraction(this["s"] * this["n"] % this["d"], C_ONE);
    498       }
    499 
    500       parse(a, b);
    501       if (0 === P["n"] && 0 === this["d"]) {
    502         throw Fraction['DivisionByZero'];
    503       }
    504 
    505       /*
    506        * First silly attempt, kinda slow
    507        *
    508        return that["sub"]({
    509        "n": num["n"] * Math.floor((this.n / this.d) / (num.n / num.d)),
    510        "d": num["d"],
    511        "s": this["s"]
    512        });*/
    513 
    514       /*
    515        * New attempt: a1 / b1 = a2 / b2 * q + r
    516        * => b2 * a1 = a2 * b1 * q + b1 * b2 * r
    517        * => (b2 * a1 % a2 * b1) / (b1 * b2)
    518        */
    519       return newFraction(
    520         this["s"] * (P["d"] * this["n"]) % (P["n"] * this["d"]),
    521         P["d"] * this["d"]
    522       );
    523     },
    524 
    525     /**
    526      * Calculates the fractional gcd of two rational numbers
    527      *
    528      * Ex: new Fraction(5,8).gcd(3,7) => 1/56
    529      */
    530     "gcd": function(a, b) {
    531 
    532       parse(a, b);
    533 
    534       // gcd(a / b, c / d) = gcd(a, c) / lcm(b, d)
    535 
    536       return newFraction(gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]), P["d"] * this["d"]);
    537     },
    538 
    539     /**
    540      * Calculates the fractional lcm of two rational numbers
    541      *
    542      * Ex: new Fraction(5,8).lcm(3,7) => 15
    543      */
    544     "lcm": function(a, b) {
    545 
    546       parse(a, b);
    547 
    548       // lcm(a / b, c / d) = lcm(a, c) / gcd(b, d)
    549 
    550       if (P["n"] === C_ZERO && this["n"] === C_ZERO) {
    551         return newFraction(C_ZERO, C_ONE);
    552       }
    553       return newFraction(P["n"] * this["n"], gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]));
    554     },
    555 
    556     /**
    557      * Gets the inverse of the fraction, means numerator and denominator are exchanged
    558      *
    559      * Ex: new Fraction([-3, 4]).inverse() => -4 / 3
    560      **/
    561     "inverse": function() {
    562       return newFraction(this["s"] * this["d"], this["n"]);
    563     },
    564 
    565     /**
    566      * Calculates the fraction to some integer exponent
    567      *
    568      * Ex: new Fraction(-1,2).pow(-3) => -8
    569      */
    570     "pow": function(a, b) {
    571 
    572       parse(a, b);
    573 
    574       // Trivial case when exp is an integer
    575 
    576       if (P['d'] === C_ONE) {
    577 
    578         if (P['s'] < C_ZERO) {
    579           return newFraction((this['s'] * this["d"]) ** P['n'], this["n"] ** P['n']);
    580         } else {
    581           return newFraction((this['s'] * this["n"]) ** P['n'], this["d"] ** P['n']);
    582         }
    583       }
    584 
    585       // Negative roots become complex
    586       //     (-a/b)^(c/d) = x
    587       // <=> (-1)^(c/d) * (a/b)^(c/d) = x
    588       // <=> (cos(pi) + i*sin(pi))^(c/d) * (a/b)^(c/d) = x
    589       // <=> (cos(c*pi/d) + i*sin(c*pi/d)) * (a/b)^(c/d) = x       # DeMoivre's formula
    590       // From which follows that only for c=0 the root is non-complex
    591       if (this['s'] < C_ZERO) return null;
    592 
    593       // Now prime factor n and d
    594       let N = factorize(this['n']);
    595       let D = factorize(this['d']);
    596 
    597       // Exponentiate and take root for n and d individually
    598       let n = C_ONE;
    599       let d = C_ONE;
    600       for (let k in N) {
    601         if (k === '1') continue;
    602         if (k === '0') {
    603           n = C_ZERO;
    604           break;
    605         }
    606         N[k]*= P['n'];
    607 
    608         if (N[k] % P['d'] === C_ZERO) {
    609           N[k]/= P['d'];
    610         } else return null;
    611         n*= BigInt(k) ** N[k];
    612       }
    613 
    614       for (let k in D) {
    615         if (k === '1') continue;
    616         D[k]*= P['n'];
    617 
    618         if (D[k] % P['d'] === C_ZERO) {
    619           D[k]/= P['d'];
    620         } else return null;
    621         d*= BigInt(k) ** D[k];
    622       }
    623 
    624       if (P['s'] < C_ZERO) {
    625         return newFraction(d, n);
    626       }
    627       return newFraction(n, d);
    628     },
    629 
    630     /**
    631      * Check if two rational numbers are the same
    632      *
    633      * Ex: new Fraction(19.6).equals([98, 5]);
    634      **/
    635     "equals": function(a, b) {
    636 
    637       parse(a, b);
    638       return this["s"] * this["n"] * P["d"] === P["s"] * P["n"] * this["d"]; // Same as compare() === 0
    639     },
    640 
    641     /**
    642      * Check if two rational numbers are the same
    643      *
    644      * Ex: new Fraction(19.6).equals([98, 5]);
    645      **/
    646     "compare": function(a, b) {
    647 
    648       parse(a, b);
    649       let t = (this["s"] * this["n"] * P["d"] - P["s"] * P["n"] * this["d"]);
    650 
    651       return (C_ZERO < t) - (t < C_ZERO);
    652     },
    653 
    654     /**
    655      * Calculates the ceil of a rational number
    656      *
    657      * Ex: new Fraction('4.(3)').ceil() => (5 / 1)
    658      **/
    659     "ceil": function(places) {
    660 
    661       places = C_TEN ** BigInt(places || 0);
    662 
    663       return newFraction(this["s"] * places * this["n"] / this["d"] +
    664         (places * this["n"] % this["d"] > C_ZERO && this["s"] >= C_ZERO ? C_ONE : C_ZERO),
    665         places);
    666     },
    667 
    668     /**
    669      * Calculates the floor of a rational number
    670      *
    671      * Ex: new Fraction('4.(3)').floor() => (4 / 1)
    672      **/
    673     "floor": function(places) {
    674 
    675       places = C_TEN ** BigInt(places || 0);
    676 
    677       return newFraction(this["s"] * places * this["n"] / this["d"] -
    678         (places * this["n"] % this["d"] > C_ZERO && this["s"] < C_ZERO ? C_ONE : C_ZERO),
    679         places);
    680     },
    681 
    682     /**
    683      * Rounds a rational numbers
    684      *
    685      * Ex: new Fraction('4.(3)').round() => (4 / 1)
    686      **/
    687     "round": function(places) {
    688 
    689       places = C_TEN ** BigInt(places || 0);
    690 
    691       /* Derivation:
    692 
    693       s >= 0:
    694         round(n / d) = trunc(n / d) + (n % d) / d >= 0.5 ? 1 : 0
    695                      = trunc(n / d) + 2(n % d) >= d ? 1 : 0
    696       s < 0:
    697         round(n / d) =-trunc(n / d) - (n % d) / d > 0.5 ? 1 : 0
    698                      =-trunc(n / d) - 2(n % d) > d ? 1 : 0
    699 
    700       =>:
    701 
    702       round(s * n / d) = s * trunc(n / d) + s * (C + 2(n % d) > d ? 1 : 0)
    703           where C = s >= 0 ? 1 : 0, to fix the >= for the positve case.
    704       */
    705 
    706       return newFraction(this["s"] * places * this["n"] / this["d"] +
    707         this["s"] * ((this["s"] >= C_ZERO ? C_ONE : C_ZERO) + C_TWO * (places * this["n"] % this["d"]) > this["d"] ? C_ONE : C_ZERO),
    708         places);
    709     },
    710 
    711     /**
    712      * Check if two rational numbers are divisible
    713      *
    714      * Ex: new Fraction(19.6).divisible(1.5);
    715      */
    716     "divisible": function(a, b) {
    717 
    718       parse(a, b);
    719       return !(!(P["n"] * this["d"]) || ((this["n"] * P["d"]) % (P["n"] * this["d"])));
    720     },
    721 
    722     /**
    723      * Returns a decimal representation of the fraction
    724      *
    725      * Ex: new Fraction("100.'91823'").valueOf() => 100.91823918239183
    726      **/
    727     'valueOf': function() {
    728       // Best we can do so far
    729       return Number(this["s"] * this["n"]) / Number(this["d"]);
    730     },
    731 
    732     /**
    733      * Creates a string representation of a fraction with all digits
    734      *
    735      * Ex: new Fraction("100.'91823'").toString() => "100.(91823)"
    736      **/
    737     'toString': function(dec) {
    738 
    739       let N = this["n"];
    740       let D = this["d"];
    741 
    742       dec = dec || 15; // 15 = decimal places when no repitation
    743 
    744       let cycLen = cycleLen(N, D); // Cycle length
    745       let cycOff = cycleStart(N, D, cycLen); // Cycle start
    746 
    747       let str = this['s'] < C_ZERO ? "-" : "";
    748 
    749       // Append integer part
    750       str+= N / D;
    751 
    752       N%= D;
    753       N*= C_TEN;
    754 
    755       if (N)
    756         str+= ".";
    757 
    758       if (cycLen) {
    759 
    760         for (let i = cycOff; i--;) {
    761           str+= N / D;
    762           N%= D;
    763           N*= C_TEN;
    764         }
    765         str+= "(";
    766         for (let i = cycLen; i--;) {
    767           str+= N / D;
    768           N%= D;
    769           N*= C_TEN;
    770         }
    771         str+= ")";
    772       } else {
    773         for (let i = dec; N && i--;) {
    774           str+= N / D;
    775           N%= D;
    776           N*= C_TEN;
    777         }
    778       }
    779       return str;
    780     },
    781 
    782     /**
    783      * Returns a string-fraction representation of a Fraction object
    784      *
    785      * Ex: new Fraction("1.'3'").toFraction() => "4 1/3"
    786      **/
    787     'toFraction': function(excludeWhole) {
    788 
    789       let n = this["n"];
    790       let d = this["d"];
    791       let str = this['s'] < C_ZERO ? "-" : "";
    792 
    793       if (d === C_ONE) {
    794         str+= n;
    795       } else {
    796         let whole = n / d;
    797         if (excludeWhole && whole > C_ZERO) {
    798           str+= whole;
    799           str+= " ";
    800           n%= d;
    801         }
    802 
    803         str+= n;
    804         str+= '/';
    805         str+= d;
    806       }
    807       return str;
    808     },
    809 
    810     /**
    811      * Returns a latex representation of a Fraction object
    812      *
    813      * Ex: new Fraction("1.'3'").toLatex() => "\frac{4}{3}"
    814      **/
    815     'toLatex': function(excludeWhole) {
    816 
    817       let n = this["n"];
    818       let d = this["d"];
    819       let str = this['s'] < C_ZERO ? "-" : "";
    820 
    821       if (d === C_ONE) {
    822         str+= n;
    823       } else {
    824         let whole = n / d;
    825         if (excludeWhole && whole > C_ZERO) {
    826           str+= whole;
    827           n%= d;
    828         }
    829 
    830         str+= "\\frac{";
    831         str+= n;
    832         str+= '}{';
    833         str+= d;
    834         str+= '}';
    835       }
    836       return str;
    837     },
    838 
    839     /**
    840      * Returns an array of continued fraction elements
    841      *
    842      * Ex: new Fraction("7/8").toContinued() => [0,1,7]
    843      */
    844     'toContinued': function() {
    845 
    846       let a = this['n'];
    847       let b = this['d'];
    848       let res = [];
    849 
    850       do {
    851         res.push(a / b);
    852         let t = a % b;
    853         a = b;
    854         b = t;
    855       } while (a !== C_ONE);
    856 
    857       return res;
    858     },
    859 
    860     "simplify": function(eps) {
    861 
    862       eps = eps || 0.001;
    863 
    864       const thisABS = this['abs']();
    865       const cont = thisABS['toContinued']();
    866 
    867       for (let i = 1; i < cont.length; i++) {
    868 
    869         let s = newFraction(cont[i - 1], C_ONE);
    870         for (let k = i - 2; k >= 0; k--) {
    871           s = s['inverse']()['add'](cont[k]);
    872         }
    873 
    874         if (s['sub'](thisABS)['abs']().valueOf() < eps) {
    875           return s['mul'](this['s']);
    876         }
    877       }
    878       return this;
    879     }
    880   };
    881 
    882   if (typeof define === "function" && define["amd"]) {
    883     define([], function() {
    884       return Fraction;
    885     });
    886   } else if (typeof exports === "object") {
    887     Object.defineProperty(exports, "__esModule", { 'value': true });
    888     Fraction['default'] = Fraction;
    889     Fraction['Fraction'] = Fraction;
    890     module['exports'] = Fraction;
    891   } else {
    892     root['Fraction'] = Fraction;
    893   }
    894 
    895 })(this);