class Rational extends Number implements Comparable {
    final BigInteger num, denom

    static final Rational ONE = new Rational(1)
    static final Rational ZERO = new Rational(0)

    Rational(BigDecimal decimal) {
        this(
        decimal.scale() < 0 ? decimal.unscaledValue() * 10 ** -decimal.scale(): decimal.unscaledValue(),
        decimal.scale() < 0 ? 1                                               : 10 ** decimal.scale()
        )
    }

    Rational(BigInteger n, BigInteger d = 1) {
        if (!d || n == null) { n/d }
        (num, denom) = reduce(n, d)
    }

    private List reduce(BigInteger n, BigInteger d) {
        BigInteger sign = ((n < 0) ^ (d < 0)) ? -1: 1
        (n, d) = [n.abs(), d.abs()]
        BigInteger commonFactor = gcd(n, d)

        [n.intdiv(commonFactor) * sign, d.intdiv(commonFactor)]
    }

    Rational toLeastTerms() { reduce(num, denom) as Rational }

    private BigInteger gcd(BigInteger n, BigInteger m) {
        n == 0 ? m: { while(m%n != 0) { (n, m) = [m%n, n] }; n }()
    }

    Rational plus(Rational r) { [num*r.denom + r.num*denom, denom*r.denom] }
    Rational plus(BigInteger n) { [num + n*denom, denom] }
    Rational plus(Number n) { this + ([n] as Rational) }

    Rational next() { [num + denom, denom] }

    Rational minus(Rational r) { [num*r.denom - r.num*denom, denom*r.denom] }
    Rational minus(BigInteger n) { [num - n*denom, denom] }
    Rational minus(Number n) { this - ([n] as Rational) }

    Rational previous() { [num - denom, denom] }

    Rational multiply(Rational r) { [num*r.num, denom*r.denom] }
    Rational multiply(BigInteger n) { [num*n, denom] }
    Rational multiply(Number n) { this * ([n] as Rational) }


    Rational div(Rational r) { new Rational(num*r.denom, denom*r.num) }
    Rational div(BigInteger n) { new Rational(num, denom*n) }
    Rational div(Number n) { this / ([n] as Rational) }

    BigInteger intdiv(BigInteger n) { num.intdiv(denom*n) }

    Rational negative() { [-num, denom] }

    Rational abs() { [num.abs(), denom] }

    Rational reciprocal() { new Rational(denom, num) }

    Rational power(BigInteger n) {
        def (nu, de) = (n < 0 ? [denom, num]: [num, denom])*.power(n.abs())
        new Rational (nu, de)
    }

    boolean asBoolean() { num != 0 }

    BigDecimal toBigDecimal() { (num as BigDecimal)/(denom as BigDecimal) }

    BigInteger toBigInteger() { num.intdiv(denom) }

    Double toDouble() { toBigDecimal().toDouble() }
    double doubleValue() { toDouble() as double }

    Float toFloat() { toBigDecimal().toFloat() }
    float floatValue() { toFloat() as float }

    Integer toInteger() { toBigInteger().toInteger() }
    int intValue() { toInteger() as int }

    Long toLong() { toBigInteger().toLong() }
    long longValue() { toLong() as long }

    Object asType(Class type) {
        switch (type) {
            case this.class:              return this
            case [Boolean, Boolean.TYPE]: return asBoolean()
            case BigDecimal:              return toBigDecimal()
            case BigInteger:              return toBigInteger()
            case [Double, Double.TYPE]:   return toDouble()
            case [Float, Float.TYPE]:     return toFloat()
            case [Integer, Integer.TYPE]: return toInteger()
            case [Long, Long.TYPE]:       return toLong()
            case String:                  return toString()
            default: throw new ClassCastException("Cannot convert from type Rational to type " + type)
        }
    }

    boolean equals(o) { compareTo(o) == 0 }

    int compareTo(o) {
        o instanceof Rational
            ? compareTo(o as Rational)
           : o instanceof Number
                ? compareTo(o as Number)
               : (Double.NaN as int)
    }
    int compareTo(Rational r) { num*r.denom <=> denom*r.num }
    int compareTo(Number n) { num <=> denom*(n as BigInteger) }

    int hashCode() { [num, denom].hashCode() }

    String toString() {
        "${num}