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 |
final BigInteger num, denom |
||
static final Rational ONE = new Rational( |
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 ? 1 : 10**(decimal.scale())) |
|||
) |
|||
} |
} |
||
Rational( |
Rational(BigInteger n, BigInteger d = 1) { |
||
if (!d || n == null) { n/d } |
|||
(num, denom) = reduce(n, d) |
|||
numerator = values[0] |
|||
denominator = values[1] |
|||
} |
} |
||
private List reduce(BigInteger |
private List reduce(BigInteger n, BigInteger d) { |
||
BigInteger sign = (( |
BigInteger sign = ((n < 0) != (d < 0)) ? -1 : 1 |
||
(n, d) = [n.abs(), d.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 plus(Number n) { this + ([n] as Rational) } |
||
Rational |
Rational next() { [num + denom, denom] } |
||
Rational |
Rational minus(Rational r) { [num*r.denom - r.num*denom, denom*r.denom] } |
||
Rational minus(BigInteger n) { [num - n*denom, denom] } |
|||
Rational minus |
Rational minus(Number n) { this - ([n] as Rational) } |
||
Rational |
Rational previous() { [num - denom, denom] } |
||
Rational |
Rational multiply(Rational r) { [num*r.num, denom*r.denom] } |
||
Rational multiply(BigInteger n) { [num*n, denom] } |
|||
Rational multiply |
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 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: |
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: |
case [Double.class,Double.TYPE]: return toDouble() |
||
case Float.class: |
case [Float.class,Float.TYPE]: return toFloat() |
||
case Integer.class: |
case [Integer.class,Integer.TYPE]: return toInteger() |
||
case Long.class: |
case [Long.class,Long.TYPE]: return toLong() |
||
case String.class: return toString() |
case String.class: return toString() |
||
default: |
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( |
int compareTo(Number n) { num <=> denom*(n as BigInteger) } |
||
int |
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 |
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 |
println 25 as Rational |
||
println |
println 25.0 as Rational |
||
println |
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 ( |
try { println (α as Date) } |
||
catch (Throwable t) { println t.message } |
catch (Throwable t) { println t.message } |
||
try { println ( |
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 == |
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 == |
1 / z as int == 1 / 0//1 as int == Division by zero |
||
1.0 / z == 1.0 / 0//1 == |
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 |
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] } |
|||
} |
|||
if ([2L, 3L].contains(target)) { return [1L, target] } |
|||
def |
def targetSqrt = Math.sqrt(target) |
||
def lowFactors = (2L..targetSqrt).findAll { (target % it) == 0 } |
|||
if (lowfactors.isEmpty()) { |
|||
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) |
||
2 as Rational == factors.sum{ factor -> new Rational(1, factor) } \ |
|||
? [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}}== |