2020-02-03 05:00:36 +01:00
|
|
|
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
2019-07-03 12:12:36 +02:00
|
|
|
// Use of this source code is governed by an MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
2019-07-15 21:16:41 +02:00
|
|
|
module fractions
|
|
|
|
|
|
|
|
import math
|
2020-05-08 14:39:23 +02:00
|
|
|
import math.bits
|
2019-07-03 12:12:36 +02:00
|
|
|
|
|
|
|
// Fraction Struct
|
|
|
|
struct Fraction {
|
2019-07-03 21:50:54 +02:00
|
|
|
n i64
|
|
|
|
d i64
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// A factory function for creating a Fraction, adds a boundary condition
|
2019-07-10 13:51:48 +02:00
|
|
|
pub fn fraction(n i64, d i64) Fraction{
|
2019-07-03 12:12:36 +02:00
|
|
|
if d != 0 {
|
2019-07-10 13:51:48 +02:00
|
|
|
return Fraction{n, d}
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
panic('Denominator cannot be zero')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// To String method
|
|
|
|
pub fn (f Fraction) str() string {
|
|
|
|
return '$f.n/$f.d'
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fraction add using operator overloading
|
|
|
|
pub fn (f1 Fraction) + (f2 Fraction) Fraction {
|
|
|
|
if f1.d == f2.d {
|
2019-07-10 13:51:48 +02:00
|
|
|
return Fraction{f1.n + f2.n, f1.d}
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
else {
|
2019-07-10 13:51:48 +02:00
|
|
|
return Fraction{(f1.n * f2.d) + (f2.n * f1.d), f1.d * f2.d}
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-12 20:45:56 +02:00
|
|
|
// Fraction subtract using operator overloading
|
2019-07-03 12:12:36 +02:00
|
|
|
pub fn (f1 Fraction) - (f2 Fraction) Fraction {
|
|
|
|
if f1.d == f2.d {
|
2019-07-10 13:51:48 +02:00
|
|
|
return Fraction{f1.n - f2.n, f1.d}
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
else {
|
2019-07-10 13:51:48 +02:00
|
|
|
return Fraction{(f1.n * f2.d) - (f2.n * f1.d), f1.d * f2.d}
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fraction multiply using operator overloading
|
|
|
|
// pub fn (f1 Fraction) * (f2 Fraction) Fraction {
|
|
|
|
// return Fraction{f1.n * f2.n,f1.d * f2.d}
|
|
|
|
// }
|
|
|
|
|
|
|
|
// Fraction divide using operator overloading
|
|
|
|
// pub fn (f1 Fraction) / (f2 Fraction) Fraction {
|
|
|
|
// return Fraction{f1.n * f2.d,f1.d * f2.n}
|
|
|
|
// }
|
|
|
|
|
|
|
|
// Fraction add method
|
|
|
|
pub fn (f1 Fraction) add(f2 Fraction) Fraction {
|
|
|
|
return f1 + f2
|
|
|
|
}
|
|
|
|
|
2019-07-03 21:50:54 +02:00
|
|
|
// Fraction subtract method
|
|
|
|
pub fn (f1 Fraction) subtract(f2 Fraction) Fraction {
|
2019-07-03 12:12:36 +02:00
|
|
|
return f1 - f2
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fraction multiply method
|
|
|
|
pub fn (f1 Fraction) multiply(f2 Fraction) Fraction {
|
2019-07-10 13:51:48 +02:00
|
|
|
return Fraction{f1.n * f2.n, f1.d * f2.d}
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fraction divide method
|
|
|
|
pub fn (f1 Fraction) divide(f2 Fraction) Fraction {
|
2019-07-10 13:51:48 +02:00
|
|
|
return Fraction{f1.n * f2.d, f1.d * f2.n}
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fraction reciprocal method
|
|
|
|
pub fn (f1 Fraction) reciprocal() Fraction {
|
2019-11-11 21:37:32 +01:00
|
|
|
if f1.n == 0 { panic('Denominator cannot be zero') }
|
2019-07-10 13:51:48 +02:00
|
|
|
return Fraction{f1.d, f1.n}
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fraction method which gives greatest common divisor of numerator and denominator
|
2019-07-03 21:50:54 +02:00
|
|
|
pub fn (f1 Fraction) gcd() i64 {
|
2019-07-15 21:16:41 +02:00
|
|
|
return math.gcd(f1.n, f1.d)
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fraction method which reduces the fraction
|
|
|
|
pub fn (f1 Fraction) reduce() Fraction {
|
2019-07-12 08:27:10 +02:00
|
|
|
cf := f1.gcd()
|
2019-07-10 13:51:48 +02:00
|
|
|
return Fraction{f1.n / cf, f1.d / cf}
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Converts Fraction to decimal
|
2019-07-03 21:50:54 +02:00
|
|
|
pub fn (f1 Fraction) f64() f64 {
|
2019-07-10 13:51:48 +02:00
|
|
|
return f64(f1.n) / f64(f1.d)
|
2019-07-03 12:12:36 +02:00
|
|
|
}
|
|
|
|
|
2020-05-08 14:39:23 +02:00
|
|
|
// Returns the absolute value of an i64
|
|
|
|
fn abs(num i64) i64 {
|
|
|
|
if num < 0 {
|
|
|
|
return -num
|
|
|
|
} else {
|
|
|
|
return num
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Two integers are safe to multiply when their bit lengths
|
|
|
|
// sum up to less than 64 (conservative estimate).
|
|
|
|
fn safe_to_multiply(a, b i64) bool {
|
|
|
|
return (bits.len_64(abs(a)) + bits.len_64(abs(b))) < 64
|
|
|
|
}
|
|
|
|
|
2019-07-03 12:12:36 +02:00
|
|
|
// Compares two Fractions
|
|
|
|
pub fn (f1 Fraction) equals(f2 Fraction) bool {
|
2020-05-08 14:39:23 +02:00
|
|
|
if safe_to_multiply(f1.n, f2.d) && safe_to_multiply(f2.n, f1.d) {
|
|
|
|
return (f1.n * f2.d) == (f2.n * f1.d)
|
|
|
|
}
|
2019-07-03 12:12:36 +02:00
|
|
|
r1 := f1.reduce()
|
|
|
|
r2 := f2.reduce()
|
2019-07-04 13:24:53 +02:00
|
|
|
return (r1.n == r2.n) && (r1.d == r2.d)
|
2019-07-10 13:51:48 +02:00
|
|
|
}
|