Branch data Line data Source code
1 [ + ]: 1 : /**
2 : 1 : * @module rational-module
3 : 1 : * @desc A module that defines a Rational class for representing and manipulating rational numbers.
4 : 1 : * @version 1.0.0
5 : 1 : * @author Essam A. El-Sherif
6 : 1 : */
7 : 1 :
8 : 1 : /**
9 : 1 : * @class Rational
10 : 1 : * @static
11 : 1 : * @desc A class for representing and manipulating rational numbers.
12 : 1 : */
13 : 1 : class Rational{
14 : 1 :
15 : 1 : /**
16 : 1 : * @method
17 : 1 : * @static
18 : 1 : * @memberof module:rational-module.Rational
19 : 1 : * @param {number} a - An integer.
20 : 1 : * @param {number} b - An integer.
21 : 1 : * @returns {number} The greatest common divisor of two integers.
22 : 1 : * @desc Calculates the greatest common divisor of two integers.
23 : 1 : */
24 [ + ]: 1 : static gcd(a, b){
25 [ + ][ + ]: 633 : return b === 0 ? a : Rational.gcd(b, a % b);
26 : 633 : }
27 : 1 :
28 : 1 : /**
29 : 1 : * @method
30 : 1 : * @instance
31 : 1 : * @memberof module:rational-module.Rational
32 : 1 : * @param {object|number} arg1 - [Optional] Rational object or numerator.
33 : 1 : * @param {string} arg2 - [Optional] denominator.
34 : 1 : * @desc Constructs a new Rational object.
35 : 1 : * @throws {TypeError} If more than two arguments are given, or invalid argument type is used.
36 : 1 : */
37 [ + ]: 1 : constructor(arg1, arg2){
38 : 286 : switch(arguments.length){
39 [ + ]: 286 : case 0:
40 : 85 : this.den = 1;
41 : 85 : this.num = 0;
42 : 85 : break;
43 [ + ]: 286 : case 1:
44 [ + ][ + ]: 44 : if(typeof arg1 === 'object' && arg1 instanceof Rational){
45 : 8 : this.den = arg1.getDenominator();
46 : 8 : this.num = arg1.getNumerator();
47 [ + ]: 8 : }
48 : 36 : else{
49 : 36 : this.den = 1;
50 : 36 : this.num = this._validate(arg1);
51 [ + ]: 36 : }
52 : 38 : break;
53 [ + ]: 286 : case 2:
54 : 155 : this.den = this._validate(arg2);
55 : 155 : this.num = this._validate(arg1);
56 : 155 : this._normalize();
57 : 155 : break;
58 [ + ]: 286 : default:
59 : 2 : throw TypeError(`Rational: invalid number of arguments`);
60 [ + ]: 286 : }
61 : 277 :
62 : 277 : Object.defineProperty(this, 'den', { enumerable: false });
63 : 277 : Object.defineProperty(this, 'num', { enumerable: false });
64 : 286 : }
65 : 1 :
66 : 1 : /**
67 : 1 : * @method
68 : 1 : * @instance
69 : 1 : * @memberof module:rational-module.Rational
70 : 1 : * @param {any} arg - The argument to be validated as a numerator or denominator.
71 : 1 : * @returns {number} An integer number.
72 : 1 : * @desc Validates the given argument to be used as a numerator or denominator.
73 : 1 : * @throws {TypeError} If the given argument is an invalid numerator or denominator.
74 : 1 : */
75 [ + ]: 1 : _validate(arg){
76 [ + ][ + ]: 457 : if(typeof arg === 'number' && !Number.isNaN(arg)){
77 : 366 : return Math.trunc(arg);
78 [ + ]: 366 : }
79 : 91 : else
80 [ + ][ + ][ + ]: 91 : if(typeof arg === 'string' && arg && !isNaN(arg)){
81 : 29 : return Math.trunc(Number(arg));
82 [ + ]: 29 : }
83 : 62 : else
84 [ + ]: 62 : if(typeof arg === 'bigint'){
85 : 15 : throw TypeError('Rational: BigInt type is not accepted');
86 [ + ]: 15 : }
87 : 47 : else{
88 : 47 : throw TypeError(`Rational: invalid argument`);
89 : 47 : }
90 : 457 : }
91 : 1 :
92 : 1 : /**
93 : 1 : * @method
94 : 1 : * @instance
95 : 1 : * @memberof module:rational-module.Rational
96 : 1 : * @desc Normalizes the rational number i.e. no common factors and denominator is positive.
97 : 1 : * @throws {TypeError} In case of zero denominator.
98 : 1 : */
99 [ + ]: 1 : _normalize(){
100 [ + ]: 159 : if(this.den === 0){
101 : 2 : throw TypeError('Rational: bad rational, zero denominator');
102 [ + ]: 2 : }
103 : 157 : else
104 [ + ]: 157 : if(this.num === 0){
105 : 2 : this.den = 1;
106 [ + ]: 2 : }
107 : 155 : else{
108 : 155 : let g = Math.abs( Rational.gcd(this.num, this.den) );
109 : 155 :
110 : 155 : this.num /= g;
111 : 155 : this.den /= g;
112 : 155 :
113 [ + ]: 155 : if(this.den < 0){
114 : 5 : this.num = -this.num;
115 : 5 : this.den = -this.den;
116 : 5 : }
117 : 155 : }
118 : 159 : }
119 : 1 :
120 : 1 : /**
121 : 1 : * @method
122 : 1 : * @instance
123 : 1 : * @memberof module:rational-module.Rational
124 : 1 : * @desc An accessor function to return the numerator.
125 : 1 : * @returns {number} The numerator.
126 : 1 : */
127 [ + ]: 1 : getNumerator(){ return this.num; }
128 : 1 :
129 : 1 : /**
130 : 1 : * @method
131 : 1 : * @instance
132 : 1 : * @memberof module:rational-module.Rational
133 : 1 : * @desc An accessor function to return the denominator.
134 : 1 : * @returns {number} The denominator.
135 : 1 : */
136 [ + ]: 1 : getDenominator(){ return this.den; }
137 : 1 :
138 : 1 : /**
139 : 1 : * @method
140 : 1 : * @instance
141 : 1 : * @memberof module:rational-module.Rational
142 : 1 : * @param {object|number} arg1 - [Optional] Rational object or numerator.
143 : 1 : * @param {string} arg2 - [Optional] denominator.
144 : 1 : * @desc Assignment to this Rational object.
145 : 1 : * @throws {TypeError} If neither of one or two arguments are given, or invalid argument type is used.
146 : 1 : */
147 [ + ]: 1 : assign(arg1, arg2){
148 : 12 : switch(arguments.length){
149 [ + ]: 12 : case 1:
150 [ + ][ + ]: 3 : if(typeof arg1 === 'object' && arg1 instanceof Rational){
151 : 1 : this.num = arg1.getNumerator();
152 : 1 : this.den = arg1.getDenominator();
153 [ + ]: 1 : }
154 : 2 : else{
155 : 2 : this.num = this._validate(arg1);
156 : 2 : this.den = 1;
157 : 2 : }
158 : 2 : break;
159 [ + ]: 12 : case 2:
160 : 7 : this.num = this._validate(arg1);
161 : 7 : this.den = this._validate(arg2);
162 : 7 : this._normalize();
163 : 7 : break;
164 [ + ]: 12 : default:
165 : 2 : throw TypeError(`Rational: invalid number of arguments`);
166 : 12 : }
167 : 12 : }
168 : 1 :
169 : 1 : /**
170 : 1 : * @method
171 : 1 : * @instance
172 : 1 : * @memberof module:rational-module.Rational
173 : 1 : * @param {object|number} arg - Rational object or integer number.
174 : 1 : * @desc Adds to this Rational object another Rational object or an integer value.
175 : 1 : * @returns {object} The Rational object denoted by this.
176 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
177 : 1 : */
178 [ + ]: 1 : selfAdd(arg){
179 : 9 : switch(arguments.length){
180 [ + ]: 9 : case 1:
181 [ + ][ + ]: 7 : if(typeof arg === 'object' && arg instanceof Rational){
182 : 1 : let r_num = arg.getNumerator();
183 : 1 : let r_den = arg.getDenominator();
184 : 1 :
185 : 1 : let g = Rational.gcd(this.den, r_den);
186 : 1 :
187 : 1 : this.den /= g;
188 : 1 : this.num = this.num * (r_den / g) + r_num * this.den;
189 : 1 :
190 : 1 : g = Math.abs( Rational.gcd(this.num, g) );
191 : 1 : this.num /= g;
192 : 1 : this.den *= (r_den/g);
193 [ + ]: 1 : }
194 : 6 : else{
195 : 6 : arg = this._validate(arg);
196 : 6 : this.num += arg * this.den;
197 [ + ]: 6 : }
198 : 3 : return this;
199 [ + ]: 9 : default:
200 : 2 : throw TypeError(`Rational: invalid number of arguments`);
201 : 9 : }
202 : 9 : }
203 : 1 :
204 : 1 : /**
205 : 1 : * @method
206 : 1 : * @instance
207 : 1 : * @memberof module:rational-module.Rational
208 : 1 : * @param {object|number} arg - Rational object or integer number.
209 : 1 : * @desc Subtracts from this Rational object another Rational object or an integer value.
210 : 1 : * @returns {object} The Rational object denoted by this.
211 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
212 : 1 : */
213 [ + ]: 1 : selfSub(arg){
214 : 9 : switch(arguments.length){
215 [ + ]: 9 : case 1:
216 [ + ][ + ]: 7 : if(typeof arg === 'object' && arg instanceof Rational){
217 : 1 : let r_num = arg.getNumerator();
218 : 1 : let r_den = arg.getDenominator();
219 : 1 :
220 : 1 : let g = Rational.gcd(this.den, r_den);
221 : 1 :
222 : 1 : this.den /= g;
223 : 1 : this.num = this.num * (r_den / g) - r_num * this.den;
224 : 1 :
225 : 1 : g = Math.abs( Rational.gcd(this.num, g) );
226 : 1 : this.num /= g;
227 : 1 : this.den *= (r_den/g);
228 [ + ]: 1 : }
229 : 6 : else{
230 : 6 : arg = this._validate(arg);
231 : 6 : this.num -= arg * this.den;
232 [ + ]: 6 : }
233 : 3 : return this;
234 [ + ]: 9 : default:
235 : 2 : throw TypeError(`Rational: invalid number of arguments`);
236 : 9 : }
237 : 9 : }
238 : 1 :
239 : 1 : /**
240 : 1 : * @method
241 : 1 : * @instance
242 : 1 : * @memberof module:rational-module.Rational
243 : 1 : * @param {object|number} arg - Rational object or integer number.
244 : 1 : * @desc Multiplies this Rational object by another Rational object or an integer value.
245 : 1 : * @returns {object} The Rational object denoted by this.
246 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
247 : 1 : */
248 [ + ]: 1 : selfMul(arg){
249 : 27 : switch(arguments.length){
250 [ + ]: 27 : case 1:
251 [ + ][ + ]: 25 : if(typeof arg === 'object' && arg instanceof Rational){
252 : 19 : let r_num = arg.getNumerator();
253 : 19 : let r_den = arg.getDenominator();
254 : 19 :
255 : 19 : let gcd1 = Math.abs( Rational.gcd(this.num, r_den) );
256 : 19 : let gcd2 = Math.abs( Rational.gcd(r_num, this.den) );
257 : 19 :
258 : 19 : this.num = (this.num/gcd1) * (r_num/gcd2);
259 : 19 : this.den = (this.den/gcd2) * (r_den/gcd1);
260 [ + ]: 19 : }
261 : 6 : else{
262 : 6 : arg = this._validate(arg);
263 : 6 :
264 : 6 : let gcd = Math.abs( Rational.gcd( arg, this.den ) );
265 : 6 : this.num *= arg / gcd;
266 : 6 : this.den /= gcd;
267 [ + ]: 6 : }
268 : 21 : return this;
269 [ + ]: 27 : default:
270 : 2 : throw TypeError(`Rational: invalid number of arguments`);
271 : 27 : }
272 : 27 : }
273 : 1 :
274 : 1 : /**
275 : 1 : * @method
276 : 1 : * @instance
277 : 1 : * @memberof module:rational-module.Rational
278 : 1 : * @param {object|number} arg - Rational object or integer number.
279 : 1 : * @desc Divides this Rational object by another Rational object or an integer value.
280 : 1 : * @returns {object} The Rational object denoted by this.
281 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
282 : 1 : */
283 [ + ]: 1 : selfDiv(arg){
284 : 17 : switch(arguments.length){
285 [ + ]: 17 : case 1:
286 [ + ][ + ]: 15 : if(typeof arg === 'object' && arg instanceof Rational){
287 : 8 :
288 : 8 : let r_num = arg.getNumerator();
289 : 8 : let r_den = arg.getDenominator();
290 : 8 :
291 [ + ]: 8 : if(r_num === 0){
292 : 3 : throw TypeError(`Rational: division by zero`);
293 [ + ]: 3 : }
294 : 5 :
295 [ - ][ + ]: 8 : if(this.num === 0) return this;
296 : 5 :
297 : 5 : let gcd1 = Math.abs( Rational.gcd(this.num, r_num) );
298 : 5 : let gcd2 = Math.abs( Rational.gcd(r_den, this.den) );
299 : 5 :
300 : 5 : this.num = (this.num/gcd1) * (r_den/gcd2);
301 : 5 : this.den = (this.den/gcd2) * (r_num/gcd1);
302 : 5 :
303 [ + ]: 8 : if(this.den < 0){
304 : 3 : this.num = -this.num;
305 : 3 : this.den = -this.den;
306 : 3 : }
307 [ + ]: 8 : }
308 : 7 : else{
309 : 7 : arg = this._validate(arg);
310 : 7 :
311 [ + ]: 7 : if(arg === 0){
312 : 1 : throw TypeError(`Rational: division by zero`);
313 [ + ]: 1 : }
314 : 2 :
315 [ - ][ + ]: 7 : if(this.num == 0) return this;
316 : 2 :
317 : 2 : let gcd = Math.abs( Rational.gcd(this.num, arg) );
318 : 2 : this.num = this.num / gcd;
319 : 2 : this.den *= (arg / gcd);
320 : 2 :
321 [ + ]: 7 : if(this.den < 0){
322 : 1 : this.num = -this.num;
323 : 1 : this.den = -this.den;
324 : 1 : }
325 [ + ]: 7 : }
326 : 7 : return this;
327 [ + ]: 17 : default:
328 : 2 : throw TypeError(`Rational: invalid number of arguments`);
329 : 17 : }
330 : 17 : }
331 : 1 :
332 : 1 : /**
333 : 1 : * @method
334 : 1 : * @instance
335 : 1 : * @memberof module:rational-module.Rational
336 : 1 : * @param {number} arg - Integer number.
337 : 1 : * @desc Raise this Rational object to the power given.
338 : 1 : * @returns {object} The Rational object denoted by this.
339 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
340 : 1 : */
341 [ + ]: 1 : selfPow(arg){
342 : 10 : switch(arguments.length){
343 [ + ]: 10 : case 1:
344 : 8 : arg = this._validate(arg);
345 : 8 :
346 : 8 : let r = new Rational(1);
347 [ + ]: 8 : for(let i = 0; i < Math.abs(arg); i++){
348 : 9 : r = r.selfMul(this);
349 [ + ]: 9 : }
350 [ + ]: 8 : if(arg < 0){
351 : 3 : r = (new Rational(1)).selfDiv(r);
352 [ + ]: 3 : }
353 : 5 :
354 : 5 : this.num = r.getNumerator();
355 : 5 : this.den = r.getDenominator();
356 : 5 : return this;
357 [ + ]: 10 : default:
358 : 2 : throw TypeError(`Rational: invalid number of arguments`);
359 [ - ]: 10 : }
360 : 10 : }
361 : 1 :
362 : 1 : /**
363 : 1 : * @method
364 : 1 : * @instance
365 : 1 : * @memberof module:rational-module.Rational
366 : 1 : * @param {object|number} arg - Rational object or integer number.
367 : 1 : * @desc Adds this Rational object to another Rational object or an integer value.
368 : 1 : * @returns {object} New Rational object.
369 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
370 : 1 : */
371 [ + ]: 1 : add(arg){
372 : 9 : switch(arguments.length){
373 [ + ]: 9 : case 1:
374 : 7 : let _num = this.num;
375 : 7 : let _den = this.den;
376 : 7 :
377 [ + ][ + ]: 7 : if(typeof arg === 'object' && arg instanceof Rational){
378 : 1 : let r_num = arg.getNumerator();
379 : 1 : let r_den = arg.getDenominator();
380 : 1 :
381 : 1 : let g = Rational.gcd(_den, r_den);
382 : 1 :
383 : 1 : _den /= g;
384 : 1 : _num = _num * (r_den / g) + r_num * _den;
385 : 1 :
386 : 1 : g = Math.abs( Rational.gcd(_num, g) );
387 : 1 : _num /= g;
388 : 1 : _den *= (r_den/g);
389 [ + ]: 1 : }
390 : 6 : else{
391 : 6 : arg = this._validate(arg);
392 : 6 : _num += arg * _den;
393 [ + ]: 6 : }
394 : 3 : return new Rational(_num, _den);
395 [ + ]: 9 : default:
396 : 2 : throw TypeError(`Rational: invalid number of arguments`);
397 [ - ]: 9 : }
398 : 9 : }
399 : 1 :
400 : 1 : /**
401 : 1 : * @method
402 : 1 : * @instance
403 : 1 : * @memberof module:rational-module.Rational
404 : 1 : * @param {object|number} arg - Rational object or integer number.
405 : 1 : * @desc Subtracts from this Rational object another Rational object or an integer value.
406 : 1 : * @returns {object} New Rational object.
407 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
408 : 1 : */
409 [ + ]: 1 : sub(arg){
410 : 9 : switch(arguments.length){
411 [ + ]: 9 : case 1:
412 : 7 : let _num = this.num;
413 : 7 : let _den = this.den;
414 : 7 :
415 [ + ][ + ]: 7 : if(typeof arg === 'object' && arg instanceof Rational){
416 : 1 : let r_num = arg.getNumerator();
417 : 1 : let r_den = arg.getDenominator();
418 : 1 :
419 : 1 : let g = Rational.gcd(_den, r_den);
420 : 1 :
421 : 1 : _den /= g;
422 : 1 : _num = _num * (r_den / g) - r_num * _den;
423 : 1 :
424 : 1 : g = Math.abs( Rational.gcd(_num, g) );
425 : 1 : _num /= g;
426 : 1 : _den *= (r_den/g);
427 [ + ]: 1 : }
428 : 6 : else{
429 : 6 : arg = this._validate(arg);
430 : 6 : _num -= arg * _den;
431 [ + ]: 6 : }
432 : 3 : return new Rational(_num, _den);
433 [ + ]: 9 : default:
434 : 2 : throw TypeError(`Rational: invalid number of arguments`);
435 [ - ]: 9 : }
436 : 9 : }
437 : 1 :
438 : 1 : /**
439 : 1 : * @method
440 : 1 : * @instance
441 : 1 : * @memberof module:rational-module.Rational
442 : 1 : * @param {object|number} arg - Rational object or integer number.
443 : 1 : * @desc Multiplies this Rational object by another Rational object or an integer value.
444 : 1 : * @returns {object} New Rational object.
445 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
446 : 1 : */
447 [ + ]: 1 : mul(arg){
448 : 9 : switch(arguments.length){
449 [ + ]: 9 : case 1:
450 : 7 : let _num = this.num;
451 : 7 : let _den = this.den;
452 : 7 :
453 [ + ][ + ]: 7 : if(typeof arg === 'object' && arg instanceof Rational){
454 : 1 : let r_num = arg.getNumerator();
455 : 1 : let r_den = arg.getDenominator();
456 : 1 :
457 : 1 : let gcd1 = Math.abs( Rational.gcd(_num, r_den) );
458 : 1 : let gcd2 = Math.abs( Rational.gcd(r_num, _den) );
459 : 1 :
460 : 1 : _num = (_num/gcd1) * (r_num/gcd2);
461 : 1 : _den = (_den/gcd2) * (r_den/gcd1);
462 [ + ]: 1 : }
463 : 6 : else{
464 : 6 : arg = this._validate(arg);
465 : 6 :
466 : 6 : let gcd = Math.abs( Rational.gcd( arg, _den ) );
467 : 6 : _num *= arg / gcd;
468 : 6 : _den /= gcd;
469 [ + ]: 6 : }
470 : 3 : return new Rational(_num, _den);
471 [ + ]: 9 : default:
472 : 2 : throw TypeError(`Rational: invalid number of arguments`);
473 [ - ]: 9 : }
474 : 9 : }
475 : 1 :
476 : 1 : /**
477 : 1 : * @method
478 : 1 : * @instance
479 : 1 : * @memberof module:rational-module.Rational
480 : 1 : * @param {object|number} arg - Rational object or integer number.
481 : 1 : * @desc Divides this Rational object by another Rational object or an integer value.
482 : 1 : * @returns {object} New Rational object.
483 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
484 : 1 : */
485 [ + ]: 1 : div(arg){
486 : 11 : switch(arguments.length){
487 [ + ]: 11 : case 1:
488 : 9 : let _num = this.num;
489 : 9 : let _den = this.den;
490 : 9 :
491 [ + ][ + ]: 9 : if(typeof arg === 'object' && arg instanceof Rational){
492 : 2 :
493 : 2 : let r_num = arg.getNumerator();
494 : 2 : let r_den = arg.getDenominator();
495 : 2 :
496 [ + ]: 2 : if(r_num === 0){
497 : 1 : throw TypeError(`Rational: division by zero`);
498 : 1 : }
499 : 1 :
500 [ - ][ + ]: 2 : if(_num === 0) return new Rational(_num, _den);
501 : 1 :
502 : 1 : let gcd1 = Math.abs( Rational.gcd(_num, r_num) );
503 : 1 : let gcd2 = Math.abs( Rational.gcd(r_den, _den) );
504 : 1 :
505 : 1 : _num = (_num/gcd1) * (r_den/gcd2);
506 : 1 : _den = (_den/gcd2) * (r_num/gcd1);
507 : 1 :
508 : 1 : if(_den < 0){
509 : 1 : _num = -_num;
510 : 1 : _den = -_den;
511 : 1 : }
512 [ + ]: 2 : }
513 : 7 : else{
514 : 7 : arg = this._validate(arg);
515 : 7 :
516 [ + ]: 7 : if(arg === 0){
517 : 1 : throw TypeError(`Rational: division by zero`);
518 [ + ]: 1 : }
519 : 2 :
520 [ - ][ + ]: 7 : if(_num == 0) return this;
521 : 2 :
522 : 2 : let gcd = Math.abs( Rational.gcd(_num, arg) );
523 : 2 : _num = _num / gcd;
524 : 2 : _den *= (arg / gcd);
525 : 2 :
526 [ + ]: 7 : if(_den < 0){
527 : 1 : _num = -_num;
528 : 1 : _den = -_den;
529 : 1 : }
530 [ + ]: 7 : }
531 : 3 : return new Rational(_num, _den);
532 [ + ]: 11 : default:
533 : 2 : throw TypeError(`Rational: invalid number of arguments`);
534 [ - ]: 11 : }
535 : 11 : }
536 : 1 :
537 : 1 : /**
538 : 1 : * @method
539 : 1 : * @instance
540 : 1 : * @memberof module:rational-module.Rational
541 : 1 : * @param {number} arg - Integer number.
542 : 1 : * @desc Raise this Rational object to the power given.
543 : 1 : * @returns {object} New Rational object.
544 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
545 : 1 : */
546 [ + ]: 1 : pow(arg){
547 : 10 : switch(arguments.length){
548 [ + ]: 10 : case 1:
549 : 8 : arg = this._validate(arg);
550 : 8 :
551 : 8 : let r = new Rational(1);
552 [ + ]: 8 : for(let i = 0; i < Math.abs(arg); i++){
553 : 9 : r = r.selfMul(this);
554 [ + ]: 9 : }
555 [ + ]: 8 : if(arg < 0){
556 : 3 : r = (new Rational(1)).selfDiv(r);
557 [ + ]: 3 : }
558 : 5 :
559 : 5 : return new Rational(r.getNumerator(), r.getDenominator());
560 [ + ]: 10 : default:
561 : 2 : throw TypeError(`Rational: invalid number of arguments`);
562 [ - ]: 10 : }
563 : 10 : }
564 : 1 :
565 : 1 : /**
566 : 1 : * @method
567 : 1 : * @instance
568 : 1 : * @memberof module:rational-module.Rational
569 : 1 : * @desc Increment and return this Rational object.
570 : 1 : * @returns {object} The Rational object denoted by this.
571 : 1 : * @throws {TypeError} If an argument was given.
572 : 1 : */
573 [ + ]: 1 : preInc(){
574 [ + ]: 4 : if(arguments.length > 0){
575 : 1 : throw TypeError(`Rational: invalid number of arguments`);
576 [ + ]: 1 : }
577 : 3 : this.num += this.den;
578 : 3 : return this;
579 : 4 : }
580 : 1 :
581 : 1 : /**
582 : 1 : * @method
583 : 1 : * @instance
584 : 1 : * @memberof module:rational-module.Rational
585 : 1 : * @desc Decrement and return this Rational object.
586 : 1 : * @returns {object} The Rational object denoted by this.
587 : 1 : * @throws {TypeError} If an argument was given.
588 : 1 : */
589 [ + ]: 1 : preDec(){
590 [ + ]: 4 : if(arguments.length > 0){
591 : 1 : throw TypeError(`Rational: invalid number of arguments`);
592 [ + ]: 1 : }
593 : 3 : this.num -= this.den;
594 : 3 : return this;
595 : 4 : }
596 : 1 :
597 : 1 : /**
598 : 1 : * @method
599 : 1 : * @instance
600 : 1 : * @memberof module:rational-module.Rational
601 : 1 : * @desc Return this Rational object, then increment it.
602 : 1 : * @returns {object} Copy of this Rational object before increment.
603 : 1 : * @throws {TypeError} If an argument was given.
604 : 1 : */
605 [ + ]: 1 : postInc(){
606 [ + ]: 4 : if(arguments.length > 0){
607 : 1 : throw TypeError(`Rational: invalid number of arguments`);
608 [ + ]: 1 : }
609 : 3 : let t = new Rational(this);
610 : 3 : this.num += this.den;
611 : 3 : return t;
612 : 4 : }
613 : 1 :
614 : 1 : /**
615 : 1 : * @method
616 : 1 : * @instance
617 : 1 : * @memberof module:rational-module.Rational
618 : 1 : * @desc Return this Rational object, then decrement it.
619 : 1 : * @returns {object} Copy of this Rational object before decrement.
620 : 1 : * @throws {TypeError} If an argument was given.
621 : 1 : */
622 [ + ]: 1 : postDec(){
623 [ + ]: 4 : if(arguments.length > 0){
624 : 1 : throw TypeError(`Rational: invalid number of arguments`);
625 [ + ]: 1 : }
626 : 3 : let t = new Rational(this);
627 : 3 : this.num -= this.den;
628 : 3 : return t;
629 : 4 : }
630 : 1 :
631 : 1 : /**
632 : 1 : * @method
633 : 1 : * @instance
634 : 1 : * @memberof module:rational-module.Rational
635 : 1 : * @desc Set this Rational object to its absolute value.
636 : 1 : * @returns {object} The Rational object denoted by this.
637 : 1 : * @throws {TypeError} If an argument was given.
638 : 1 : */
639 [ + ]: 1 : selfAbs(){
640 [ + ]: 3 : if(arguments.length > 0){
641 : 1 : throw TypeError(`Rational: invalid number of arguments`);
642 [ + ]: 1 : }
643 [ + ][ + ]: 3 : if(this.num < 0) this.num = -this.num;
644 : 2 : return this;
645 : 3 : }
646 : 1 :
647 : 1 : /**
648 : 1 : * @method
649 : 1 : * @instance
650 : 1 : * @memberof module:rational-module.Rational
651 : 1 : * @desc Negate this Rational object sign.
652 : 1 : * @returns {object} The Rational object denoted by this.
653 : 1 : * @throws {TypeError} If an argument was given.
654 : 1 : */
655 [ + ]: 1 : selfNeg(){
656 [ + ]: 3 : if(arguments.length > 0){
657 : 1 : throw TypeError(`Rational: invalid number of arguments`);
658 [ + ]: 1 : }
659 : 2 : if(this.num !== 0) this.num = -this.num;
660 : 2 : return this;
661 : 3 : }
662 : 1 :
663 : 1 : /**
664 : 1 : * @method
665 : 1 : * @instance
666 : 1 : * @memberof module:rational-module.Rational
667 : 1 : * @desc Returns absolute value of Rational object.
668 : 1 : * @returns {object} New Rational object.
669 : 1 : * @throws {TypeError} If an argument was given.
670 : 1 : */
671 [ + ]: 1 : abs(){
672 [ + ]: 3 : if(arguments.length > 0){
673 : 1 : throw TypeError(`Rational: invalid number of arguments`);
674 [ + ]: 1 : }
675 [ + ]: 3 : if(this.num < 0) return new Rational(-this.num, this.den);
676 : 1 : return new Rational(this.num, this.den);;
677 : 3 : }
678 : 1 :
679 : 1 : /**
680 : 1 : * @method
681 : 1 : * @instance
682 : 1 : * @memberof module:rational-module.Rational
683 : 1 : * @desc Returns negate of this Rational object sign.
684 : 1 : * @returns {object} New Rational object.
685 : 1 : * @throws {TypeError} If an argument was given.
686 : 1 : */
687 [ + ]: 1 : neg(){
688 [ + ]: 3 : if(arguments.length > 0){
689 : 1 : throw TypeError(`Rational: invalid number of arguments`);
690 [ + ]: 1 : }
691 [ - ]: 2 : if(this.num !== 0) return new Rational(-this.num, this.den);
692 : 0 : return new Rational(this.num, this.den);
693 : 3 : }
694 : 1 :
695 : 1 : /**
696 : 1 : * @method
697 : 1 : * @instance
698 : 1 : * @memberof module:rational-module.Rational
699 : 1 : * @desc Returns true if this Rational object is zero, false otherwise.
700 : 1 : * @returns {boolean} True if this Rational object is zero, false otherwise.
701 : 1 : * @throws {TypeError} If an argument was given.
702 : 1 : */
703 [ + ]: 1 : not(){
704 [ + ]: 3 : if(arguments.length > 0){
705 : 1 : throw TypeError(`Rational: invalid number of arguments`);
706 [ + ]: 1 : }
707 : 2 : return !this.num;
708 : 3 : }
709 : 1 :
710 : 1 : /**
711 : 1 : * @method
712 : 1 : * @instance
713 : 1 : * @memberof module:rational-module.Rational
714 : 1 : * @desc Returns true if this Rational object is not zero, false otherwise.
715 : 1 : * @returns {boolean} True if this Rational object is not zero, false otherwise.
716 : 1 : * @throws {TypeError} If an argument was given.
717 : 1 : */
718 [ + ]: 1 : bool(){
719 [ + ]: 3 : if(arguments.length > 0){
720 : 1 : throw TypeError(`Rational: invalid number of arguments`);
721 [ + ]: 1 : }
722 : 2 : return !!this.num;
723 : 3 : }
724 : 1 :
725 : 1 : /**
726 : 1 : * @method
727 : 1 : * @instance
728 : 1 : * @memberof module:rational-module.Rational
729 : 1 : * @param {object|number} arg - Rational object or integer number.
730 : 1 : * @desc Compare this Rational object to the given argument.
731 : 1 : * @returns {boolean} True if this Rational object is less than the given argument.
732 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
733 : 1 : */
734 [ + ]: 1 : lessThan(arg){
735 : 18 : switch(arguments.length){
736 [ + ]: 18 : case 1:
737 [ + ][ + ]: 16 : if(typeof arg === 'object' && arg instanceof Rational){
738 : 8 :
739 : 8 : let ts = {
740 : 8 : n: this.num,
741 : 8 : d: this.den,
742 : 8 : q: Math.trunc(this.num / this.den),
743 : 8 : r: this.num % this.den
744 : 8 : };
745 : 8 :
746 : 8 : let rs = {
747 : 8 : n: arg.getNumerator(),
748 : 8 : d: arg.getDenominator(),
749 : 8 : q: Math.trunc(arg.getNumerator() / arg.getDenominator()),
750 : 8 : r: arg.getNumerator() % arg.getDenominator()
751 : 8 : };
752 : 8 :
753 [ + ]: 8 : while (ts.r < 0){ ts.r += ts.d; --ts.q; }
754 [ + ]: 8 : while (rs.r < 0){ rs.r += rs.d; --rs.q; }
755 : 8 :
756 : 8 : let reverse = 0x0;
757 : 8 :
758 : 8 : for( ;; ){
759 : 8 : if(ts.q !== rs.q){
760 [ - ]: 8 : return reverse ? ts.q > rs.q : ts.q < rs.q;
761 [ - ]: 8 : }
762 : 0 :
763 : 0 : reverse ^= 0x1;
764 : 0 :
765 [ - ]: 8 : if(ts.r === 0 || rs.r === 0) break;
766 : 0 :
767 : 0 : ts.n = ts.d; ts.d = ts.r;
768 : 0 : ts.q = Math.trunc(ts.n / ts.d); ts.r = ts.n % ts.d;
769 : 0 : rs.n = rs.d; rs.d = rs.r;
770 : 0 : rs.q = Math.trunc(rs.n / rs.d); rs.r = rs.n % rs.d;
771 : 0 : }
772 : 0 :
773 : 0 : if(ts.r === rs.r)
774 : 0 : return false;
775 : 0 : else
776 : 0 : return ( ts.r !== zero ) !== ( !!reverse );
777 [ + ]: 8 : }
778 : 8 : else{
779 : 8 : arg = this._validate(arg);
780 : 8 :
781 : 8 : let q = Math.trunc(this.num / this.den);
782 : 8 : let r = this.num % this.den;
783 : 8 :
784 [ + ][ + ]: 8 : while(r < 0){ r += this.den; --q; }
785 : 4 :
786 : 4 : return q < arg;
787 : 4 : }
788 [ + ]: 18 : default:
789 : 2 : throw TypeError(`Rational: invalid number of arguments`);
790 : 18 : }
791 : 18 : }
792 : 1 :
793 : 1 : /**
794 : 1 : * @method
795 : 1 : * @instance
796 : 1 : * @memberof module:rational-module.Rational
797 : 1 : * @param {object|number} arg - Rational object or integer number.
798 : 1 : * @desc Compare this Rational object to the given argument.
799 : 1 : * @returns {boolean} True if this Rational object is greater than the given argument.
800 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
801 : 1 : */
802 [ + ]: 1 : greaterThan(arg){
803 : 12 : switch(arguments.length){
804 [ + ]: 12 : case 1:
805 [ + ][ + ]: 10 : if(typeof arg === 'object' && arg instanceof Rational){
806 [ + ]: 4 : return !(this.lessThan(arg) || this.equalTo(arg));
807 [ + ]: 4 : }
808 : 6 : else{
809 : 6 : arg = this._validate(arg);
810 [ + ]: 6 : return !(this.lessThan(arg) || this.equalTo(arg));
811 : 6 : }
812 [ + ]: 12 : default:
813 : 2 : throw TypeError(`Rational: invalid number of arguments`);
814 : 12 : }
815 : 12 : }
816 : 1 :
817 : 1 : /**
818 : 1 : * @method
819 : 1 : * @instance
820 : 1 : * @memberof module:rational-module.Rational
821 : 1 : * @param {object|number} arg - Rational object or integer number.
822 : 1 : * @desc Compare this Rational object to the given argument.
823 : 1 : * @returns {boolean} True if this Rational object is equal to the given argument.
824 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
825 : 1 : */
826 [ + ]: 1 : equalTo(arg){
827 : 21 : switch(arguments.length){
828 [ + ]: 21 : case 1:
829 [ + ][ + ]: 19 : if(typeof arg === 'object' && arg instanceof Rational){
830 [ + ]: 10 : return this.num === arg.getNumerator() && this.den === arg.getDenominator();
831 [ + ]: 10 : }
832 : 9 : else{
833 : 9 : arg = this._validate(arg);
834 [ + ]: 9 : return this.num === arg && this.den === 1;
835 : 9 : }
836 [ + ]: 21 : default:
837 : 2 : throw TypeError(`Rational: invalid number of arguments`);
838 : 21 : }
839 : 21 : }
840 : 1 :
841 : 1 : /**
842 : 1 : * @method
843 : 1 : * @instance
844 : 1 : * @memberof module:rational-module.Rational
845 : 1 : * @param {object|number} arg - Rational object or integer number.
846 : 1 : * @desc Compare this Rational object to the given argument.
847 : 1 : * @returns {boolean} True if this Rational object is not equal to the given argument.
848 : 1 : * @throws {TypeError} If other than one arguments is given, or invalid argument type is used.
849 : 1 : */
850 [ + ]: 1 : notEqualTo(arg){
851 : 12 : switch(arguments.length){
852 [ + ]: 12 : case 1:
853 [ + ][ + ]: 10 : if(typeof arg === 'object' && arg instanceof Rational){
854 : 4 : return !this.equalTo(arg);
855 [ + ]: 4 : }
856 : 6 : else{
857 : 6 : arg = this._validate(arg);
858 : 6 : return !this.equalTo(arg);
859 : 6 : }
860 [ + ]: 12 : default:
861 : 2 : throw TypeError(`Rational: invalid number of arguments`);
862 : 12 : }
863 : 12 : }
864 : 1 :
865 : 1 : /**
866 : 1 : * @method
867 : 1 : * @instance
868 : 1 : * @memberof module:rational-module.Rational
869 : 1 : * @desc Returns this Rational object converted to a real number.
870 : 1 : * @returns {number} Real number.
871 : 1 : * @throws {TypeError} If an argument was given.
872 : 1 : */
873 [ + ]: 1 : valueOf(){
874 [ + ]: 7 : if(arguments.length > 0){
875 : 1 : throw TypeError(`Rational: invalid number of arguments`);
876 [ + ]: 1 : }
877 : 6 : return this.num / this.den;
878 : 7 : }
879 : 1 :
880 [ + ]: 1 : toString(){
881 [ + ]: 5 : if(arguments.length > 0){
882 : 1 : throw TypeError(`Rational: invalid number of arguments`);
883 [ + ]: 1 : }
884 [ + ][ + ]: 5 : return `${this.num < 0 ? '-' : ''}${Math.abs(this.num)}/${this.den}`;
885 : 5 : }
886 : 1 : }
887 : 1 :
888 : 1 : module.exports.Rational = Rational;
|