PageSourceSearch

https://thedisabledchef.com/wp-content/plugins/wp-ultimate-recipe-…/core/vendor/fraction-js/index.js?ver=2.8.1

js thedisabledchef.com collected 2026-10-09 03:42:46 UTC 12,183 bytes, 395 lines download raw bytes

1/*
2fraction.js
3A Javascript fraction library.
4
5Copyright (c) 2009  Erik Garrison <[email protected]>
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23THE SOFTWARE.
24
25*/
26
27
28/* Fractions */
29/* 
30 *
31 * Fraction objects are comprised of a numerator and a denomenator.  These
32 * values can be accessed at fraction.numerator and fraction.denomenator.
33 *
34 * Fractions are always returned and stored in lowest-form normalized format.
35 * This is accomplished via Fraction.normalize.
36 *
37 * The following mathematical operations on fractions are supported:
38 *
39 * Fraction.equals
40 * Fraction.add
41 * Fraction.subtract
42 * Fraction.multiply
43 * Fraction.divide
44 *
45 * These operations accept both numbers and fraction objects.  (Best results
46 * are guaranteed when the input is a fraction object.)  They all return a new
47 * Fraction object.
48 *
49 * Usage:
50 *
51 * TODO
52 *
53 */
54
55/*
56 * The Fraction constructor takes one of:
57 *   an explicit numerator (integer) and denominator (integer),
58 *   a string representation of the fraction (string),
59 *   or a floating-point number (float)
60 *
61 * These initialization methods are provided for convenience.  Because of
62 * rounding issues the best results will be given when the fraction is
63 * constructed from an explicit integer numerator and denomenator, and not a
64 * decimal number.
65 *
66 *
67 * e.g. new Fraction(1, 2) --> 1/2
68 *      new Fraction('1/2') --> 1/2
69 *      new Fraction('2 3/4') --> 11/4  (prints as 2 3/4)
70 *
71 */
72Fraction = function(numerator, denominator)
73{
74    /* double argument invocation */
75    if (typeof numerator !== 'undefined' && denominator) {
76        if (typeof(numerator) === 'number' && typeof(denominator) === 'number') {
77            this.numerator = numerator;
78            this.denominator = denominator;
79        } else if (typeof(numerator) === 'string' && typeof(denominator) === 'string') {
80            // what are they?
81            // hmm....
82            // assume they are ints?
83            this.numerator = parseInt(numerator);
84            this.denominator = parseInt(denominator);
85        }
86    /* single-argument invocation */
87    } else if (typeof denominator === 'undefined') {
88        num = numerator; // swap variable names for legibility
89        if (typeof(num) === 'number') {  // just a straight number init
90            this.numerator = num;
91            this.denominator = 1;
92        } else if (typeof(num) === 'string') {
93            var a, b;  // hold the first and second part of the fraction, e.g. a = '1' and b = '2/3' in 1 2/3
94                       // or a = '2/3' and b = undefined if we are just passed a single-part number
95            var arr = num.split(' ')
96            if (arr[0]) a = arr[0]
97            if (arr[1]) b = arr[1]
98            /* compound fraction e.g. 'A B/C' */
99            //  if a is an integer ...
100            if (a % 1 === 0 && b && b.match('/')) {
101                return (new Fraction(a)).add(new Fraction(b));
102            } else if (a && !b) {
103                /* simple fraction e.g. 'A/B' */
104                if (typeof(a) === 'string' && a.match('/')) {
105                    // it's not a whole number... it's actually a fraction without a whole part written
106                    var f = a.split('/');
107                    this.numerator = f[0]; this.denominator = f[1];
108                /* string floating point */
109                } else if (typeof(a) === 'string' && a.match('\.')) {
110                    return new Fraction(parseFloat(a));
111                /* whole number e.g. 'A' */
112                } else { // just passed a whole number as a string
113                    this.numerator = parseInt(a);
114                    this.denominator = 1;
115                }
116            } else {
117                return undefined; // could not parse
118            }
119        }
120    }
121    this.normalize();
122}
123
124
125Fraction.prototype.clone = function()
126{
127    return new Fraction(this.numerator, this.denominator);
128}
129
130
131/* pretty-printer, converts fractions into whole numbers and fractions */
132Fraction.prototype.toString = function()
133{
134    if (this.denominator==='NaN') return 'NaN'
135    var wholepart = (this.numerator/this.denominator>0) ?
136      Math.floor(this.numerator / this.denominator) :
137      Math.ceil(this.numerator / this.denominator)
138    var numerator = this.numerator % this.denominator 
139    var denominator = this.denominator;
140    var result = []; 
141    if (wholepart != 0)  
142        result.push(wholepart);
143    if (numerator != 0)  
144        result.push(((wholepart===0) ? numerator : Math.abs(numerator)) + '/' + denominator);
145    return result.length > 0 ? result.join(' ') : 0;
146}
147
148
149/* destructively rescale the fraction by some integral factor */
150Fraction.prototype.rescale = function(factor)
151{
152    this.numerator *= factor;
153    this.denominator *= factor;
154    return this;
155}
156
157
158Fraction.prototype.add = function(b)
159{
160    var a = this.clone();
161    if (b instanceof Fraction) {
162        b = b.clone();
163    } else {
164        b = new Fraction(b);
165    }
166    td = a.denominator;
167    a.rescale(b.denominator);
168    b.rescale(td);
169
170    a.numerator += b.numerator;
171
172    return a.normalize();
173}
174
175
176Fraction.prototype.subtract = function(b)
177{
178    var a = this.clone();
179    if (b instanceof Fraction) {
180        b = b.clone();  // we scale our argument destructively, so clone
181    } else {
182        b = new Fraction(b);
183    }
184    td = a.denominator;
185    a.rescale(b.denominator);
186    b.rescale(td);
187
188    a.numerator -= b.numerator;
189
190    return a.normalize();
191}
192
193
194Fraction.prototype.multiply = function(b)
195{
196    var a = this.clone();
197    if (b instanceof Fraction)
198    {
199        a.numerator *= b.numerator;
200        a.denominator *= b.denominator;
201    } else if (typeof b === 'number') {
202        a.numerator *= b;
203    } else {
204        return a.multiply(new Fraction(b));
205    }
206    return a.normalize();
207}
208
209Fraction.prototype.divide = function(b)
210{
211    var a = this.clone();
212    if (b instanceof Fraction)
213    {
214        a.numerator *= b.denominator;
215        a.denominator *= b.numerator;
216    } else if (typeof b === 'number') {
217        a.denominator *= b;
218    } else {
219        return a.divide(new Fraction(b));
220    }
221    return a.normalize();
222}
223
224Fraction.prototype.equals = function(b)
225{
226    if (!(b instanceof Fraction)) {
227        b = new Fraction(b);
228    }
229    // fractions that are equal should have equal normalized forms
230    var a = this.clone().normalize();
231    var b = b.clone().normalize();
232    return (a.numerator === b.numerator && a.denominator === b.denominator);
233}
234
235
236/* Utility functions */
237
238/* Destructively normalize the fraction to its smallest representation. 
239 * e.g. 4/16 -> 1/4, 14/28 -> 1/2, etc.
240 * This is called after all math ops.
241 */
242Fraction.prototype.normalize = (function()
243{
244
245    var isFloat = function(n)
246    {
247        return (typeof(n) === 'number' && 
248                ((n > 0 && n % 1 > 0 && n % 1 < 1) || 
249                 (n < 0 && n % -1 < 0 && n % -1 > -1))
250               );
251    }
252
253    var roundToPlaces = function(n, places) 
254    {
255        if (!places) {
256            return Math.round(n);
257        } else {
258            var scalar = Math.pow(10, places);
259            return Math.round(n*scalar)/scalar;
260        }
261    }
262        
263    return (function() {
264
265        // XXX hackish.  Is there a better way to address this issue?
266        //
267        /* first check if we have decimals, and if we do eliminate them
268         * multiply by the 10 ^ number of decimal places in the number
269         * round the number to nine decimal places
270         * to avoid js floating point funnies
271         */
272        if (isFloat(this.denominator)) {
273            var rounded = roundToPlaces(this.denominator, 9);
274            var scaleup = Math.pow(10, rounded.toString().split('.')[1].length);
275            this.denominator = Math.round(this.denominator * scaleup); // this !!! should be a whole number
276            //this.numerator *= scaleup;
277            this.numerator *= scaleup;
278        } 
279        if (isFloat(this.numerator)) {
280            var rounded = roundToPlaces(this.numerator, 9);
281            var split = rounded.toString().split('.');
282
283            var scaleup = 0;
284            if(split[1] !== undefined) {
285                scaleup = Math.pow(10, split[1].length);
286            }
287
288            this.numerator = Math.round(this.numerator * scaleup); // this !!! should be a whole number
289            //this.numerator *= scaleup;
290            this.denominator *= scaleup;
291        }
292        var gcf = Fraction.gcf(this.numerator, this.denominator);
293        this.numerator /= gcf;
294        this.denominator /= gcf;
295        if ((this.numerator < 0 && this.denominator < 0) || (this.numerator > 0 && this.denominator < 0)) {
296            this.numerator *= -1;
297            this.denominator *= -1;
298        }
299        return this;
300    });
301
302})();
303
304
305/* Takes two numbers and returns their greatest common factor.
306 */
307Fraction.gcf = function(a, b)
308{
309
310    var common_factors = [];
311    var fa = Fraction.primeFactors(a);
312    var fb = Fraction.primeFactors(b);
313    // for each factor in fa
314    // if it's also in fb
315    // put it into the common factors
316    fa.forEach(function (factor) 
317    { 
318        var i = fb.indexOf(factor);
319        if (i >= 0) {
320            common_factors.push(factor);
321            fb.splice(i,1); // remove from fb
322        }
323    });
324
325    if (common_factors.length === 0)
326        return 1;
327
328    var gcf = (function() {
329        var r = common_factors[0];
330        var i;
331        for (i=1;i<common_factors.length;i++)
332        {
333            r = r * common_factors[i];
334        }
335        return r;
336    })();
337
338    return gcf;
339
340};
341
342
343// Adapted from: 
344// http://www.btinternet.com/~se16/js/factor.htm
345Fraction.primeFactors = function(n) 
346{
347
348    var num = Math.abs(n);
349    var factors = [];
350    var _factor = 2;  // first potential prime factor
351
352    while (_factor * _factor <= num)  // should we keep looking for factors?
353    {      
354      if (num % _factor === 0)  // this is a factor
355        { 
356            factors.push(_factor);  // so keep it
357            num = num/_factor;
357  // and divide our search point by it
358        }
359        else
360        {
361            _factor++;  // and increment
362        }
363    }
364
365    if (num != 1)                    // If there is anything left at the end...
366    {                                // ...this must be the last prime factor
367        factors.push(num);           //    so it too should be recorded
368    }
369
370    return factors;                  // Return the prime factors
371}
372
373
374Fraction.prototype.snap = function(max, threshold) {
375    if (!threshold) threshold = .0001;
376    if (!max) max = 100;
377
378    var negative = (this.numerator < 0);
379    var decimal = this.numerator / this.denominator;
380    var fraction = Math.abs(decimal % 1);
381    var remainder = negative ? Math.ceil(decimal) : Math.floor(decimal);
382
383    for(var denominator = 1; denominator <= max; ++denominator) {
384        for(var numerator = 0; numerator <= max; ++numerator) {
385            var approximation = Math.abs(numerator/denominator);
386            if (Math.abs(approximation - fraction) < threshold) {
387                return new Fraction(remainder * denominator + numerator * (negative ? -1 : 1), denominator);
388            }
389        }
390    }
391
392    return new Fraction(this.numerator, this.denominator);
393};
394
395//module.exports.Fraction = Fraction

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.