Arithmetic/Rational: Difference between revisions

(→‎{{header|Groovy}}: new solution)
Line 579:
 
[insert implementation here]
 
=={{header|Groovy}}==
Groovy does not provide any built-in facility for rational arithmetic. However, it does support arithmetic operator overloading. Thus it is not too hard to build a fairly robust, complete, and intuitive rational number class, such as the following:
<lang groovy>class Rational implements Comparable {
final BigInteger numerator, denominator
static final Rational ONE = new Rational(1, 1)
static final Rational ZERO = new Rational(0, 1)
Rational(BigInteger whole) { this(whole, 1) }
Rational(BigDecimal decimal) {
this(
decimal.scale() < 0 ? decimal.unscaledValue()*10**(-decimal.scale()) : decimal.unscaledValue(),
decimal.scale() < 0 ? 1 : 10**(decimal.scale())
)
}
Rational(num, denom) { assert denom != 0 : "Denominator must not be 0"; def values = reduce(num, denom); numerator = values[0]; denominator = values[1] }
private List reduce(BigInteger num, BigInteger denom) {
BigInteger sign = ((num < 0) != (denom < 0)) ? -1 : 1
num = num.abs()
denom = denom.abs()
BigInteger commonFactor = gcd(num, denom)
[num.intdiv(commonFactor) * sign, denom.intdiv(commonFactor)]
}
private BigInteger gcd(BigInteger n, BigInteger m) { n == 0 ? m : { while(m%n != 0) { def t=n; n=m%n; m=t }; n }() }
Rational plus (Rational r) { new Rational(numerator*r.denominator + r.numerator*denominator, denominator*r.denominator) }
Rational plus (BigInteger n) { new Rational(numerator + n*denominator, denominator) }
Rational next () { new Rational(numerator + denominator, denominator) }
Rational minus (Rational r) { new Rational(numerator*r.denominator - r.numerator*denominator, denominator*r.denominator) }
Rational minus (BigInteger n) { new Rational(numerator - n*denominator, denominator) }
Rational previous () { new Rational(numerator - denominator, denominator) }
Rational multiply (Rational r) { new Rational(numerator*r.numerator, denominator*r.denominator) }
Rational multiply (BigInteger n) { new Rational(numerator*n, denominator) }
Rational div (Rational r) { new Rational(numerator*r.denominator, denominator*r.numerator) }
Rational div (BigInteger n) { new Rational(numerator, denominator*n) }
BigInteger intdiv (BigInteger n) { numerator.intdiv(denominator*n) }
Rational negative () { new Rational(-numerator, denominator) }
Rational abs () { new Rational(numerator.abs(), denominator) }
Rational reciprocal() { new Rational(denominator, numerator) }
Rational power(BigInteger n) { new Rational(numerator ** n, denominator ** n) }
boolean asBoolean() { numerator != 0 }
BigDecimal toBigDecimal() { (numerator as BigDecimal)/(denominator as BigDecimal) }
BigInteger toBigInteger() { numerator.intdiv(denominator) }
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.getClass(): return this
case Boolean.class: return asBoolean()
case BigDecimal.class: return toBigDecimal()
case BigInteger.class: return toBigInteger()
case Double.class: return toDouble()
case Float.class: return toFloat()
case Integer.class: return toInteger()
case Long.class: return toLong()
case String.class: 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) { numerator*r.denominator <=> denominator*r.numerator }
int compareTo(Number n) { numerator <=> denominator*(n as BigInteger) }
int hashCode() { [numerator, denominator].hashCode() }
String toString() { "${numerator}//${denominator}" }
}</lang>
 
The following script tests some of this class's features:
<lang groovy style="height:30ex;overflow:scroll;">def x = new Rational(5, 20)
def y = new Rational(9, 12)
def z = new Rational(0, 10000)
 
println x
println y
println z
println (x <=> y)
println ((x as Rational).compareTo(y))
assert x*3 == y
assert (z + 1) <= y*4
assert x != y
 
println "x + y == ${x} + ${y} == ${x + y}"
println "x + z == ${x} + ${z} == ${x + z}"
println "x - y == ${x} - ${y} == ${x - y}"
println "x - z == ${x} - ${z} == ${x - z}"
println "x * y == ${x} * ${y} == ${x * y}"
println "y ** 3 == ${y} ** 3 == ${y ** 3}"
println "x * z == ${x} * ${z} == ${x * z}"
println "x / y == ${x} / ${y} == ${x / y}"
try { print "x / z == ${x} / ${z} == "; println "${x / z}" }
catch (Throwable t) { println t.message }
 
