const type: rational is new object struct
var integer: numerator is 0;
var integer: denominator is 1;
end struct;
const proc: normalize (inout rational: number) is func
begin
if number.denominator < 0 then
number.numerator := -number.numerator;
number.denominator := -number.denominator;
end if;
end func;
const proc: reduce (inout rational: number) is func
local
var integer: a is 0;
var integer: b is 0;
var integer: help is 0;
begin
a := abs(number.numerator);
b := number.denominator;
while a <> 0 do
help := b rem a;
b := a;
a := help;
end while;
if b >= 2 then
number.numerator := number.numerator div b;
number.denominator := number.denominator div b;
end if;
end func;
const func integer: gcd1 (in var integer: a, in var integer: b) is func
result
var integer: gcd is 0;
local
var integer: help is 0;
begin
while a <> 0 do
help := b rem a;
b := a;
a := help;
end while;
gcd := b;
end func;
const func integer: gcd2 (in integer: numerator, in integer: denominator) is func
result
var integer: b is 0;
local
var integer: a is 0;
var integer: help is 0;
begin
if numerator >= 0 then
a := numerator;
else
a := -numerator;
end if;
b := denominator;
while a <> 0 do
help := b rem a;
b := a;
a := help;
end while;
end func;
const func rational: (in integer: numerator) / (in integer: denominator) is func
result
var rational: aRational is rational.value;
begin
aRational.numerator := numerator;
aRational.denominator := denominator;
normalize(aRational);
reduce(aRational);
end func;
const func rational: + (in rational: number) is
return number;
const func rational: - (in rational: number) is func
result
var rational: negatedNumber is rational.value;
begin
negatedNumber.numerator := -number.numerator;
negatedNumber.denominator := number.denominator;
end func;
const func rational: (in rational: summand1) + (in rational: summand2) is func
result
var rational: sum is rational.value;
local
var integer: gcd_denominator is 0;
begin
gcd_denominator := gcd1(summand1.denominator, summand2.denominator);
sum.numerator := (summand1.numerator * summand2.denominator +
summand2.numerator * summand1.denominator) div gcd_denominator;
sum.denominator := summand1.denominator div gcd_denominator * summand2.denominator;
reduce(sum);
end func;
const func rational: (in rational: minuend) - (in rational: subtrahend) is func
result
var rational: difference is rational.value;
local
var integer: gcd_denominator is 0;
begin
gcd_denominator := gcd1(minuend.denominator, subtrahend.denominator);
difference.numerator := (minuend.numerator * subtrahend.denominator -
subtrahend.numerator * minuend.denominator) div gcd_denominator;
difference.denominator := minuend.denominator div gcd_denominator * subtrahend.denominator;
reduce(difference);
end func;
const func rational: (in rational: factor1) * (in rational: factor2) is func
result
var rational: product is rational.value;
local
var integer: gcd1 is 0;
var integer: gcd2 is 0;
begin
gcd1 := gcd2(factor1.numerator, factor2.denominator);
gcd2 := gcd2(factor2.numerator, factor1.denominator);
product.numerator := (factor1.numerator div gcd1) * (factor2.numerator div gcd2);
product.denominator := (factor1.denominator div gcd2) * (factor2.denominator div gcd1);
end func;
const func rational: (in rational: dividend) / (in rational: divisor) is func
result
var rational: quotient is rational.value;
local
var integer: gcd1 is 0;
var integer: gcd2 is 0;
begin
gcd1 := gcd2(dividend.numerator, divisor.numerator);
gcd2 := gcd2(divisor.denominator, dividend.denominator);
quotient.numerator := (dividend.numerator div gcd1) * (divisor.denominator div gcd2);
quotient.denominator := (dividend.denominator div gcd2) * (divisor.numerator div gcd1);
normalize(quotient);
end func;
const proc: (inout rational: number) +:= (in rational: delta) is func
local
var integer: gcd_denominator is 0;
begin
gcd_denominator := gcd1(number.denominator, delta.denominator);
number.numerator := (number.numerator * delta.denominator +
delta.numerator * number.denominator) div gcd_denominator;
number.denominator *:= delta.denominator div gcd_denominator;
reduce(number);
end func;
const proc: (inout rational: number) -:= (in rational: delta) is func
local
var integer: gcd_denominator is 0;
begin
gcd_denominator := gcd1(number.denominator, delta.denominator);
number.numerator := (number.numerator * delta.denominator -
delta.numerator * number.denominator) div gcd_denominator;
number.denominator *:= delta.denominator div gcd_denominator;
reduce(number);
end func;
const proc: (inout rational: number) *:= (in rational: factor) is func
begin
number.numerator *:= factor.numerator;
number.denominator *:= factor.denominator;
reduce(number);
end func;
const proc: (inout rational: number) /:= (in rational: divisor) is func
begin
number.numerator *:= divisor.denominator;
number.denominator *:= divisor.numerator;
normalize(number);
reduce(number);
end func;
const func rational: (in rational: base) ** (in integer: exponent) is func
result
var rational: power is rational.value;
begin
if exponent >= 0 then
power.numerator := base.numerator ** exponent;
power.denominator := base.denominator ** exponent;
else
power.numerator := base.denominator ** (-exponent);
power.denominator := base.numerator ** (-exponent);
normalize(power);
end if;
end func;
const func boolean: (in rational: number1) = (in rational: number2) is
return number1.numerator = number2.numerator and
number1.denominator = number2.denominator;
const func boolean: (in rational: number1) <> (in rational: number2) is
return number1.numerator <> number2.numerator or
number1.denominator <> number2.denominator;
const func boolean: (in rational: number1) < (in rational: number2) is
return number1.numerator * number2.denominator <
number2.numerator * number1.denominator;
const func boolean: (in rational: number1) > (in rational: number2) is
return number1.numerator * number2.denominator >
number2.numerator * number1.denominator;
const func boolean: (in rational: number1) <= (in rational: number2) is
return number1.numerator * number2.denominator <=
number2.numerator * number1.denominator;
const func boolean: (in rational: number1) >= (in rational: number2) is
return number1.numerator * number2.denominator >=
number2.numerator * number1.denominator;
const func integer: compare (in rational: number1, in rational: number2) is
return compare(number1.numerator * number2.denominator,
number2.numerator * number1.denominator);
const func integer: hashCode (in rational: number) is
return number.numerator mod 16#40000000 + number.denominator mod 16#40000000;
const func rational: rat (in integer: number) is func
result
var rational: aRational is rational.value;
begin
aRational.numerator := number;
aRational.denominator := 1;
end func;
const func rational: rational (in integer: number) is func
result
var rational: aRational is rational.value;
begin
aRational.numerator := number;
aRational.denominator := 1;
end func;
const func rational: (attr rational) conv (in integer: number) is func
result
var rational: aRational is rational.value;
begin
aRational.numerator := number;
aRational.denominator := 1;
end func;
const func rational: abs (in rational: number) is func
result
var rational: absoluteValue is rational.value;
begin
absoluteValue.numerator := abs(number.numerator);
absoluteValue.denominator := number.denominator;
end func;
const func integer: floor (in rational: number) is
return number.numerator mdiv number.denominator;
const func integer: ceil (in rational: number) is
return -(number.numerator mdiv -number.denominator);
const func integer: trunc (in rational: number) is
return number.numerator div number.denominator;
const func integer: round (in rational: number) is func
result
var integer: int_val is 0;
begin
if number.numerator >= 0 then
int_val := (2 * number.numerator + number.denominator) div (2 * number.denominator);
else
int_val := (2 * number.numerator - number.denominator) div (2 * number.denominator);
end if;
end func;
const func rational: round10 (in rational: number, in integer: precision) is func
result
var rational: rounded is rational.value;
begin
if precision < 0 then
rounded.numerator := (abs(number.numerator) div 10 ** pred(-precision) +
number.denominator * 5) div (number.denominator * 10) *
10 ** (-precision);
rounded.denominator := 1;
else
rounded.numerator := (abs(number.numerator) * 10 ** succ(precision) +
number.denominator * 5) div (number.denominator * 10);
rounded.denominator := 10 ** precision;
end if;
if number.numerator < 0 then
rounded.numerator := -rounded.numerator;
end if;
end func;
const type: INT_REMAINDER_HASH_TYPE is hash [integer] integer;
const func string: str (in rational: number) is func
result
var string: stri is "";
local
var integer: remainder is 0;
var INT_REMAINDER_HASH_TYPE: remainderHash is INT_REMAINDER_HASH_TYPE.value;
var integer: pos is 0;
begin
if number.denominator = 0 then
if number.numerator > 0 then
stri := "Infinity";
elsif number.numerator = 0 then
stri := "NaN";
else
stri := "-Infinity";
end if;
else
stri := str(abs(number.numerator) div number.denominator);
stri &:= ".";
remainder := abs(number.numerator) rem number.denominator;
if remainder = 0 then
stri &:= "0";
else
repeat
remainderHash @:= [remainder] length(stri);
remainder *:= 10;
stri &:= str(remainder div number.denominator);
remainder := remainder rem number.denominator;
until remainder = 0 or remainder in remainderHash;
if remainder <> 0 then
pos := remainderHash[remainder];
stri := stri[.. pos] & "(" & stri[succ(pos) ..] & ")";
end if;
end if;
if number.numerator < 0 then
stri := "-" & stri;
end if;
end if;
end func;
const func string: fraction (in rational: number) is
return str(number.numerator) & "/" & str(number.denominator);
const func string: (in rational: number) digits (in integer: precision) is func
result
var string: stri is "";
local
var integer: mantissa is 0;
begin
if precision < 0 then
raise RANGE_ERROR;
elsif number.denominator = 0 then
if number.numerator > 0 then
stri := "Infinity";
elsif number.numerator = 0 then
stri := "NaN";
else
stri := "-Infinity";
end if;
else
mantissa := (abs(number.numerator) * 10 ** succ(precision) +
number.denominator * 5) div (number.denominator * 10);
stri := str(mantissa);
if precision >= length(stri) then
stri := "0" mult (precision - length(stri) + 1) & stri;
end if;
if precision <> 0 then
stri := stri[ .. length(stri) - precision] & "." &
stri[length(stri) - precision + 1 .. ];
end if;
if number.numerator < 0 and mantissa <> 0 then
stri := "-" & stri;
end if;
end if;
end func;
const func integer: decimalExponent (in rational: number) is func
result
var integer: exponent is 0;
begin
if abs(number.numerator) >= number.denominator then
exponent := log10(abs(number.numerator) div number.denominator);
else
exponent := -log10(number.denominator div abs(number.numerator)) - 1;
end if;
end func;
const func string: (in rational: number) sci (in integer: precision) is func
result
var string: stri is "";
local
var integer: exponent is 0;
var integer: mantissa is 0;
begin
if precision < 0 then
raise RANGE_ERROR;
elsif number.denominator = 0 then
if number.numerator > 0 then
stri := "Infinity";
elsif number.numerator = 0 then
stri := "NaN";
else
stri := "-Infinity";
end if;
elsif number.numerator = 0 then
if precision = 0 then
stri := "0e+0";
else
stri := "0." & "0" mult precision & "e+0";
end if;
else
exponent := decimalExponent(number);
if succ(precision) >= exponent then
mantissa := (abs(number.numerator) * 10 ** succ(precision - exponent) +
number.denominator * 5) div (number.denominator * 10);
else
mantissa := (abs(number.numerator) div 10 ** pred(exponent - precision) +
number.denominator * 5) div (number.denominator * 10);
end if;
stri := str(mantissa);
if length(stri) > succ(precision) then
incr(exponent);
stri := stri[.. succ(precision)];
end if;
if precision <> 0 then
stri := stri[1 fixLen 1] & "." & stri[2 .. ];
end if;
if exponent >= 0 then
stri &:= "e+" <& exponent;
else
stri &:= "e" <& exponent;
end if;
if number.numerator < 0 then
stri := "-" & stri;
end if;
end if;
end func;
const func rational: rational (in var string: stri) is func
result
var rational: aRational is rational.value;
local
var boolean: negative is FALSE;
var string: fraction is "";
var string: period is "";
begin
if stri <> "" then
if stri[1] = '-' then
stri := stri[2 ..];
negative := TRUE;
elsif stri[1] = '+' then
stri := stri[2 ..];
end if;
aRational.numerator := integer(getint(stri));
if stri[1] = '/' then
stri := stri[2 ..];
aRational.denominator := integer(getint(stri));
reduce(aRational);
elsif stri[1] = '.' then
stri := stri[2 ..];
if startsWith(stri, "(") then
stri := stri[2 ..];
period := getint(stri);
aRational.denominator := 1;
aRational +:= integer(period) / pred(10 ** length(period));
if stri[1] = ')' then
stri := stri[2 ..];
end if;
else
fraction := getint(stri);
aRational.denominator := 10 ** length(fraction);
aRational.numerator *:= aRational.denominator;
aRational.numerator +:= integer(fraction);
if startsWith(stri, "(") then
stri := stri[2 ..];
period := getint(stri);
aRational +:= integer(period) / (pred(10 ** length(period)) * aRational.denominator);
if stri[1] = ')' then
stri := stri[2 ..];
end if;
end if;
end if;
reduce(aRational);
end if;
if stri <> "" then
raise RANGE_ERROR;
elsif negative then
aRational.numerator := -aRational.numerator;
end if;
else
raise RANGE_ERROR;
end if;
end func;
const func rational: (attr rational) parse (in string: stri) is
return rational(stri);
enable_io(rational);
DECLARE_TERNARY(rational);
DECLARE_MIN_MAX(rational);
const type: _rationalArray is array rational;