RosettaCodeData/Task/Arithmetic-Rational/Groovy/arithmetic-rational-1.groovy

118 lines
3.9 KiB
Groovy
Raw Permalink Normal View History

2018-06-22 20:57:24 +00:00
class Rational extends Number implements Comparable {
2015-02-20 00:35:01 -05:00
final BigInteger num, denom
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
static final Rational ONE = new Rational(1)
static final Rational ZERO = new Rational(0)
2013-04-10 21:29:02 -07:00
Rational(BigDecimal decimal) {
this(
2018-06-22 20:57:24 +00:00
decimal.scale() < 0 ? decimal.unscaledValue() * 10 ** -decimal.scale() : decimal.unscaledValue(),
decimal.scale() < 0 ? 1 : 10 ** decimal.scale()
)
2013-04-10 21:29:02 -07:00
}
2015-02-20 00:35:01 -05:00
Rational(BigInteger n, BigInteger d = 1) {
if (!d || n == null) { n/d }
(num, denom) = reduce(n, d)
2013-04-10 21:29:02 -07:00
}
2015-02-20 00:35:01 -05:00
private List reduce(BigInteger n, BigInteger d) {
2018-06-22 20:57:24 +00:00
BigInteger sign = ((n < 0) ^ (d < 0)) ? -1 : 1
2015-02-20 00:35:01 -05:00
(n, d) = [n.abs(), d.abs()]
BigInteger commonFactor = gcd(n, d)
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
[n.intdiv(commonFactor) * sign, d.intdiv(commonFactor)]
2013-04-10 21:29:02 -07:00
}
2018-06-22 20:57:24 +00:00
Rational toLeastTerms() { reduce(num, denom) as Rational }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
private BigInteger gcd(BigInteger n, BigInteger m) {
n == 0 ? m : { while(m%n != 0) { (n, m) = [m%n, n] }; n }()
}
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
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) }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
Rational next() { [num + denom, denom] }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
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) }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
Rational previous() { [num - denom, denom] }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
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) }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
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) }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
BigInteger intdiv(BigInteger n) { num.intdiv(denom*n) }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
Rational negative() { [-num, denom] }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
Rational abs() { [num.abs(), denom] }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
Rational reciprocal() { new Rational(denom, num) }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
Rational power(BigInteger n) {
def (nu, de) = (n < 0 ? [denom, num] : [num, denom])*.power(n.abs())
new Rational (nu, de)
}
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
boolean asBoolean() { num != 0 }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
BigDecimal toBigDecimal() { (num as BigDecimal)/(denom as BigDecimal) }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
BigInteger toBigInteger() { num.intdiv(denom) }
2013-04-10 21:29:02 -07:00
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) {
2018-06-22 20:57:24 +00:00
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()
2015-02-20 00:35:01 -05:00
default: throw new ClassCastException("Cannot convert from type Rational to type " + type)
2013-04-10 21:29:02 -07:00
}
}
2015-02-20 00:35:01 -05:00
boolean equals(o) { compareTo(o) == 0 }
2013-04-10 21:29:02 -07:00
int compareTo(o) {
2018-06-22 20:57:24 +00:00
o instanceof Rational
? compareTo(o as Rational)
: o instanceof Number
? compareTo(o as Number)
2013-04-10 21:29:02 -07:00
: (Double.NaN as int)
}
2015-02-20 00:35:01 -05:00
int compareTo(Rational r) { num*r.denom <=> denom*r.num }
int compareTo(Number n) { num <=> denom*(n as BigInteger) }
2013-04-10 21:29:02 -07:00
2015-02-20 00:35:01 -05:00
int hashCode() { [num, denom].hashCode() }
2013-04-10 21:29:02 -07:00
String toString() {
2015-02-20 00:35:01 -05:00
"${num}//${denom}"
2013-04-10 21:29:02 -07:00
}
}