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