Arithmetic/Rational: Difference between revisions

Content added Content deleted
(→‎{{header|Groovy}}: various code improvements)
Line 1,040: Line 1,040:
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:
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 {
<lang groovy>class Rational implements Comparable {
final BigInteger numerator, denominator
final BigInteger num, denom

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

static final Rational ZERO = new Rational(0, 1)
Rational(BigInteger whole) { this(whole, 1) }
Rational(BigDecimal decimal) {
Rational(BigDecimal decimal) {
this(
this(
decimal.scale() < 0 ? decimal.unscaledValue()*10**(-decimal.scale()) : decimal.unscaledValue(),
decimal.scale() < 0 ? decimal.unscaledValue()*10**(-decimal.scale()) : decimal.unscaledValue(),
decimal.scale() < 0 ? 1 : 10**(decimal.scale())
decimal.scale() < 0 ? 1 : 10**(decimal.scale()))
)
}
}

Rational(num, denom) {
Rational(BigInteger n, BigInteger d = 1) {
assert denom != 0 : "Denominator must not be 0"
if (!d || n == null) { n/d }
def values = denom > 0 ? [num, denom] : [-num, -denom] //reduce(num, denom)
(num, denom) = reduce(n, d)
numerator = values[0]
denominator = values[1]
}
}

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

BigInteger commonFactor = gcd(num, denom)
[n.intdiv(commonFactor) * sign, d.intdiv(commonFactor)]
[num.intdiv(commonFactor) * sign, denom.intdiv(commonFactor)]
}
}

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

def reduced = reduce(numerator, denominator)
private BigInteger gcd(BigInteger n, BigInteger m) {
new Rational(reduced[0], reduced[1])
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] }
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(BigInteger n) { [num + n*denom, denom] }
Rational plus (Rational r) { new Rational(numerator*r.denominator + r.numerator*denominator, denominator*r.denominator) }
Rational plus(Number n) { this + ([n] as Rational) }

Rational plus (BigInteger n) { new Rational(numerator + n*denominator, denominator) }
Rational next() { [num + denom, denom] }

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

Rational minus (BigInteger n) { new Rational(numerator - n*denominator, denominator) }
Rational previous() { [num - denom, denom] }

Rational previous () { new Rational(numerator - denominator, denominator) }
Rational multiply(Rational r) { [num*r.num, denom*r.denom] }
Rational multiply(BigInteger n) { [num*n, denom] }
Rational multiply (Rational r) { new Rational(numerator*r.numerator, denominator*r.denominator) }
Rational multiply(Number n) { this * ([n] as Rational) }


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

Rational div (BigInteger n) { new Rational(numerator, denominator*n) }
BigInteger intdiv(BigInteger n) { num.intdiv(denom*n) }

BigInteger intdiv (BigInteger n) { numerator.intdiv(denominator*n) }
Rational negative() { [-num, denom] }

Rational negative () { new Rational(-numerator, denominator) }
Rational abs() { [num.abs(), denom] }

Rational abs () { new Rational(numerator.abs(), denominator) }
Rational reciprocal() { new Rational(denom, num) }

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

boolean asBoolean() { num != 0 }
BigDecimal toBigDecimal() { (numerator as BigDecimal)/(denominator as BigDecimal) }

BigDecimal toBigDecimal() { (num as BigDecimal)/(denom as BigDecimal) }
BigInteger toBigInteger() { numerator.intdiv(denominator) }

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

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

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

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

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

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

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

compareTo(o) == 0
}
int compareTo(o) {
int compareTo(o) {
o instanceof Rational \
o instanceof Rational \
Line 1,157: Line 1,146:
: (Double.NaN as int)
: (Double.NaN as int)
}
}
int compareTo(Rational r) { num*r.denom <=> denom*r.num }
int compareTo(Rational r) { numerator*r.denominator <=> denominator*r.numerator }
int compareTo(Number n) { num <=> denom*(n as BigInteger) }

int compareTo(Number n) { numerator <=> denominator*(n as BigInteger) }
int hashCode() { [num, denom].hashCode() }

int hashCode() { [numerator, denominator].hashCode() }
String toString() {
String toString() {
"${num}//${denom}"
def reduced = reduce(numerator, denominator)
"${reduced[0]}//${reduced[1]}"
}
}
}</lang>
}</lang>

