export function gcd ( a , b ) { if ( a === 0 || b === 0 ) return 1 ; if ( ! ( Number . isInteger ( a ) && Number . isInteger ( b ) ) ) return 1 ; a = Math . abs ( a ) ; b = Math . abs ( b ) ; let tmp = 0 ; while ( a !== 0 && b !== 0 ) { a = a % b ; tmp = a ; a = b ; b = tmp ; } return a === 0 ? b : a ; } export class Fraction { up : number ; down : number ; constructor ( up , down ) { this . up = up ; this . down = down ; } add ( that ) { return new Fraction ( this . up * that . down + this . down * that . up , this . down * that . down ) ; } addN ( n ) { return new Fraction ( this . up + n * this . down , this . down ) ; } sub ( that ) { return new Fraction ( this . up * that . down - this . down * that . up , this . down * that . down ) ; } subN ( n ) { return new Fraction ( this . up - n * this . down , this . down ) ; } mul ( that ) { return new Fraction ( this . up * that . up , this . down * that . down ) ; } mulN ( n ) { return new Fraction ( this . up * n , this . down ) ; } div ( that ) { if ( that . up === 0 ) { return new Fraction ( this . up * that . down * this . down >= 0 ? Infinity : - Infinity , 1 ) ; } return new Fraction ( this . up * that . down , this . down * that . up ) ; } divN ( n ) { if ( n === 0 ) { return new Fraction ( this . up * n * this . down >= 0 ? Infinity : - Infinity , 1 ) ; } if ( Number . isInteger ( n ) ) { return new Fraction ( this . up , n * this . down ) ; } else { return new Fraction ( this . up / n , this . down ) ; } } floor ( ) { return new Fraction ( Math . floor ( this . up / this . down ) * this . down , this . down ) ; } neg ( ) { return new Fraction ( - this . up , this . down ) ; } toNum ( ) { return this . up / this . down ; } norm ( ) { const g = gcd ( this . up , this . down ) ; if ( this . down < 0 ) { this . down *= - 1 ; this . up *= - 1 ; } this . up /= g ; this . down /= g ; return this ; } toString ( ) { return `${ this . up }/${ this . down }` ; } }