fractions-rs 0.1.4

Fractions numbers implementation for Rust
Documentation
const gcd = require('num-integer').gcd;
const { Integer, Num, NumAssign, One, Signed, Zero } = require('num-traits');

function const_abs(a) {
    if (a < Zero::zero()) {
        return -a;
    } else {
        return a;
    }
}

function gcd_recur(m, n) {
    if (n == Zero::zero()) {
        return const_abs(m);
    } else {
        return gcd_recur(n, m % n);
    }
}

function const_gcd(m, n) {
    if (m == Zero::zero()) {
        return const_abs(n);
    } else {
        return gcd_recur(m, n);
    }
}

class Fraction {
    constructor(numer, denom) {
        this.numer = numer;
        this.denom = denom;
    }

    static new_raw(numer, denom) {
        return new Fraction(numer, denom);
    }

    numer() {
        return this.numer;
    }

    denom() {
        return this.denom;
    }

    static zero() {
        return new Fraction(Zero::zero(), One::one());
    }

    is_zero() {
        return this.numer.is_zero() && !this.denom.is_zero();
    }

    set_zero() {
        this.numer.set_zero();
        this.denom.set_one();
    }

    is_normal() {
        return !(this.numer.is_zero() || this.denom.is_zero());
    }

    is_infinite() {
        return !this.numer.is_zero() && this.denom.is_zero();
    }

    is_nan() {
        return this.numer.is_zero() && this.denom.is_zero();
    }

    static one() {
        return new Fraction(One::one(), One::one());
    }

    is_one() {
        return this.numer == this.denom;
    }

    set_one() {
        this.numer.set_one();
        this.denom.set_one();
    }

    normalize() {
        this.keep_denom_positive();
        return this.reduce();
    }

    abs() {
        if (this.is_negative()) {
            return -this;
        } else {
            return this;
        }
    }

    signum() {
        if (this.is_positive()) {
            return Fraction.one();
        } else if (this.is_zero()) {
            return Fraction.zero();
        } else {
            return -Fraction.one();
        }
    }

    is_positive() {
        return this.numer.is_positive();
    }

    is_negative() {
        return this.numer.is_negative();
    }

    reduce() {
        const common = gcd(this.numer, this.denom);
        if (common != One::one() && common != Zero::zero()) {
            this.numer /= common;
            this.denom /= common;
        }
        return common;
    }

    keep_denom_positive() {
        if (this.denom < Zero::zero()) {
            this.numer = -this.numer;
            this.denom = -this.denom;
        }
    }

    reciprocal() {
        [this.numer, this.denom] = [this.denom, this.numer];
        this.keep_denom_positive();
    }

    cross(rhs) {
        return this.numer * rhs.denom - this.denom * rhs.numer;
    }

    neg() {
        return new Fraction(-this.numer, this.denom);
    }

    inv() {
        let res = this;
        res.reciprocal();
        return res;
    }

    eq(other) {
        return this.denom == One::one() && this.numer == other;
    }

    partial_cmp(other) {
        if (this.denom == One::one() || other == Zero::zero()) {
            return this.numer.partial_cmp(other);
        }
        let lhs = new Fraction(this.numer, other);
        let rhs = this.denom;
        lhs.reduce();
        return lhs.numer.partial_cmp(lhs.denom * rhs);
    }

    cmp(other) {
        if (this.denom == other.denom) {
            return this.numer.cmp(other.numer);
        }
        let lhs = new Fraction(this.numer, other.numer);
        let rhs = new Fraction(this.denom, other.denom);
        lhs.reduce();
        rhs.reduce();
        return (lhs.numer * rhs.denom).cmp(lhs.denom * rhs.numer);
    }

    add_assign(other) {
        if (this.denom == other.denom) {
            this.numer += other.numer;
            this.reduce();
            return;
        }

        let rhs = other;
        [this.denom, rhs.numer] = [rhs.numer, this.denom];
        let common_n = this.reduce();
        let common_d = rhs.reduce();
        [this.denom, rhs.numer] = [rhs.numer, this.denom];
        this.numer = this.numer * rhs.denom + this.denom * rhs.numer;
        this.denom *= rhs.denom;
        [this.denom, common_d] = [common_d, this.denom];
        this.reduce();
        this.numer *= common_n;
        this.denom *= common_d;
        this.reduce();
    }

    sub_assign(other) {
        if (this.denom == other.denom) {
            this.numer -= other.numer;
            this.reduce();
            return;
        }

        let rhs = other;
        [this.denom, rhs.numer] = [rhs.numer, this.denom];
        let common_n = this.reduce();
        let common_d = rhs.reduce();
        [this.denom, rhs.numer] = [rhs.numer, this.denom];
        this.numer = this.cross(rhs);
        this.denom *= rhs.denom;
        [this.denom, common_d] = [common_d, this.denom];
        this.reduce();
        this.numer *= common_n;
        this.denom *= common_d;
        this.reduce();
    }

    mul_assign(other) {
        let rhs = other;
        [this.numer, rhs.numer] = [rhs.numer, this.numer];
        this.reduce();
        rhs.reduce();
        this.numer *= rhs.numer;
        this.denom *= rhs.denom;
    }

    div_assign(other) {
        let rhs = other;
        [this.denom, rhs.numer] = [rhs.numer, this.denom];
        this.normalize();
        rhs.reduce();
        this.numer *= rhs.denom;
        this.denom *= rhs.numer;
    }

    add(other) {
        let res = this;
        res.add_assign(other);
        return res;
    }

    sub(other) {
        let res = this;
        res.sub_assign(other);
        return res;
    }

    mul(other) {
        let res = this;
        res.mul_assign(other);
        return res;
    }

    div(other) {
        let res = this;
        res.div_assign(other);
        return res;
    }
}

module.exports = Fraction;