The following script tests some of this class's features:
The following ''RationalCategory'' class allows for modification of regular ''Number'' behavior when interacting with ''Rational''.
<lang groovy>def x = new Rational(5, 20)
<lang groovy>import org.codehaus.groovy.runtime.DefaultGroovyMethods
def y = new Rational(9, 12)

def z = new Rational(0, 10000)
class RationalCategory {
static Rational plus (Number a, Rational b) { ([a] as Rational) + b }
static Rational minus (Number a, Rational b) { ([a] as Rational) - b }
static Rational multiply (Number a, Rational b) { ([a] as Rational) * b }
static Rational div (Number a, Rational b) { ([a] as Rational) / b }

static <T> T asType (Number a, Class<T> type) {
type == Rational \
? [a] as Rational
: DefaultGroovyMethods.asType(a, type)
}
}</lang>

Test Program (mixes the ''RationalCategory'' methods into the ''Number'' class):
<lang groovy>Number.metaClass.mixin RationalCategory

def x = [5, 20] as Rational
def y = [9, 12] as Rational
def z = [0, 10000] as Rational


println x
println x
Line 1,178: Line 1,183:
println z
println z
println (x <=> y)
println (x <=> y)
println ((x as Rational).compareTo(y))
println (x.compareTo(y))
assert x < y
assert x*3 == y
assert x*3 == y
assert x*5.5 == 5.5*x
assert (z + 1) <= y*4
assert (z + 1) <= y*4
assert x + 1.3 == 1.3 + x
assert 24 - y == -(y - 24)
assert 3 / y == (y / 3).reciprocal()
assert x != y
assert x != y


Line 1,189: Line 1,199:
println "x * y == ${x} * ${y} == ${x * y}"
println "x * y == ${x} * ${y} == ${x * y}"
println "y ** 3 == ${y} ** 3 == ${y ** 3}"
println "y ** 3 == ${y} ** 3 == ${y ** 3}"
println "y ** -3 == ${y} ** -3 == ${y ** -3}"
println "x * z == ${x} * ${z} == ${x * z}"
println "x * z == ${x} * ${z} == ${x * z}"
println "x / y == ${x} / ${y} == ${x / y}"
println "x / y == ${x} / ${y} == ${x / y}"
Line 1,228: Line 1,239:
assert (x < y)
assert (x < y)


println (new Rational(25))
println 25 as Rational
println (new Rational(25.0))
println 25.0 as Rational
println (new Rational(0.25))
println 0.25 as Rational


def ε = 0.000000001 // tolerance (epsilon): acceptable "wrongness" to account for rounding error
println Math.PI

