class Rational { readonly number: number readonly denom: number // -------------- public ---------- constructor(n: number, d: number){ this.number = n this.denom = d } add(that): Rational{ return this._translate(that, (this_n, this_d, that_n, that_d)=>{ const n = this_n * that_d + that_n * this_d const d = this_d * that_d return {n, d} }); } sub(that): Rational { return this._translate(that, (this_n, this_d, that_n, that_d)=>{ const n = this_n * that_d - that_n * this_d const d = this_d * that_d return {n, d} }); } mul(that): Rational { return this._translate(that, (this_n, this_d, that_n, that_d)=>{ const n = this_n * that_n const d = this_d * that_d return {n, d} }); } div(that): Rational { return this._translate(that, (this_n, this_d, that_n, that_d)=>{ const n = this_n * that_d const d = this_d * that_n return {n, d} }); } toFloat(){ return this.number / this.denom } // --------------- static ------------ static of(n): Rational { if(n instanceof Rational) { return n; } if(typeof n === 'string'){ n = parseFloat(n) } if(typeof n !== "number"){ throw new Error("invalidate number") } const num = n.toPrecision() const parts = num.split('.') var denom = 1 if(parts.length > 1){ denom = Math.pow(10, parts[1].length) } var number = n * denom return new Rational(number, denom) } // private // private _translate(_that ,fn: (n:number, d:number, that_n:number, that_d:number)=>{n:number, d:number}) { var that = _that if(!(that instanceof Rational)){ that = Rational.of(that) } const this_n = this.number, this_d = this.denom, that_n = that.number, that_d = that.denom; var r = fn(this_n, this_d, that_n, that_d) return new Rational(r.n, r.d) } } function safePlus(a, b){ return Rational.of(a).add(b).toFloat() } // console.log(safePlus(1, 2)) // console.log(safePlus(1.1, 2.1)) // console.log(safePlus(100000.000001, 100000.000001)) console.log(1213.11 * 10000) console.log(safePlus(1213.11, 10000))