///|
priv struct R {
n : @bigint.BigInt
d : @bigint.BigInt
} derive(Eq)
///|
fn ratio(n : @bigint.BigInt, d : @bigint.BigInt) -> R {
let (n, d) = if d < 0N { (-n, -d) } else { (n, d) }
let mut a = if n < 0N { -n } else { n }
let mut b = d
while b != 0N {
let remainder = a % b
a = b
b = remainder
}
{ n: n / a, d: d / a, }
}
///|
fn r(value : Int32) -> R {
{ n: @bigint.BigInt::from_int(value), d: 1N, }
}
///|
impl Add for R with fn add(a, b) {
ratio(a.n * b.d + b.n * a.d, a.d * b.d)
}
///|
impl Sub for R with fn sub(a, b) {
ratio(a.n * b.d - b.n * a.d, a.d * b.d)
}
///|
impl Mul for R with fn mul(a, b) {
ratio(a.n * b.n, a.d * b.d)
}
///|
impl Div for R with fn div(a, b) {
ratio(a.n * b.d, a.d * b.n)
}
///|
impl Neg for R with fn neg(a) {
{ n: -a.n, d: a.d, }
}
///|
impl Compare for R with fn compare(a, b) {
(a.n * b.d).compare(b.n * a.d)
}
///|
fn exact(value : R) -> Exact {
{ numerator: value.n.to_string(), denominator: value.d.to_string(), }
}
///|
fn integer_text(value : String, signed~ : Bool) -> Bool {
let bytes = value.to_array()
if bytes.length() == 0 || bytes.length() > 700 {
return false
}
let start = if signed && bytes[0] == '-' { 1 } else { 0 }
if start == bytes.length() {
return false
}
for i = start; i < bytes.length(); i = i + 1 {
if bytes[i] < '0' || bytes[i] > '9' {
return false
}
}
true
}
///|
fn parse_exact(value : Exact) -> Result[R, String] {
if !integer_text(value.numerator, signed=true) ||
!integer_text(value.denominator, signed=false) {
return Err(
"exact values require integer numerator and positive denominator",
)
}
let d = @bigint.BigInt::from_string(value.denominator)
if d == 0N {
return Err("exact denominator cannot be zero")
}
Ok(ratio(@bigint.BigInt::from_string(value.numerator), d))
}