LCOV - code coverage report
Current view: top level - test - rational.module.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 873 888 98.3 %
Date: 2025-08-30 09:52:33 Functions: 33 33 100.0 %
Branches: 196 210 93.3 %

           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;

Generated by: LCOV version 1.14