164 lines
4.5 KiB
Rexx
164 lines
4.5 KiB
Rexx
loop candidate = 6 to 2**19
|
|
sum = .fraction~new(1, candidate)
|
|
max2 = rxcalcsqrt(candidate)~trunc
|
|
|
|
loop factor = 2 to max2
|
|
if candidate // factor == 0 then do
|
|
sum += .fraction~new(1, factor)
|
|
sum += .fraction~new(1, candidate / factor)
|
|
end
|
|
end
|
|
if sum == 1 then say candidate "is a perfect number"
|
|
end
|
|
|
|
::class fraction public inherit orderable
|
|
::method init
|
|
expose numerator denominator
|
|
use strict arg numerator, denominator = 1
|
|
|
|
if denominator == 0 then raise syntax 98.900 array("Fraction denominator cannot be zero")
|
|
|
|
-- if the denominator is negative, make the numerator carry the sign
|
|
if denominator < 0 then do
|
|
numerator = -numerator
|
|
denominator = - denominator
|
|
end
|
|
|
|
|
|
-- find the greatest common denominator and reduce to
|
|
-- the simplest form
|
|
gcd = self~gcd(numerator~abs, denominator~abs)
|
|
|
|
numerator /= gcd
|
|
denominator /= gcd
|
|
|
|
-- fraction instances are immutable, so these are
|
|
-- read only attributes
|
|
::attribute numerator GET
|
|
::attribute denominator GET
|
|
|
|
-- calculate the greatest common denominator of a numerator/denominator pair
|
|
::method gcd private
|
|
use arg x, y
|
|
|
|
loop while y \= 0
|
|
-- check if they divide evenly
|
|
temp = x // y
|
|
x = y
|
|
y = temp
|
|
end
|
|
return x
|
|
|
|
-- calculate the least common multiple of a numerator/denominator pair
|
|
::method lcm private
|
|
use arg x, y
|
|
return x / self~gcd(x, y) * y
|
|
|
|
::method abs
|
|
expose numerator denominator
|
|
-- the denominator is always forced to be positive
|
|
return self~class~new(numerator~abs, denominator)
|
|
|
|
::method reciprocal
|
|
expose numerator denominator
|
|
return self~class~new(denominator, numerator)
|
|
|
|
-- convert a fraction to regular Rexx number
|
|
::method toNumber
|
|
expose numerator denominator
|
|
|
|
if numerator == 0 then return 0
|
|
return numerator/denominator
|
|
|
|
::method negative
|
|
expose numerator denominator
|
|
return self~class~new(-numerator, denominator)
|
|
|
|
::method add
|
|
expose numerator denominator
|
|
use strict arg other
|
|
-- convert to a fraction if a regular number
|
|
if \other~isa(.fraction) then other = self~class~new(other, 1)
|
|
|
|
multiple = self~lcm(denominator, other~denominator)
|
|
newa = numerator * multiple / denominator
|
|
newb = other~numerator * multiple / other~denominator
|
|
return self~class~new(newa + newb, multiple)
|
|
|
|
::method subtract
|
|
use strict arg other
|
|
return self + (-other)
|
|
|
|
::method times
|
|
expose numerator denominator
|
|
use strict arg other
|
|
-- convert to a fraction if a regular number
|
|
if \other~isa(.fraction) then other = self~class~new(other, 1)
|
|
return self~class~new(numerator * other~numerator, denominator * other~denominator)
|
|
|
|
::method divide
|
|
use strict arg other
|
|
-- convert to a fraction if a regular number
|
|
if \other~isa(.fraction) then other = self~class~new(other, 1)
|
|
-- and multiply by the reciprocal
|
|
return self * other~reciprocal
|
|
|
|
-- compareTo method used by the orderable interface to implement
|
|
-- the operator methods
|
|
::method compareTo
|
|
expose numerator denominator
|
|
-- convert to a fraction if a regular number
|
|
if \other~isa(.fraction) then other = self~class~new(other, 1)
|
|
|
|
return (numerator * other~denominator - denominator * other~numerator)~sign
|
|
|
|
-- we still override "==" and "\==" because we want to bypass the
|
|
-- checks for not being an instance of the class
|
|
::method "=="
|
|
expose numerator denominator
|
|
use strict arg other
|
|
|
|
-- convert to a fraction if a regular number
|
|
if \other~isa(.fraction) then other = self~class~new(other, 1)
|
|
-- Note: these are numeric comparisons, so we're using the "="
|
|
-- method so those are handled correctly
|
|
return numerator = other~numerator & denominator = other~denominator
|
|
|
|
::method "\=="
|
|
use strict arg other
|
|
return \self~"\=="(other)
|
|
|
|
-- some operator overrides -- these only work if the left-hand-side of the
|
|
-- subexpression is a quaternion
|
|
::method "*"
|
|
forward message("TIMES")
|
|
|
|
::method "/"
|
|
forward message("DIVIDE")
|
|
|
|
::method "-"
|
|
-- need to check if this is a prefix minus or a subtract
|
|
if arg() == 0 then
|
|
forward message("NEGATIVE")
|
|
else
|
|
forward message("SUBTRACT")
|
|
|
|
::method "+"
|
|
-- need to check if this is a prefix plus or an addition
|
|
if arg() == 0 then
|
|
return self -- we can return this copy since it is imutable
|
|
else
|
|
forward message("ADD")
|
|
|
|
::method string
|
|
expose numerator denominator
|
|
if denominator == 1 then return numerator
|
|
return numerator"/"denominator
|
|
|
|
-- override hashcode for collection class hash uses
|
|
::method hashCode
|
|
expose numerator denominator
|
|
return numerator~hashcode~bitxor(numerator~hashcode)
|
|
|
|
::requires rxmath library
|