println (new Rational(Math.PI))
def π = Math.PI
println ((new Rational(Math.PI)).toBigDecimal())
def α = π as Rational
println ((new Rational(Math.PI)) as BigDecimal)
assert (π - (α as BigDecimal)).abs() < ε
println ((new Rational(Math.PI)) as Double)
println π
println ((new Rational(Math.PI)) as double)
println α
println ((new Rational(Math.PI)) as boolean)
println (α.toBigDecimal())
println (α as BigDecimal)
println (α as Double)
println (α as double)
println (α as boolean)
println (z as boolean)
println (z as boolean)
try { println ((new Rational(Math.PI)) as Date) }
try { println (α as Date) }
catch (Throwable t) { println t.message }
catch (Throwable t) { println t.message }
try { println ((new Rational(Math.PI)) as char) }
try { println (α as char) }
catch (Throwable t) { println t.message }</lang>
catch (Throwable t) { println t.message }</lang>
{{out}}
{{out}}
Line 1,256: Line 1,272:
x * y == 1//4 * 3//4 == 3//16
x * y == 1//4 * 3//4 == 3//16
y ** 3 == 3//4 ** 3 == 27//64
y ** 3 == 3//4 ** 3 == 27//64
y ** -3 == 3//4 ** -3 == 64//27
x * z == 1//4 * 0//1 == 0//1
x * z == 1//4 * 0//1 == 0//1
x / y == 1//4 / 3//4 == 1//3
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 / z == 1//4 / 0//1 == Division by zero
-x == -1//4 == -1//4
-x == -1//4 == -1//4
-y == -3//4 == -3//4
-y == -3//4 == -3//4
Line 1,272: Line 1,289:
z as int == 0//1 as int == 0
z as int == 0//1 as int == 0
z as double == 0//1 as double == 0.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 / z as int == 1 / 0//1 as int == Division by zero
1.0 / z == 1.0 / 0//1 == Denominator must not be 0. Expression: (denom != 0). Values: denom = 0
1.0 / z == 1.0 / 0//1 == Division by zero
++x == ++ 1//4 == 5//4
++x == ++ 1//4 == 5//4
++y == ++ 3//4 == 7//4
++y == ++ 3//4 == 7//4
Line 1,296: Line 1,313:
false
false
Cannot convert from type Rational to type class java.util.Date
Cannot convert from type Rational to type class java.util.Date
Cannot convert from type Rational to type class java.lang.Character</pre>
Cannot convert from type Rational to type char
</pre>
The following uses the Rational class to find all perfect numbers less than 2<sup>19</sup>:
The following uses the ''Rational'' class, with ''RationalCategory'' mixed into ''Number'', to find all perfect numbers less than 2<sup>19</sup>:
<lang groovy>def factorize = { target ->
<lang groovy>Number.metaClass.mixin RationalCategory
if (target == 1L) {

return [1L]
def factorize = { target ->
} else if ([2L, 3L].contains(target)) {
assert target > 0
return [1L, target]
if (target == 1L) { return [1L] }
}
def targetSqrt = Math.ceil(Math.sqrt(target)) as long
if ([2L, 3L].contains(target)) { return [1L, target] }
def lowfactors = (2L..(targetSqrt)).findAll { (target % it) == 0 }
def targetSqrt = Math.sqrt(target)
def lowFactors = (2L..targetSqrt).findAll { (target % it) == 0 }

if (lowfactors.isEmpty()) {
return [1L, target]
if (!lowFactors) { return [1L, target] }
def highFactors = lowFactors[-1..0].findResults { target.intdiv(it) } - lowFactors[-1]
}

return [1L] + lowFactors + highFactors + [target]
def nhalf = lowfactors.size() - ((lowfactors[-1] == targetSqrt) ? 1 : 0)
return ([1L] + lowfactors + ((nhalf-1)..0).collect { target.intdiv(lowfactors[it]) } + [target]).unique()
}
}


def perfect = {
1.upto(2**19) {
if ((it % 100000) == 0) { println "HT" }
else if ((it % 1000) == 0) { print "." }
def factors = factorize(it)
def factors = factorize(it)
def isPerfect = factors.collect{ factor -> new Rational( factor ).reciprocal() }.sum() == new Rational(2)
2 as Rational == factors.sum{ factor -> new Rational(1, factor) } \
if (isPerfect) { println() ; println ([perfect: it, factors: factors]) }
? [perfect: it, factors: factors]
: null
}</lang>
}
{{out}}
<pre>[perfect:6, factors:[1, 2, 3, 6]]


def trackProgress = { if ((it % (100*1000)) == 0) { println it } else if ((it % 1000) == 0) { print "." } }
[perfect:28, factors:[1, 2, 4, 7, 14, 28]]


(1..(2**19)).findResults { trackProgress(it); perfect(it) }.each { println(); print it }</lang>
{{out}}
<pre>...................................................................................................100000
...................................................................................................200000
...................................................................................................300000
...................................................................................................400000
...................................................................................................500000
........................
[perfect:6, factors:[1, 2, 3, 6]]
[perfect:28, factors:[1, 2, 4, 7, 14, 28]]
[perfect:496, factors:[1, 2, 4, 8, 16, 31, 62, 124, 248, 496]]
[perfect:496, factors:[1, 2, 4, 8, 16, 31, 62, 124, 248, 496]]
[perfect:8128, factors:[1, 2, 4, 8, 16, 32, 64, 127, 254, 508, 1016, 2032, 4064, 8128]]</pre>
........
[perfect:8128, factors:[1, 2, 4, 8, 16, 32, 64, 127, 254, 508, 1016, 2032, 4064, 8128]]
...........................................................................................HT
...................................................................................................HT
...................................................................................................HT
...................................................................................................HT
...................................................................................................HT
........................</pre>


=={{header|Haskell}}==
=={{header|Haskell}}==