println "-x == -${x} == ${-x}"
println "-y == -${y} == ${-y}"
println "-z == -${z} == ${-z}"
 
print "x as int == ${x} as int == "; println x.intValue()
print "x as double == ${x} as double == "; println x.doubleValue()
print "1 / x as int == 1 / ${x} as int == "; println x.reciprocal().intValue()
print "1.0 / x == 1.0 / ${x} == "; println x.reciprocal().doubleValue()
print "y as int == ${y} as int == "; println y.intValue()
print "y as double == ${y} as double == "; println y.doubleValue()
print "1 / y as int == 1 / ${y} as int == "; println y.reciprocal().intValue()
print "1.0 / y == 1.0 / ${y} == "; println y.reciprocal().doubleValue()
print "z as int == ${z} as int == "; println z.intValue()
print "z as double == ${z} as double == "; println z.doubleValue()
try { print "1 / z as int == 1 / ${z} as int == "; println z.reciprocal().intValue() }
catch (Throwable t) { println t.message }
try { print "1.0 / z == 1.0 / ${z} == "; println z.reciprocal().doubleValue() }
catch (Throwable t) { println t.message }
 
println "++x == ++ ${x} == ${++x}"
println "++y == ++ ${y} == ${++y}"
println "++z == ++ ${z} == ${++z}"
println "-- --x == -- -- ${x} == ${-- (--x)}"
println "-- --y == -- -- ${y} == ${-- (--y)}"
println "-- --z == -- -- ${z} == ${-- (--z)}"
println x
println y
println z
 
println (x <=> y)
assert x*3 == y
assert (z + 1) <= y*4
assert (x < y)
 
println (new Rational(25))
println (new Rational(25.0))
println (new Rational(0.25))
 
println Math.PI
println (new Rational(Math.PI))
println ((new Rational(Math.PI)).toBigDecimal())
println ((new Rational(Math.PI)) as BigDecimal)
println ((new Rational(Math.PI)) as Double)
println ((new Rational(Math.PI)) as double)
println ((new Rational(Math.PI)) as boolean)
println (z as boolean)
try { println ((new Rational(Math.PI)) as Date) }
catch (Throwable t) { println t.message }
try { println ((new Rational(Math.PI)) as char) }
catch (Throwable t) { println t.message }</lang>
 
Output:
<pre style="height:30ex;overflow:scroll;">1//4
3//4
0//1
-1
-1
x + y == 1//4 + 3//4 == 1//1
x + z == 1//4 + 0//1 == 1//4
x - y == 1//4 - 3//4 == -1//2
x - z == 1//4 - 0//1 == 1//4
x * y == 1//4 * 3//4 == 3//16
y ** 3 == 3//4 ** 3 == 27//64
x * z == 1//4 * 0//1 == 0//1
x / y == 1//4 / 3//4 == 1//3
x / z == 1//4 / 0//1 == Denominator must not be 0. Expression: (denom != 0). Values: denom = 0
-x == -1//4 == -1//4
-y == -3//4 == -3//4
-z == -0//1 == 0//1
x as int == 1//4 as int == 0
x as double == 1//4 as double == 0.25
1 / x as int == 1 / 1//4 as int == 4
1.0 / x == 1.0 / 1//4 == 4.0
y as int == 3//4 as int == 0
y as double == 3//4 as double == 0.75
1 / y as int == 1 / 3//4 as int == 1
1.0 / y == 1.0 / 3//4 == 1.3333333333
z as int == 0//1 as int == 0
z as double == 0//1 as double == 0.0
1 / z as int == 1 / 0//1 as int == Denominator must not be 0. Expression: (denom != 0). Values: denom = 0
1.0 / z == 1.0 / 0//1 == Denominator must not be 0. Expression: (denom != 0). Values: denom = 0
++x == ++ 1//4 == 5//4
++y == ++ 3//4 == 7//4
++z == ++ 0//1 == 1//1
-- --x == -- -- 5//4 == -3//4
-- --y == -- -- 7//4 == -1//4
-- --z == -- -- 1//1 == -1//1
1//4
3//4
0//1
-1
25//1
25//1
1//4
3.141592653589793
884279719003555//281474976710656
3.141592653589793115997963468544185161590576171875
3.141592653589793115997963468544185161590576171875
3.141592653589793
3.141592653589793
true
false
Cannot convert from type Rational to type class java.util.Date
Cannot convert from type Rational to type class java.lang.Character</pre>
 
(solution to "perfect numbers &lt; 2<sup>19</sup>" will go here soon --[[User:Balrog|Balrog]] 06:19, 25 February 2011 (UTC))
 
=={{header|Haskell}}==
Anonymous user