math.fractions: refactor and add more tests
parent
43ec01b23d
commit
8aba3eaa07
|
@ -1,105 +1,219 @@
|
|||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module fractions
|
||||
|
||||
import math
|
||||
import math.bits
|
||||
|
||||
// Fraction Struct
|
||||
// A Fraction has a numerator (n) and a denominator (d). If the user uses
|
||||
// the helper functions in this module, then the following are guaranteed:
|
||||
// 1.
|
||||
struct Fraction {
|
||||
n i64
|
||||
d i64
|
||||
n i64
|
||||
d i64
|
||||
pub:
|
||||
is_reduced bool
|
||||
}
|
||||
|
||||
// A factory function for creating a Fraction, adds a boundary condition
|
||||
pub fn fraction(n i64, d i64) Fraction{
|
||||
// to ensure that the denominator is non-zero. It automatically converts
|
||||
// the negative denominator to positive and adjusts the numerator.
|
||||
// NOTE: Fractions created are not reduced by default.
|
||||
pub fn fraction(n, d i64) Fraction {
|
||||
if d != 0 {
|
||||
return Fraction{n, d}
|
||||
}
|
||||
else {
|
||||
// The denominator is always guaranteed to be positive (and non-zero).
|
||||
if d < 0 {
|
||||
return fraction(-n, -d)
|
||||
} else {
|
||||
return Fraction{
|
||||
n: n
|
||||
d: d
|
||||
is_reduced: math.gcd(n, d) == 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic('Denominator cannot be zero')
|
||||
}
|
||||
}
|
||||
|
||||
// To String method
|
||||
pub fn (f Fraction) str() string {
|
||||
return '$f.n/$f.d'
|
||||
pub fn (f Fraction) str() string {
|
||||
return '$f.n/$f.d'
|
||||
}
|
||||
|
||||
//
|
||||
// + ---------------------+
|
||||
// | Arithmetic functions.|
|
||||
// + ---------------------+
|
||||
//
|
||||
// These are implemented from Knuth, TAOCP Vol 2. Section 4.5
|
||||
//
|
||||
// Returns a correctly reduced result for both addition and subtraction
|
||||
fn general_addition_result(f1, f2 Fraction, addition bool) Fraction {
|
||||
d1 := math.gcd(f1.d, f2.d)
|
||||
// d1 happends to be 1 around 600/(pi)^2 or 61 percent of the time (Theorem 4.5.2D)
|
||||
if d1 == 1 {
|
||||
mut n := i64(0)
|
||||
num1n2d := f1.n * f2.d
|
||||
num1d2n := f1.d * f2.n
|
||||
if addition {
|
||||
n = num1n2d + num1d2n
|
||||
} else {
|
||||
n = num1n2d - num1d2n
|
||||
}
|
||||
return Fraction{
|
||||
n: n
|
||||
d: f1.d * f2.d
|
||||
is_reduced: true
|
||||
}
|
||||
}
|
||||
// Here d1 > 1.
|
||||
// Without the i64(...), t is declared as an int
|
||||
// and it does not have enough precision
|
||||
mut t := i64(0)
|
||||
term1 := f1.n * (f2.d / d1)
|
||||
term2 := f2.n * (f1.d / d1)
|
||||
if addition {
|
||||
t = term1 + term2
|
||||
} else {
|
||||
t = term1 - term2
|
||||
}
|
||||
d2 := math.gcd(t, d1)
|
||||
return Fraction{
|
||||
n: t / d2
|
||||
d: (f1.d / d1) * (f2.d / d2)
|
||||
is_reduced: true
|
||||
}
|
||||
}
|
||||
|
||||
// Fraction add using operator overloading
|
||||
pub fn (f1 Fraction) + (f2 Fraction) Fraction {
|
||||
if f1.d == f2.d {
|
||||
return Fraction{f1.n + f2.n, f1.d}
|
||||
}
|
||||
else {
|
||||
return Fraction{(f1.n * f2.d) + (f2.n * f1.d), f1.d * f2.d}
|
||||
}
|
||||
pub fn (f1 Fraction) +(f2 Fraction) Fraction {
|
||||
return general_addition_result(f1.reduce(), f2.reduce(), true)
|
||||
}
|
||||
|
||||
// Fraction subtract using operator overloading
|
||||
pub fn (f1 Fraction) - (f2 Fraction) Fraction {
|
||||
if f1.d == f2.d {
|
||||
return Fraction{f1.n - f2.n, f1.d}
|
||||
pub fn (f1 Fraction) -(f2 Fraction) Fraction {
|
||||
return general_addition_result(f1.reduce(), f2.reduce(), false)
|
||||
}
|
||||
|
||||
// Returns a correctly reduced result for both multiplication and division
|
||||
fn general_multiplication_result(f1, f2 Fraction, multiplication bool) Fraction {
|
||||
// Theorem: If f1 and f2 are reduced i.e. gcd(f1.n, f1.d) == 1 and gcd(f2.n, f2.d) == 1,
|
||||
// then gcd(f1.n * f2.n, f1.d * f2.d) == gcd(f1.n, f2.d) * gcd(f1.d, f2.n)
|
||||
// Knuth poses this an exercise for 4.5.1. - Exercise 2
|
||||
mut d1 := i64(0)
|
||||
mut d2 := i64(0)
|
||||
mut n := i64(0)
|
||||
mut d := i64(0)
|
||||
// The terms are flipped for multiplication and division, so the gcds must be calculated carefully
|
||||
// We do multiple divisions in order to prevent any possible overflows. Also, note that:
|
||||
// if d = gcd(a, b) for example, then d divides both a and b
|
||||
if multiplication {
|
||||
d1 = math.gcd(f1.n, f2.d)
|
||||
d2 = math.gcd(f1.d, f2.n)
|
||||
n = (f1.n / d1) * (f2.n / d2)
|
||||
d = (f2.d / d1) * (f1.d / d2)
|
||||
} else {
|
||||
d1 = math.gcd(f1.n, f2.n)
|
||||
d2 = math.gcd(f1.d, f2.d)
|
||||
n = (f1.n / d1) * (f2.d / d2)
|
||||
d = (f2.n / d1) * (f1.d / d2)
|
||||
}
|
||||
else {
|
||||
return Fraction{(f1.n * f2.d) - (f2.n * f1.d), f1.d * f2.d}
|
||||
return Fraction{
|
||||
n: n
|
||||
d: d
|
||||
is_reduced: true
|
||||
}
|
||||
}
|
||||
|
||||
// Fraction multiply using operator overloading
|
||||
// pub fn (f1 Fraction) * (f2 Fraction) Fraction {
|
||||
// return Fraction{f1.n * f2.n,f1.d * f2.d}
|
||||
// }
|
||||
pub fn (f1 Fraction) *(f2 Fraction) Fraction {
|
||||
return general_multiplication_result(f1.reduce(), f2.reduce(), true)
|
||||
}
|
||||
|
||||
// Fraction divide using operator overloading
|
||||
// pub fn (f1 Fraction) / (f2 Fraction) Fraction {
|
||||
// return Fraction{f1.n * f2.d,f1.d * f2.n}
|
||||
// }
|
||||
pub fn (f1 Fraction) /(f2 Fraction) Fraction {
|
||||
if f2.n == 0 {
|
||||
panic('Cannot divive by zero')
|
||||
}
|
||||
// If the second fraction is negative, it will
|
||||
// mess up the sign. We need positive denominator
|
||||
if f2.n < 0 {
|
||||
return f1.negate() / f2.negate()
|
||||
}
|
||||
return general_multiplication_result(f1.reduce(), f2.reduce(), false)
|
||||
}
|
||||
|
||||
// Fraction add method
|
||||
// Fraction add method. Deprecated. Use the operator instead.
|
||||
[deprecated]
|
||||
pub fn (f1 Fraction) add(f2 Fraction) Fraction {
|
||||
return f1 + f2
|
||||
}
|
||||
|
||||
// Fraction subtract method
|
||||
// Fraction subtract method. Deprecated. Use the operator instead.
|
||||
[deprecated]
|
||||
pub fn (f1 Fraction) subtract(f2 Fraction) Fraction {
|
||||
return f1 - f2
|
||||
}
|
||||
|
||||
// Fraction multiply method
|
||||
// Fraction multiply method. Deprecated. Use the operator instead.
|
||||
[deprecated]
|
||||
pub fn (f1 Fraction) multiply(f2 Fraction) Fraction {
|
||||
return Fraction{f1.n * f2.n, f1.d * f2.d}
|
||||
return f1 * f2
|
||||
}
|
||||
|
||||
// Fraction divide method
|
||||
// Fraction divide method. Deprecated. Use the operator instead.
|
||||
[deprecated]
|
||||
pub fn (f1 Fraction) divide(f2 Fraction) Fraction {
|
||||
return Fraction{f1.n * f2.d, f1.d * f2.n}
|
||||
return f1 / f2
|
||||
}
|
||||
|
||||
// Fraction negate method
|
||||
pub fn (f1 Fraction) negate() Fraction {
|
||||
return Fraction{
|
||||
n: -f1.n
|
||||
d: f1.d
|
||||
is_reduced: f1.is_reduced
|
||||
}
|
||||
}
|
||||
|
||||
// Fraction reciprocal method
|
||||
pub fn (f1 Fraction) reciprocal() Fraction {
|
||||
if f1.n == 0 { panic('Denominator cannot be zero') }
|
||||
return Fraction{f1.d, f1.n}
|
||||
}
|
||||
|
||||
// Fraction method which gives greatest common divisor of numerator and denominator
|
||||
pub fn (f1 Fraction) gcd() i64 {
|
||||
return math.gcd(f1.n, f1.d)
|
||||
if f1.n == 0 {
|
||||
panic('Denominator cannot be zero')
|
||||
}
|
||||
return Fraction{
|
||||
n: f1.d
|
||||
d: f1.n
|
||||
is_reduced: f1.is_reduced
|
||||
}
|
||||
}
|
||||
|
||||
// Fraction method which reduces the fraction
|
||||
pub fn (f1 Fraction) reduce() Fraction {
|
||||
cf := f1.gcd()
|
||||
return Fraction{f1.n / cf, f1.d / cf}
|
||||
if f1.is_reduced {
|
||||
return f1
|
||||
}
|
||||
cf := math.gcd(f1.n, f1.d)
|
||||
return Fraction{
|
||||
n: f1.n / cf
|
||||
d: f1.d / cf
|
||||
is_reduced: true
|
||||
}
|
||||
}
|
||||
|
||||
// Converts Fraction to decimal
|
||||
// f64 converts the Fraction to 64-bit floating point
|
||||
pub fn (f1 Fraction) f64() f64 {
|
||||
return f64(f1.n) / f64(f1.d)
|
||||
}
|
||||
|
||||
//
|
||||
// + ------------------+
|
||||
// | Utility functions.|
|
||||
// + ------------------+
|
||||
//
|
||||
// Returns the absolute value of an i64
|
||||
fn abs(num i64) i64 {
|
||||
if num < 0 {
|
||||
|
@ -109,18 +223,65 @@ fn abs(num i64) i64 {
|
|||
}
|
||||
}
|
||||
|
||||
fn cmp_i64s(a, b i64) int {
|
||||
if a == b {
|
||||
return 0
|
||||
} else if a > b {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp_f64s(a, b f64) int {
|
||||
// V uses epsilon comparison internally
|
||||
if a == b {
|
||||
return 0
|
||||
} else if a > b {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Compares two Fractions
|
||||
pub fn (f1 Fraction) equals(f2 Fraction) bool {
|
||||
fn cmp(f1, f2 Fraction) int {
|
||||
if safe_to_multiply(f1.n, f2.d) && safe_to_multiply(f2.n, f1.d) {
|
||||
return (f1.n * f2.d) == (f2.n * f1.d)
|
||||
return cmp_i64s(f1.n * f2.d, f2.n * f1.d)
|
||||
} else {
|
||||
return cmp_f64s(f1.f64(), f2.f64())
|
||||
}
|
||||
r1 := f1.reduce()
|
||||
r2 := f2.reduce()
|
||||
return (r1.n == r2.n) && (r1.d == r2.d)
|
||||
}
|
||||
|
||||
// +-----------------------------+
|
||||
// | Public comparison functions |
|
||||
// +-----------------------------+
|
||||
// equals returns true if both the Fractions are equal
|
||||
pub fn (f1 Fraction) equals(f2 Fraction) bool {
|
||||
return cmp(f1, f2) == 0
|
||||
}
|
||||
|
||||
// ge returns true if f1 >= f2
|
||||
pub fn (f1 Fraction) ge(f2 Fraction) bool {
|
||||
return cmp(f1, f2) >= 0
|
||||
}
|
||||
|
||||
// gt returns true if f1 > f2
|
||||
pub fn (f1 Fraction) gt(f2 Fraction) bool {
|
||||
return cmp(f1, f2) > 0
|
||||
}
|
||||
|
||||
// le returns true if f1 <= f2
|
||||
pub fn (f1 Fraction) le(f2 Fraction) bool {
|
||||
return cmp(f1, f2) <= 0
|
||||
}
|
||||
|
||||
// lt returns true if f1 < f2
|
||||
pub fn (f1 Fraction) lt(f2 Fraction) bool {
|
||||
return cmp(f1, f2) < 0
|
||||
}
|
||||
|
|
|
@ -1,153 +1,266 @@
|
|||
import math.fractions as fractions
|
||||
import math.fractions
|
||||
|
||||
// Results are verified using https://www.calculatorsoup.com/calculators/math/fractions.php
|
||||
|
||||
fn test_fraction_creation() {
|
||||
mut f1 := fractions.fraction(4,8)
|
||||
assert f1.f64() == 0.5
|
||||
assert f1.str().eq('4/8')
|
||||
f1 = fractions.fraction(10,5)
|
||||
assert f1.f64() == 2.0
|
||||
assert f1.str().eq('10/5')
|
||||
f1 = fractions.fraction(9,3)
|
||||
assert f1.f64() == 3.0
|
||||
assert f1.str().eq('9/3')
|
||||
// (Old) results are verified using https://www.calculatorsoup.com/calculators/math/fractions.php
|
||||
// Newer ones are contrived for corner cases or prepared by hand.
|
||||
fn test_4_by_8_f64_and_str() {
|
||||
f := fractions.fraction(4, 8)
|
||||
assert f.f64() == 0.5
|
||||
assert f.str() == '4/8'
|
||||
}
|
||||
|
||||
fn test_fraction_add() {
|
||||
mut f1 := fractions.fraction(4,8)
|
||||
mut f2 := fractions.fraction(5,10)
|
||||
mut sum := f1 + f2
|
||||
fn test_10_by_5_f64_and_str() {
|
||||
f := fractions.fraction(10, 5)
|
||||
assert f.f64() == 2.0
|
||||
assert f.str() == '10/5'
|
||||
}
|
||||
|
||||
fn test_9_by_3_f64_and_str() {
|
||||
f := fractions.fraction(9, 3)
|
||||
assert f.f64() == 3.0
|
||||
assert f.str() == '9/3'
|
||||
}
|
||||
|
||||
fn test_4_by_minus_5_f64_and_str() {
|
||||
f := fractions.fraction(4, -5)
|
||||
assert f.f64() == -0.8
|
||||
assert f.str() == '-4/5'
|
||||
}
|
||||
|
||||
fn test_minus_7_by_minus_92_str() {
|
||||
f := fractions.fraction(-7, -5)
|
||||
assert f.str() == '7/5'
|
||||
}
|
||||
|
||||
fn test_4_by_8_plus_5_by_10() {
|
||||
f1 := fractions.fraction(4, 8)
|
||||
f2 := fractions.fraction(5, 10)
|
||||
sum := f1 + f2
|
||||
assert sum.f64() == 1.0
|
||||
assert sum.str().eq('80/80')
|
||||
f1 = fractions.fraction(5,5)
|
||||
f2 = fractions.fraction(8,8)
|
||||
sum = f1 + f2
|
||||
assert sum.str() == '1/1'
|
||||
assert sum.equals(fractions.fraction(1, 1))
|
||||
}
|
||||
|
||||
fn test_5_by_5_plus_8_by_8() {
|
||||
f1 := fractions.fraction(5, 5)
|
||||
f2 := fractions.fraction(8, 8)
|
||||
sum := f1 + f2
|
||||
assert sum.f64() == 2.0
|
||||
assert sum.str().eq('80/40')
|
||||
f1 = fractions.fraction(9,3)
|
||||
f2 = fractions.fraction(1,3)
|
||||
sum = f1 + f2
|
||||
$if debug {
|
||||
println(sum.f64())
|
||||
}
|
||||
assert sum.str().eq('10/3')
|
||||
f1 = fractions.fraction(3,7)
|
||||
f2 = fractions.fraction(1,4)
|
||||
sum = f1 + f2
|
||||
$if debug {
|
||||
println(sum.f64())
|
||||
}
|
||||
assert sum.str().eq('19/28')
|
||||
assert sum.str() == '2/1'
|
||||
assert sum.equals(fractions.fraction(2, 1))
|
||||
}
|
||||
|
||||
fn test_fraction_subtract() {
|
||||
mut f1 := fractions.fraction(4,8)
|
||||
mut f2 := fractions.fraction(5,10)
|
||||
mut diff := f2 - f1
|
||||
assert diff.f64() == 0
|
||||
assert diff.str().eq('0/80')
|
||||
f1 = fractions.fraction(5,5)
|
||||
f2 = fractions.fraction(8,8)
|
||||
diff = f2 - f1
|
||||
assert diff.f64() == 0
|
||||
assert diff.str().eq('0/40')
|
||||
f1 = fractions.fraction(9,3)
|
||||
f2 = fractions.fraction(1,3)
|
||||
diff = f1 - f2
|
||||
$if debug {
|
||||
println(diff.f64())
|
||||
}
|
||||
assert diff.str().eq('8/3')
|
||||
f1 = fractions.fraction(3,7)
|
||||
f2 = fractions.fraction(1,4)
|
||||
diff = f1 - f2
|
||||
$if debug {
|
||||
println(diff.f64())
|
||||
}
|
||||
assert diff.str().eq('5/28')
|
||||
fn test_9_by_3_plus_1_by_3() {
|
||||
f1 := fractions.fraction(9, 3)
|
||||
f2 := fractions.fraction(1, 3)
|
||||
sum := f1 + f2
|
||||
assert sum.str() == '10/3'
|
||||
assert sum.equals(fractions.fraction(10, 3))
|
||||
}
|
||||
|
||||
fn test_fraction_multiply() {
|
||||
mut f1 := fractions.fraction(4,8)
|
||||
mut f2 := fractions.fraction(5,10)
|
||||
mut product := f1.multiply(f2)
|
||||
fn test_3_by_7_plus_1_by_4() {
|
||||
f1 := fractions.fraction(3, 7)
|
||||
f2 := fractions.fraction(1, 4)
|
||||
sum := f1 + f2
|
||||
assert sum.str() == '19/28'
|
||||
assert sum.equals(fractions.fraction(19, 28))
|
||||
}
|
||||
|
||||
fn test_36529_by_12409100000_plus_418754901_by_9174901000() {
|
||||
f1 := fractions.fraction(i64(36529), i64(12409100000))
|
||||
f2 := fractions.fraction(i64(418754901), i64(9174901000))
|
||||
sum := f1 + f2
|
||||
assert sum.str() == '5196706591957729/113852263999100000'
|
||||
}
|
||||
|
||||
fn test_4_by_8_plus_minus_5_by_10() {
|
||||
f1 := fractions.fraction(4, 8)
|
||||
f2 := fractions.fraction(-5, 10)
|
||||
diff := f2 + f1
|
||||
assert diff.f64() == 0
|
||||
assert diff.str() == '0/1'
|
||||
}
|
||||
|
||||
fn test_4_by_8_minus_5_by_10() {
|
||||
f1 := fractions.fraction(4, 8)
|
||||
f2 := fractions.fraction(5, 10)
|
||||
diff := f2 - f1
|
||||
assert diff.f64() == 0
|
||||
assert diff.str() == '0/1'
|
||||
}
|
||||
|
||||
fn test_5_by_5_minus_8_by_8() {
|
||||
f1 := fractions.fraction(5, 5)
|
||||
f2 := fractions.fraction(8, 8)
|
||||
diff := f2 - f1
|
||||
assert diff.f64() == 0
|
||||
assert diff.str() == '0/1'
|
||||
}
|
||||
|
||||
fn test_9_by_3_minus_1_by_3() {
|
||||
f1 := fractions.fraction(9, 3)
|
||||
f2 := fractions.fraction(1, 3)
|
||||
diff := f1 - f2
|
||||
assert diff.str() == '8/3'
|
||||
}
|
||||
|
||||
fn test_3_by_7_minus_1_by_4() {
|
||||
f1 := fractions.fraction(3, 7)
|
||||
f2 := fractions.fraction(1, 4)
|
||||
diff := f1 - f2
|
||||
assert diff.str() == '5/28'
|
||||
}
|
||||
|
||||
fn test_36529_by_12409100000_minus_418754901_by_9174901000() {
|
||||
f1 := fractions.fraction(i64(36529), i64(12409100000))
|
||||
f2 := fractions.fraction(i64(418754901), i64(9174901000))
|
||||
sum := f1 - f2
|
||||
assert sum.str() == '-5196036292040471/113852263999100000'
|
||||
}
|
||||
|
||||
fn test_4_by_8_times_5_by_10() {
|
||||
f1 := fractions.fraction(4, 8)
|
||||
f2 := fractions.fraction(5, 10)
|
||||
product := f1 * f2
|
||||
assert product.f64() == 0.25
|
||||
assert product.str().eq('20/80')
|
||||
f1 = fractions.fraction(5,5)
|
||||
f2 = fractions.fraction(8,8)
|
||||
product = f1.multiply(f2)
|
||||
assert product.str() == '1/4'
|
||||
}
|
||||
|
||||
fn test_5_by_5_times_8_by_8() {
|
||||
f1 := fractions.fraction(5, 5)
|
||||
f2 := fractions.fraction(8, 8)
|
||||
product := f1 * f2
|
||||
assert product.f64() == 1.0
|
||||
assert product.str().eq('40/40')
|
||||
f1 = fractions.fraction(9,3)
|
||||
f2 = fractions.fraction(1,3)
|
||||
product = f1.multiply(f2)
|
||||
assert product.str() == '1/1'
|
||||
}
|
||||
|
||||
fn test_9_by_3_times_1_by_3() {
|
||||
f1 := fractions.fraction(9, 3)
|
||||
f2 := fractions.fraction(1, 3)
|
||||
product := f1 * f2
|
||||
assert product.f64() == 1.0
|
||||
assert product.str().eq('9/9')
|
||||
f1 = fractions.fraction(3,7)
|
||||
f2 = fractions.fraction(1,4)
|
||||
product = f1.multiply(f2)
|
||||
$if debug {
|
||||
println(product.f64())
|
||||
}
|
||||
assert product.str().eq('3/28')
|
||||
assert product.str() == '1/1'
|
||||
}
|
||||
|
||||
fn test_fraction_divide() {
|
||||
mut f1 := fractions.fraction(4,8)
|
||||
mut f2 := fractions.fraction(5,10)
|
||||
mut re := f1.divide(f2)
|
||||
assert re.f64() == 1.0
|
||||
assert re.str().eq('40/40')
|
||||
f1 = fractions.fraction(5,5)
|
||||
f2 = fractions.fraction(8,8)
|
||||
re = f1.divide(f2)
|
||||
assert re.f64() == 1.0
|
||||
assert re.str().eq('40/40')
|
||||
f1 = fractions.fraction(9,3)
|
||||
f2 = fractions.fraction(1,3)
|
||||
re = f1.divide(f2)
|
||||
assert re.f64() == 9.0
|
||||
assert re.str().eq('27/3')
|
||||
f1 = fractions.fraction(3,7)
|
||||
f2 = fractions.fraction(1,4)
|
||||
re = f1.divide(f2)
|
||||
$if debug {
|
||||
println(re.f64())
|
||||
}
|
||||
assert re.str().eq('12/7')
|
||||
fn test_3_by_7_times_1_by_4() {
|
||||
f1 := fractions.fraction(3, 7)
|
||||
f2 := fractions.fraction(1, 4)
|
||||
product := f2 * f1
|
||||
assert product.f64() == (3.0 / 28.0)
|
||||
assert product.str() == '3/28'
|
||||
}
|
||||
|
||||
fn test_fraction_reciprocal() {
|
||||
mut f1 := fractions.fraction(4,8)
|
||||
assert f1.reciprocal().str().eq('8/4')
|
||||
f1 = fractions.fraction(5,10)
|
||||
assert f1.reciprocal().str().eq('10/5')
|
||||
f1 = fractions.fraction(5,5)
|
||||
assert f1.reciprocal().str().eq('5/5')
|
||||
f1 = fractions.fraction(8,8)
|
||||
assert f1.reciprocal().str().eq('8/8')
|
||||
f1 = fractions.fraction(9,3)
|
||||
assert f1.reciprocal().str().eq('3/9')
|
||||
f1 = fractions.fraction(1,3)
|
||||
assert f1.reciprocal().str().eq('3/1')
|
||||
f1 = fractions.fraction(3,7)
|
||||
assert f1.reciprocal().str().eq('7/3')
|
||||
f1 = fractions.fraction(1,4)
|
||||
assert f1.reciprocal().str().eq('4/1')
|
||||
fn test_4_by_8_over_5_by_10() {
|
||||
f1 := fractions.fraction(4, 8)
|
||||
f2 := fractions.fraction(5, 10)
|
||||
q := f1 / f2
|
||||
assert q.f64() == 1.0
|
||||
assert q.str() == '1/1'
|
||||
}
|
||||
|
||||
fn test_fraction_equals() {
|
||||
mut f1 := fractions.fraction(4,8)
|
||||
mut f2 := fractions.fraction(5,10)
|
||||
fn test_5_by_5_over_8_by_8() {
|
||||
f1 := fractions.fraction(5, 5)
|
||||
f2 := fractions.fraction(8, 8)
|
||||
q := f1 / f2
|
||||
assert q.f64() == 1.0
|
||||
assert q.str() == '1/1'
|
||||
}
|
||||
|
||||
fn test_9_by_3_over_1_by_3() {
|
||||
f1 := fractions.fraction(9, 3)
|
||||
f2 := fractions.fraction(1, 3)
|
||||
q := f1 / f2
|
||||
assert q.f64() == 9.0
|
||||
assert q.str() == '9/1'
|
||||
}
|
||||
|
||||
fn test_3_by_7_over_1_by_4() {
|
||||
f1 := fractions.fraction(3, 7)
|
||||
f2 := fractions.fraction(1, 4)
|
||||
q := f1 / f2
|
||||
assert q.str() == '12/7'
|
||||
}
|
||||
|
||||
fn test_reciprocal_4_by_8() {
|
||||
f := fractions.fraction(4, 8)
|
||||
assert f.reciprocal().str() == '8/4'
|
||||
}
|
||||
|
||||
fn test_reciprocal_5_by_10() {
|
||||
f := fractions.fraction(5, 10)
|
||||
assert f.reciprocal().str() == '10/5'
|
||||
}
|
||||
|
||||
fn test_reciprocal_5_by_5() {
|
||||
f := fractions.fraction(5, 5)
|
||||
assert f.reciprocal().str() == '5/5'
|
||||
}
|
||||
|
||||
fn test_reciprocal_8_by_8() {
|
||||
f := fractions.fraction(8, 8)
|
||||
assert f.reciprocal().str() == '8/8'
|
||||
}
|
||||
|
||||
fn test_reciprocal_9_by_3() {
|
||||
f := fractions.fraction(9, 3)
|
||||
assert f.reciprocal().str() == '3/9'
|
||||
}
|
||||
|
||||
fn test_reciprocal_1_by_3() {
|
||||
f := fractions.fraction(1, 3)
|
||||
assert f.reciprocal().str() == '3/1'
|
||||
}
|
||||
|
||||
fn test_reciprocal_7_by_3() {
|
||||
f := fractions.fraction(7, 3)
|
||||
assert f.reciprocal().str() == '3/7'
|
||||
}
|
||||
|
||||
fn test_reciprocal_1_by_4() {
|
||||
f := fractions.fraction(1, 4)
|
||||
assert f.reciprocal().str() == '4/1'
|
||||
}
|
||||
|
||||
fn test_4_by_8_equals_5_by_10() {
|
||||
f1 := fractions.fraction(4, 8)
|
||||
f2 := fractions.fraction(5, 10)
|
||||
assert f1.equals(f2)
|
||||
f1 = fractions.fraction(1,2)
|
||||
f2 = fractions.fraction(3,4)
|
||||
}
|
||||
|
||||
fn test_1_by_2_does_not_equal_3_by_4() {
|
||||
f1 := fractions.fraction(1, 2)
|
||||
f2 := fractions.fraction(3, 4)
|
||||
assert !f1.equals(f2)
|
||||
}
|
||||
|
||||
fn test_gcd_and_reduce(){
|
||||
fn test_reduce_3_by_9() {
|
||||
f := fractions.fraction(3, 9)
|
||||
assert f.gcd() == 3
|
||||
assert f.reduce().equals(fractions.fraction(1, 3))
|
||||
}
|
||||
|
||||
fn test_1_by_3_less_than_2_by_4() {
|
||||
f1 := fractions.fraction(1, 3)
|
||||
f2 := fractions.fraction(2, 4)
|
||||
assert f1.lt(f2)
|
||||
assert f1.le(f2)
|
||||
}
|
||||
|
||||
fn test_2_by_3_greater_than_2_by_4() {
|
||||
f1 := fractions.fraction(2, 3)
|
||||
f2 := fractions.fraction(2, 4)
|
||||
assert f1.gt(f2)
|
||||
assert f1.ge(f2)
|
||||
}
|
||||
|
||||
fn test_5_by_7_not_less_than_2_by_4() {
|
||||
f1 := fractions.fraction(5, 7)
|
||||
f2 := fractions.fraction(2, 4)
|
||||
assert !f1.lt(f2)
|
||||
assert !f1.le(f2)
|
||||
}
|
||||
|
||||
fn test_49_by_75_not_greater_than_2_by_3() {
|
||||
f1 := fractions.fraction(49, 75)
|
||||
f2 := fractions.fraction(2, 3)
|
||||
assert !f1.gt(f2)
|
||||
assert !f1.ge(f2)
|
||||
}
|
Loading…
Reference in New Issue