JAVASCRIPT 24
###### Bigfraction.js Guest on 20th April 2021 04:46:16 PM
1. /**
2.  * @license Fraction.js v4.0.12 09/09/2015
3.  * http://www.xarg.org/2014/03/rational-numbers-in-javascript/
4.  *
5.  * Copyright (c) 2015, 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) { 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 = BigInt(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 createError(name) {
66.
67.     function errorConstructor() {
68.       const temp = Error.apply(this, arguments);
69.       temp['name'] = this['name'] = name;
70.       this['stack'] = temp['stack'];
71.       this['message'] = temp['message'];
72.     }
73.
74.     /**
75.      * Error constructor
76.      *
77.      * @constructor
78.      */
79.     function IntermediateInheritor() { }
80.     IntermediateInheritor.prototype = Error.prototype;
81.     errorConstructor.prototype = new IntermediateInheritor();
82.
83.     return errorConstructor;
84.   }
85.
86.   const DivisionByZero = Fraction['DivisionByZero'] = createError('DivisionByZero');
87.   const InvalidParameter = Fraction['InvalidParameter'] = createError('InvalidParameter');
88.
89.   function assign(n, s) {
90.
91.     try {
92.       n = BigInt(n);
93.     } catch (e) {
94.       throw new InvalidParameter();
95.     }
96.
97.     return n * s;
98.   }
99.
100.   const parse = function(p1, p2) {
101.
102.     let n = C_ZERO, d = C_ONE, s = C_ONE;
103.
104.     if (p1 === undefined || p1 === null) {
105.       /* void */
106.     } else if (p2 !== undefined) {
107.       n = BigInt(p1);
108.       d = BigInt(p2);
109.       s = n * d;
110.     } else if (typeof p1 === "object") {
111.       if ("d" in p1 && "n" in p1) {
112.         n = BigInt(p1["n"]);
113.         d = BigInt(p1["d"]);
114.         if ("s" in p1)
115.           n *= BigInt(p1["s"]);
116.       } else if (0 in p1) {
117.         n = BigInt(p1[0]);
118.         if (1 in p1)
119.           d = BigInt(p1[1]);
120.       } else if (p1 instanceof BigInt) {
121.         n = BigInt(p1);
122.       } else {
123.         throw new InvalidParameter();
124.       }
125.       s = n * d;
126.     } else if (typeof p1 === "bigint") {
127.       n = p1;
128.       s = p1;
129.       d = BigInt(1);
130.     } else if (typeof p1 === "number") {
131.
132.       if (isNaN(p1)) {
133.         throw new InvalidParameter();
134.       }
135.
136.       if (p1 < 0) {
137.         s = -C_ONE;
138.         p1 = -p1;
139.       }
140.
141.       if (p1 % 1 === 0) {
142.         n = BigInt(p1);
143.       } else if (p1 > 0) { // check for != 0, scale would become NaN (log(0)), which converges really slow
144.
145.         let z = 1;
146.
147.         let A = 0, B = 1;
148.         let C = 1, D = 1;
149.
150.         let N = 10000000;
151.
152.         if (p1 >= 1) {
153.           z = 10 ** Math.floor(1 + Math.log10(p1));
154.           p1 /= z;
155.         }
156.
157.         // Using Farey Sequences
158.
159.         while (B <= N && D <= N) {
160.           let M = (A + C) / (B + D);
161.
162.           if (p1 === M) {
163.             if (B + D <= N) {
164.               n = A + C;
165.               d = B + D;
166.             } else if (D > B) {
167.               n = C;
168.               d = D;
169.             } else {
170.               n = A;
171.               d = B;
172.             }
173.             break;
174.
175.           } else {
176.
177.             if (p1 > M) {
178.               A += C;
179.               B += D;
180.             } else {
181.               C += A;
182.               D += B;
183.             }
184.
185.             if (B > N) {
186.               n = C;
187.               d = D;
188.             } else {
189.               n = A;
190.               d = B;
191.             }
192.           }
193.         }
194.         n = BigInt(n) * BigInt(z);
195.         d = BigInt(d);
196.
197.       } else if (isNaN(p1)) {
198.         d = n = NaN;
199.       }
200.
201.     } else if (typeof p1 === "string") {
202.
203.       let ndx = 0;
204.
205.       let v = C_ZERO, w = C_ZERO, x = C_ZERO, y = C_ONE, z = C_ONE;
206.
207.       let match = p1.match(/\d+|./g);
208.
209.       if (match === null)
210.         throw new InvalidParameter()
211.
212.       if (match[ndx] === '-') {// Check for minus sign at the beginning
213.         s = -C_ONE;
214.         ndx++;
215.       } else if (match[ndx] === '+') {// Check for plus sign at the beginning
216.         ndx++;
217.       }
218.
219.       if (match.length === ndx + 1) { // Check if it's just a simple number "1234"
220.         w = assign(match[ndx++], s);
221.       } else if (match[ndx + 1] === '.' || match[ndx] === '.') { // Check if it's a decimal number
222.
223.         if (match[ndx] !== '.') { // Handle 0.5 and .5
224.           v = assign(match[ndx++], s);
225.         }
226.         ndx++;
227.
228.         // Check for decimal places
229.         if (ndx + 1 === match.length || match[ndx + 1] === '(' && match[ndx + 3] === ')' || match[ndx + 1] === "'" && match[ndx + 3] === "'") {
230.           w = assign(match[ndx], s);
231.           y = C_TEN ** BigInt(match[ndx].length);
232.           ndx++;
233.         }
234.
235.         // Check for repeating places
236.         if (match[ndx] === '(' && match[ndx + 2] === ')' || match[ndx] === "'" && match[ndx + 2] === "'") {
237.           x = assign(match[ndx + 1], s);
238.           z = C_TEN ** BigInt(match[ndx + 1].length) - C_ONE;
239.           ndx += 3;
240.         }
241.
242.       } else if (match[ndx + 1] === '/' || match[ndx + 1] === ':') { // Check for a simple fraction "123/456" or "123:456"
243.         w = assign(match[ndx], s);
244.         y = assign(match[ndx + 2], C_ONE);
245.         ndx += 3;
246.       } else if (match[ndx + 3] === '/' && match[ndx + 1] === ' ') { // Check for a complex fraction "123 1/2"
247.         v = assign(match[ndx], s);
248.         w = assign(match[ndx + 2], s);
249.         y = assign(match[ndx + 4], C_ONE);
250.         ndx += 5;
251.       }
252.
253.       if (match.length <= ndx) { // Check for more tokens on the stack
254.         d = y * z;
255.         s = /* void */
256.         n = x + d * v + z * w;
257.       } else {
258.         throw new InvalidParameter();
259.       }
260.
261.     } else {
262.       throw new InvalidParameter();
263.     }
264.
265.     if (d === C_ZERO) {
266.       throw new DivisionByZero();
267.     }
268.
269.     P["s"] = s < C_ZERO ? -C_ONE : C_ONE;
270.     P["n"] = n < C_ZERO ? -n : n;
271.     P["d"] = d < C_ZERO ? -d : d;
272.
273.   };
274.
275.   function modpow(b, e, m) {
276.
277.     let r = C_ONE;
278.     for (; e > C_ZERO; b = (b * b) % m, e >>= C_ONE) {
279.
280.       if (e & C_ONE) {
281.         r = (r * b) % m;
282.       }
283.     }
284.     return r;
285.   }
286.
287.   function cycleLen(n, d) {
288.
289.     for (; d % C_TWO === C_ZERO;
290.       d /= C_TWO) {
291.     }
292.
293.     for (; d % C_FIVE === C_ZERO;
294.       d /= C_FIVE) {
295.     }
296.
297.     if (d === C_ONE) // Catch non-cyclic numbers
298.       return C_ZERO;
299.
300.     // If we would like to compute really large numbers quicker, we could make use of Fermat's little theorem:
301.     // 10^(d-1) % d == 1
302.     // However, we don't need such large numbers and MAX_CYCLE_LEN should be the capstone,
303.     // as we want to translate the numbers to strings.
304.
305.     let rem = C_TEN % d;
306.     let t = C_ONE;
307.
308.     for (; rem !== C_ONE; t++) {
309.       rem = rem * C_TEN % d;
310.
311.       if (t > MAX_CYCLE_LEN)
312.         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
313.     }
314.     return t;
315.   }
316.
317.   function cycleStart(n, d, len) {
318.
319.     let rem1 = C_ONE;
320.     let rem2 = modpow(C_TEN, len, d);
321.
322.     for (let t = 0; t < 300; t++) { // s < ~log10(Number.MAX_VALUE)
323.       // Solve 10^s == 10^(s+t) (mod d)
324.
325.       if (rem1 === rem2)
326.         return BigInt(t);
327.
328.       rem1 = rem1 * C_TEN % d;
329.       rem2 = rem2 * C_TEN % d;
330.     }
331.     return 0;
332.   }
333.
334.   function gcd(a, b) {
335.
336.     if (!a)
337.       return b;
338.     if (!b)
339.       return a;
340.
341.     while (1) {
342.       a %= b;
343.       if (!a)
344.         return b;
345.       b %= a;
346.       if (!b)
347.         return a;
348.     }
349.   }
350.
351.   /**
352.    * Module constructor
353.    *
354.    * @constructor
355.    * @param {number|Fraction=} a
356.    * @param {number=} b
357.    */
358.   function Fraction(a, b) {
359.
360.     if (!(this instanceof Fraction)) {
361.       return new Fraction(a, b);
362.     }
363.
364.     parse(a, b);
365.
366.     a = gcd(P["d"], P["n"]); // Abuse a
367.
368.     this["s"] = P["s"];
369.     this["n"] = P["n"] / a | C_ZERO;
370.     this["d"] = P["d"] / a | C_ZERO;
371.   }
372.
373.   Fraction.prototype = {
374.
375.     "s": C_ONE,
376.     "n": C_ZERO,
377.     "d": C_ONE,
378.
379.     /**
380.      * Calculates the absolute value
381.      *
382.      * Ex: new Fraction(-4).abs() => 4
383.      **/
384.     "abs": function() {
385.
386.       return new Fraction(this["n"], this["d"]);
387.     },
388.
389.     /**
390.      * Inverts the sign of the current fraction
391.      *
392.      * Ex: new Fraction(-4).neg() => 4
393.      **/
394.     "neg": function() {
395.
396.       return new Fraction(-this["s"] * this["n"], this["d"]);
397.     },
398.
399.     /**
400.      * Adds two rational numbers
401.      *
402.      * Ex: new Fraction({n: 2, d: 3}).add("14.9") => 467 / 30
403.      **/
405.
406.       parse(a, b);
407.       return new Fraction(
408.         this["s"] * this["n"] * P["d"] + P["s"] * this["d"] * P["n"],
409.         this["d"] * P["d"]
410.       );
411.     },
412.
413.     /**
414.      * Subtracts two rational numbers
415.      *
416.      * Ex: new Fraction({n: 2, d: 3}).add("14.9") => -427 / 30
417.      **/
418.     "sub": function(a, b) {
419.
420.       parse(a, b);
421.       return new Fraction(
422.         this["s"] * this["n"] * P["d"] - P["s"] * this["d"] * P["n"],
423.         this["d"] * P["d"]
424.       );
425.     },
426.
427.     /**
428.      * Multiplies two rational numbers
429.      *
430.      * Ex: new Fraction("-17.(345)").mul(3) => 5776 / 111
431.      **/
432.     "mul": function(a, b) {
433.
434.       parse(a, b);
435.       return new Fraction(
436.         this["s"] * P["s"] * this["n"] * P["n"],
437.         this["d"] * P["d"]
438.       );
439.     },
440.
441.     /**
442.      * Divides two rational numbers
443.      *
444.      * Ex: new Fraction("-17.(345)").inverse().div(3)
445.      **/
446.     "div": function(a, b) {
447.
448.       parse(a, b);
449.       return new Fraction(
450.         this["s"] * P["s"] * this["n"] * P["d"],
451.         this["d"] * P["n"]
452.       );
453.     },
454.
455.     /**
456.      * Clones the actual object
457.      *
458.      * Ex: new Fraction("-17.(345)").clone()
459.      **/
460.     "clone": function() {
461.       return new Fraction(this);
462.     },
463.
464.     /**
465.      * Calculates the modulo of two rational numbers - a more precise fmod
466.      *
467.      * Ex: new Fraction('4.(3)').mod([7, 8]) => (13/3) % (7/8) = (5/6)
468.      **/
469.     "mod": function(a, b) {
470.
471.       if (a === undefined) {
472.         return new Fraction(this["s"] * this["n"] % this["d"], 1);
473.       }
474.
475.       parse(a, b);
476.       if (0 === P["n"] && 0 === this["d"]) {
477.         Fraction(0, 0); // Throw DivisionByZero
478.       }
479.
480.       /*
481.        * First silly attempt, kinda slow
482.        *
483.        return that["sub"]({
484.        "n": num["n"] * Math.floor((this.n / this.d) / (num.n / num.d)),
485.        "d": num["d"],
486.        "s": this["s"]
487.        });*/
488.
489.       /*
490.        * New attempt: a1 / b1 = a2 / b2 * q + r
491.        * => b2 * a1 = a2 * b1 * q + b1 * b2 * r
492.        * => (b2 * a1 % a2 * b1) / (b1 * b2)
493.        */
494.       return new Fraction(
495.         this["s"] * (P["d"] * this["n"]) % (P["n"] * this["d"]),
496.         P["d"] * this["d"]
497.       );
498.     },
499.
500.     /**
501.      * Calculates the fractional gcd of two rational numbers
502.      *
503.      * Ex: new Fraction(5,8).gcd(3,7) => 1/56
504.      */
505.     "gcd": function(a, b) {
506.
507.       parse(a, b);
508.
509.       // gcd(a / b, c / d) = gcd(a, c) / lcm(b, d)
510.
511.       return new Fraction(gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]), P["d"] * this["d"]);
512.     },
513.
514.     /**
515.      * Calculates the fractional lcm of two rational numbers
516.      *
517.      * Ex: new Fraction(5,8).lcm(3,7) => 15
518.      */
519.     "lcm": function(a, b) {
520.
521.       parse(a, b);
522.
523.       // lcm(a / b, c / d) = lcm(a, c) / gcd(b, d)
524.
525.       if (P["n"] === C_ZERO && this["n"] === C_ZERO) {
526.         return new Fraction;
527.       }
528.       return new Fraction(P["n"] * this["n"], gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]));
529.     },
530.
531.     /**
532.      * Gets the inverse of the fraction, means numerator and denominator are exchanged
533.      *
534.      * Ex: new Fraction([-3, 4]).inverse() => -4 / 3
535.      **/
536.     "inverse": function() {
537.
538.       return new Fraction(this["s"] * this["d"], this["n"]);
539.     },
540.
541.     /**
542.      * Calculates the fraction to some integer exponent
543.      *
544.      * Ex: new Fraction(-1,2).pow(-3) => -8
545.      */
546.     "pow": function(m) {
547.
548.       if (m < 0) {
549.         return new Fraction((this['s'] * this["d"]) ** BigInt(-m), this["n"] ** BigInt(-m));
550.       } else {
551.         return new Fraction((this['s'] * this["n"]) ** BigInt(+m), this["d"] ** BigInt(+m));
552.       }
553.     },
554.
555.     /**
556.      * Check if two rational numbers are the same
557.      *
558.      * Ex: new Fraction(19.6).equals([98, 5]);
559.      **/
560.     "equals": function(a, b) {
561.
562.       parse(a, b);
563.       return this["s"] * this["n"] * P["d"] === P["s"] * P["n"] * this["d"]; // Same as compare() === 0
564.     },
565.
566.     /**
567.      * Check if two rational numbers are the same
568.      *
569.      * Ex: new Fraction(19.6).equals([98, 5]);
570.      **/
571.     "compare": function(a, b) {
572.
573.       parse(a, b);
574.       let t = (this["s"] * this["n"] * P["d"] - P["s"] * P["n"] * this["d"]);
575.
576.       return (C_ZERO < t) - (t < C_ZERO);
577.     },
578.
579.     /**
580.      * Calculates the ceil of a rational number
581.      *
582.      * Ex: new Fraction('4.(3)').ceil() => (5 / 1)
583.      **/
584.     "ceil": function(places) {
585.
586.       places = 10 ** Number(places || 0);
587.
588.       return new Fraction(Math.ceil(places * Number(this["s"] * this["n"]) / Number(this["d"])), places);
589.     },
590.
591.     /**
592.      * Calculates the floor of a rational number
593.      *
594.      * Ex: new Fraction('4.(3)').floor() => (4 / 1)
595.      **/
596.     "floor": function(places) {
597.
598.       places = 10 ** Number(places || 0);
599.
600.       return new Fraction(Math.floor(places * Number(this["s"] * this["n"]) / Number(this["d"])), places);
601.     },
602.
603.     /**
604.      * Rounds a rational numbers
605.      *
606.      * Ex: new Fraction('4.(3)').round() => (4 / 1)
607.      **/
608.     "round": function(places) {
609.
610.       places = 10 ** Number(places || 0);
611.
612.       return new Fraction(Math.round(places * Number(this["s"] * this["n"]) / Number(this["d"])), places);
613.     },
614.
615.     /**
616.      * Check if two rational numbers are divisible
617.      *
618.      * Ex: new Fraction(19.6).divisible(1.5);
619.      */
620.     "divisible": function(a, b) {
621.
622.       parse(a, b);
623.       return !(!(P["n"] * this["d"]) || ((this["n"] * P["d"]) % (P["n"] * this["d"])));
624.     },
625.
626.     /**
627.      * Returns a decimal representation of the fraction
628.      *
629.      * Ex: new Fraction("100.'91823'").valueOf() => 100.91823918239183
630.      **/
631.     'valueOf': function() {
632.       // Best we can do so far
633.       return Number(this["s"] * this["n"]) / Number(this["d"]);
634.     },
635.
636.     /**
637.      * Creates a string representation of a fraction with all digits
638.      *
639.      * Ex: new Fraction("100.'91823'").toString() => "100.(91823)"
640.      **/
641.     'toString': function(dec) {
642.
643.       let g;
644.       let N = this["n"];
645.       let D = this["d"];
646.
647.       dec = dec || 15; // 15 = decimal places when no repitation
648.
649.       let cycLen = cycleLen(N, D); // Cycle length
650.       let cycOff = cycleStart(N, D, cycLen); // Cycle start
651.
652.       let str = this['s'] < C_ZERO ? "-" : "";
653.
654.       // Append integer part
655.       str += N / D | C_ZERO;
656.
657.       N %= D;
658.       N *= C_TEN;
659.
660.       if (N)
661.         str += ".";
662.
663.       if (cycLen) {
664.
665.         for (let i = cycOff; i--;) {
666.           str += N / D | C_ZERO;
667.           N %= D;
668.           N *= C_TEN;
669.         }
670.         str += "(";
671.         for (let i = cycLen; i--;) {
672.           str += N / D | C_ZERO;
673.           N %= D;
674.           N *= C_TEN;
675.         }
676.         str += ")";
677.       } else {
678.         for (let i = dec; N && i--;) {
679.           str += N / D | C_ZERO;
680.           N %= D;
681.           N *= C_TEN;
682.         }
683.       }
684.       return str;
685.     },
686.
687.     /**
688.      * Returns a string-fraction representation of a Fraction object
689.      *
690.      * Ex: new Fraction("1.'3'").toFraction() => "4 1/3"
691.      **/
692.     'toFraction': function(excludeWhole) {
693.
694.       let n = this["n"];
695.       let d = this["d"];
696.       let str = this['s'] < C_ZERO ? "-" : "";
697.
698.       if (d === C_ONE) {
699.         str += n;
700.       } else {
701.         let whole = n / d | C_ZERO;
702.         if (excludeWhole && whole > C_ZERO) {
703.           str += whole;
704.           str += " ";
705.           n %= d;
706.         }
707.
708.         str += n;
709.         str += '/';
710.         str += d;
711.       }
712.       return str;
713.     },
714.
715.     /**
716.      * Returns a latex representation of a Fraction object
717.      *
718.      * Ex: new Fraction("1.'3'").toLatex() => "\frac{4}{3}"
719.      **/
720.     'toLatex': function(excludeWhole) {
721.
722.       let n = this["n"];
723.       let d = this["d"];
724.       let str = this['s'] < C_ZERO ? "-" : "";
725.
726.       if (d === C_ONE) {
727.         str += n;
728.       } else {
729.         let whole = n / d | C_ZERO;
730.         if (excludeWhole && whole > C_ZERO) {
731.           str += whole;
732.           n %= d;
733.         }
734.
735.         str += "\\frac{";
736.         str += n;
737.         str += '}{';
738.         str += d;
739.         str += '}';
740.       }
741.       return str;
742.     },
743.
744.     /**
745.      * Returns an array of continued fraction elements
746.      *
747.      * Ex: new Fraction("7/8").toContinued() => [0,1,7]
748.      */
749.     'toContinued': function() {
750.
751.       let a = this['n'];
752.       let b = this['d'];
753.       let res = [];
754.
755.       do {
756.         res.push(a / b | C_ZERO);
757.         let t = a % b;
758.         a = b;
759.         b = t;
760.       } while (a !== C_ONE);
761.
762.       return res;
763.     },
764.
765.     "simplify": function(eps) {
766.
767.       // First naive implementation, needs improvement
768.
769.       let cont = this['abs']()['toContinued']();
770.
771.       eps = eps || 0.001;
772.
773.       function rec(a) {
774.         if (a.length === 1)
775.           return new Fraction(a[0]);
777.       }
778.
779.       for (let i = 0; i < cont.length; i++) {
780.         let tmp = rec(cont.slice(0, i + 1));
781.         if (tmp['sub'](this['abs']())['abs']().valueOf() < eps) {
782.           return tmp['mul'](this['s']);
783.         }
784.       }
785.       return this;
786.     }
787.   };
788.
789.   if (typeof define === "function" && define["amd"]) {
790.     define([], function() {
791.       return Fraction;
792.     });
793.   } else if (typeof exports === "object") {
794.     Object.defineProperty(exports, "__esModule", { 'value': true });
795.     Fraction['default'] = Fraction;
796.     Fraction['Fraction'] = Fraction;
797.     module['exports'] = Fraction;
798.   } else {
799.     root['Fraction'] = Fraction;
800.   }
801.
802. })(this);

Paste-bin is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Recent Pastes

Raw Paste

or to edit or fork this paste. It's free.