3
1

More than 5 years have passed since last update.

javascriptで分数クラス

Last updated at Posted at 2019-07-29

C#でも分数class
https://qiita.com/HitsujiRere/items/e49275a42ddda92b510c

こんな記事を見たのでjavascriptで書いてみた。

が、javascriptの場合は数値が整数とは限らないので、小数を渡されることも考慮する必要がある。

そこでこんな感じになった。

const fraction = class {
  constructor(numerator=0, denomitor=1){
    this.n = numerator;
    this.d = denomitor;
    fraction._reduce(this);
  }

  /** 約分 */
  static _reduce(o) {
    const m = fraction._integerizable(o.n, o.d);
    o.n *= m, o.d *= m; // 小数が渡されたら分子分母を整数化
    const g = fraction._gcm(o.n, o.d);
    o.n /=g, o.d /=g;   // 最大公約数で除算
  }
  static _gcm(n, d) {
    for(let i = Math.min(n,d); i > 1; i--) if(n%i==0 && d%i==0) return i;
    return 1;
  }
  static _integerizable(n, d) {
    for(let m = 1; m < Number.MAX_SAFE_INTEGER; m++)
      if (m*n%1==0 && m*d%1==0) return m;
    throw new Error("overflow while reducing ("+n+","+d+")");
  }

  toString()  { return this.n + (this.d>1?("/" + this.d):""); }
  numerize()  { return this.n / this.d; }
  valueOf()   { return this.numerize(); }

  add     (other){
            return new fraction(
                     this.n * other.d + other.n * this.d, 
                     other.d * this.d
                   );
          }
  subtract(other){ return this.add(new fraction(other.n * -1, other.d)); }
  multiply(other){ return new fraction(this.n * other.n, this.d * other.d); }
  divide  (other){ return this.multiply(other.reciprocal()); }

  reciprocal(){ return new fraction(this.d, this.n); }

出来上がったらとりあえずテスト。

const test = (arr)=> arr.forEach(f=>{
  const t=(a,b)=>{
    const stra = a.toString();
    const strb = b.toString();
    console.log(stra + " * " + strb + " = " + a.multiply(b));
    console.log(stra + " / " + strb + " = " + a.divide(b));
    console.log(stra + " + " + strb + " = " + a.add(b));
    console.log(stra + " - " + strb + " = " + a.subtract(b));
  };
  t(f.a, f.b); t(f.b,f.a);
});

test([
  { a:new fraction(5),   b:new fraction(1,2) },
  { a:new fraction(2,3), b:new fraction(1,6) },
  { a:new fraction(1,2), b:new fraction(1,2) },
  { a:new fraction(1/3), b:new fraction(3)   }
]);

今回の気づきとしては「javascriptでは無理数が近似値に有理化されてしまっている」ということ。

[ Math.PI, Math.sqrt(2) ].forEach(e=>{
  console.log(e);
  const o = new fraction(e);
  console.log(o);
  console.log(o.numerize());
});
// Math.PI:      fraction {n: 245850922, d: 78256779}
// Math.sqrt(2); fraction {n: 131836323, d: 93222358}

ついでに小数の文字列表現からもインスタンス化できるようにしてみたが、

fraction.fromString(exp) {
  const arr = exp.split(/[ \/]+/).filter(e=>e.length).map(e=>Number(e));
  if(arr.length < 2) arr.push(1);
  return new fraction(arr[0], arr[1]);
}

こっちの方が簡単だわな。

fraction.fromString(exp) {
  return new fraction(Number(eval(exp)));
}
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1