| 1 | // Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | import math.big |
| 5 | import math.fractions |
| 6 | |
| 7 | // (Old) results are verified using https://www.calculatorsoup.com/calculators/math/fractions.php |
| 8 | // Newer ones are contrived for corner cases or prepared by hand. |
| 9 | fn bi(s string) big.Integer { |
| 10 | return big.integer_from_string(s) or { panic(err) } |
| 11 | } |
| 12 | |
| 13 | fn test_4_by_8_f64_and_str() { |
| 14 | f := fractions.fraction(4, 8) |
| 15 | assert f.f64() == 0.5 |
| 16 | assert f.str() == '4/8' |
| 17 | } |
| 18 | |
| 19 | fn test_10_by_5_f64_and_str() { |
| 20 | f := fractions.fraction(10, 5) |
| 21 | assert f.f64() == 2.0 |
| 22 | assert f.str() == '10/5' |
| 23 | } |
| 24 | |
| 25 | fn test_9_by_3_f64_and_str() { |
| 26 | f := fractions.fraction(9, 3) |
| 27 | assert f.f64() == 3.0 |
| 28 | assert f.str() == '9/3' |
| 29 | } |
| 30 | |
| 31 | fn test_4_by_minus_5_f64_and_str() { |
| 32 | f := fractions.fraction(4, -5) |
| 33 | assert f.f64() == -0.8 |
| 34 | assert f.str() == '-4/5' |
| 35 | } |
| 36 | |
| 37 | fn test_minus_7_by_minus_92_str() { |
| 38 | f := fractions.fraction(-7, -5) |
| 39 | assert f.str() == '7/5' |
| 40 | } |
| 41 | |
| 42 | fn test_4_by_8_plus_5_by_10() { |
| 43 | f1 := fractions.fraction(4, 8) |
| 44 | f2 := fractions.fraction(5, 10) |
| 45 | sum := f1 + f2 |
| 46 | assert sum.f64() == 1.0 |
| 47 | assert sum.str() == '1/1' |
| 48 | assert sum == fractions.fraction(1, 1) |
| 49 | } |
| 50 | |
| 51 | fn test_5_by_5_plus_8_by_8() { |
| 52 | f1 := fractions.fraction(5, 5) |
| 53 | f2 := fractions.fraction(8, 8) |
| 54 | sum := f1 + f2 |
| 55 | assert sum.f64() == 2.0 |
| 56 | assert sum.str() == '2/1' |
| 57 | assert sum == fractions.fraction(2, 1) |
| 58 | } |
| 59 | |
| 60 | fn test_9_by_3_plus_1_by_3() { |
| 61 | f1 := fractions.fraction(9, 3) |
| 62 | f2 := fractions.fraction(1, 3) |
| 63 | sum := f1 + f2 |
| 64 | assert sum.str() == '10/3' |
| 65 | assert sum == fractions.fraction(10, 3) |
| 66 | } |
| 67 | |
| 68 | fn test_3_by_7_plus_1_by_4() { |
| 69 | f1 := fractions.fraction(3, 7) |
| 70 | f2 := fractions.fraction(1, 4) |
| 71 | sum := f1 + f2 |
| 72 | assert sum.str() == '19/28' |
| 73 | assert sum == fractions.fraction(19, 28) |
| 74 | } |
| 75 | |
| 76 | fn test_36529_by_12409100000_plus_418754901_by_9174901000() { |
| 77 | f1 := fractions.fraction(i64(36529), i64(12409100000)) |
| 78 | f2 := fractions.fraction(i64(418754901), i64(9174901000)) |
| 79 | sum := f1 + f2 |
| 80 | assert sum.str() == '5196706591957729/113852263999100000' |
| 81 | } |
| 82 | |
| 83 | fn test_4_by_8_plus_minus_5_by_10() { |
| 84 | f1 := fractions.fraction(4, 8) |
| 85 | f2 := fractions.fraction(-5, 10) |
| 86 | diff := f2 + f1 |
| 87 | assert diff.f64() == 0 |
| 88 | assert diff.str() == '0/1' |
| 89 | } |
| 90 | |
| 91 | fn test_4_by_8_minus_5_by_10() { |
| 92 | f1 := fractions.fraction(4, 8) |
| 93 | f2 := fractions.fraction(5, 10) |
| 94 | diff := f2 - f1 |
| 95 | assert diff.f64() == 0 |
| 96 | assert diff.str() == '0/1' |
| 97 | } |
| 98 | |
| 99 | fn test_5_by_5_minus_8_by_8() { |
| 100 | f1 := fractions.fraction(5, 5) |
| 101 | f2 := fractions.fraction(8, 8) |
| 102 | diff := f2 - f1 |
| 103 | assert diff.f64() == 0 |
| 104 | assert diff.str() == '0/1' |
| 105 | } |
| 106 | |
| 107 | fn test_9_by_3_minus_1_by_3() { |
| 108 | f1 := fractions.fraction(9, 3) |
| 109 | f2 := fractions.fraction(1, 3) |
| 110 | diff := f1 - f2 |
| 111 | assert diff.str() == '8/3' |
| 112 | } |
| 113 | |
| 114 | fn test_3_by_7_minus_1_by_4() { |
| 115 | f1 := fractions.fraction(3, 7) |
| 116 | f2 := fractions.fraction(1, 4) |
| 117 | diff := f1 - f2 |
| 118 | assert diff.str() == '5/28' |
| 119 | } |
| 120 | |
| 121 | fn test_36529_by_12409100000_minus_418754901_by_9174901000() { |
| 122 | f1 := fractions.fraction(i64(36529), i64(12409100000)) |
| 123 | f2 := fractions.fraction(i64(418754901), i64(9174901000)) |
| 124 | sum := f1 - f2 |
| 125 | assert sum.str() == '-5196036292040471/113852263999100000' |
| 126 | } |
| 127 | |
| 128 | fn test_4_by_8_times_5_by_10() { |
| 129 | f1 := fractions.fraction(4, 8) |
| 130 | f2 := fractions.fraction(5, 10) |
| 131 | product := f1 * f2 |
| 132 | assert product.f64() == 0.25 |
| 133 | assert product.str() == '1/4' |
| 134 | } |
| 135 | |
| 136 | fn test_5_by_5_times_8_by_8() { |
| 137 | f1 := fractions.fraction(5, 5) |
| 138 | f2 := fractions.fraction(8, 8) |
| 139 | product := f1 * f2 |
| 140 | assert product.f64() == 1.0 |
| 141 | assert product.str() == '1/1' |
| 142 | } |
| 143 | |
| 144 | fn test_9_by_3_times_1_by_3() { |
| 145 | f1 := fractions.fraction(9, 3) |
| 146 | f2 := fractions.fraction(1, 3) |
| 147 | product := f1 * f2 |
| 148 | assert product.f64() == 1.0 |
| 149 | assert product.str() == '1/1' |
| 150 | } |
| 151 | |
| 152 | fn test_3_by_7_times_1_by_4() { |
| 153 | f1 := fractions.fraction(3, 7) |
| 154 | f2 := fractions.fraction(1, 4) |
| 155 | product := f2 * f1 |
| 156 | assert product.f64() == (3.0 / 28.0) |
| 157 | assert product.str() == '3/28' |
| 158 | } |
| 159 | |
| 160 | fn test_4_by_8_over_5_by_10() { |
| 161 | f1 := fractions.fraction(4, 8) |
| 162 | f2 := fractions.fraction(5, 10) |
| 163 | q := f1 / f2 |
| 164 | assert q.f64() == 1.0 |
| 165 | assert q.str() == '1/1' |
| 166 | } |
| 167 | |
| 168 | fn test_5_by_5_over_8_by_8() { |
| 169 | f1 := fractions.fraction(5, 5) |
| 170 | f2 := fractions.fraction(8, 8) |
| 171 | q := f1 / f2 |
| 172 | assert q.f64() == 1.0 |
| 173 | assert q.str() == '1/1' |
| 174 | } |
| 175 | |
| 176 | fn test_9_by_3_over_1_by_3() { |
| 177 | f1 := fractions.fraction(9, 3) |
| 178 | f2 := fractions.fraction(1, 3) |
| 179 | q := f1 / f2 |
| 180 | assert q.f64() == 9.0 |
| 181 | assert q.str() == '9/1' |
| 182 | } |
| 183 | |
| 184 | fn test_3_by_7_over_1_by_4() { |
| 185 | f1 := fractions.fraction(3, 7) |
| 186 | f2 := fractions.fraction(1, 4) |
| 187 | q := f1 / f2 |
| 188 | assert q.str() == '12/7' |
| 189 | } |
| 190 | |
| 191 | fn test_reciprocal_4_by_8() { |
| 192 | f := fractions.fraction(4, 8) |
| 193 | assert f.reciprocal().str() == '8/4' |
| 194 | } |
| 195 | |
| 196 | fn test_reciprocal_5_by_10() { |
| 197 | f := fractions.fraction(5, 10) |
| 198 | assert f.reciprocal().str() == '10/5' |
| 199 | } |
| 200 | |
| 201 | fn test_reciprocal_5_by_5() { |
| 202 | f := fractions.fraction(5, 5) |
| 203 | assert f.reciprocal().str() == '5/5' |
| 204 | } |
| 205 | |
| 206 | fn test_reciprocal_8_by_8() { |
| 207 | f := fractions.fraction(8, 8) |
| 208 | assert f.reciprocal().str() == '8/8' |
| 209 | } |
| 210 | |
| 211 | fn test_reciprocal_9_by_3() { |
| 212 | f := fractions.fraction(9, 3) |
| 213 | assert f.reciprocal().str() == '3/9' |
| 214 | } |
| 215 | |
| 216 | fn test_reciprocal_1_by_3() { |
| 217 | f := fractions.fraction(1, 3) |
| 218 | assert f.reciprocal().str() == '3/1' |
| 219 | } |
| 220 | |
| 221 | fn test_reciprocal_7_by_3() { |
| 222 | f := fractions.fraction(7, 3) |
| 223 | assert f.reciprocal().str() == '3/7' |
| 224 | } |
| 225 | |
| 226 | fn test_reciprocal_1_by_4() { |
| 227 | f := fractions.fraction(1, 4) |
| 228 | assert f.reciprocal().str() == '4/1' |
| 229 | } |
| 230 | |
| 231 | fn test_4_by_8_equals_5_by_10() { |
| 232 | f1 := fractions.fraction(4, 8) |
| 233 | f2 := fractions.fraction(5, 10) |
| 234 | assert f1 == f2 |
| 235 | } |
| 236 | |
| 237 | fn test_1_by_2_does_not_equal_3_by_4() { |
| 238 | f1 := fractions.fraction(1, 2) |
| 239 | f2 := fractions.fraction(3, 4) |
| 240 | assert f1 != f2 |
| 241 | } |
| 242 | |
| 243 | fn test_reduce_3_by_9() { |
| 244 | f := fractions.fraction(3, 9) |
| 245 | assert f.reduce() == fractions.fraction(1, 3) |
| 246 | } |
| 247 | |
| 248 | fn test_1_by_3_less_than_2_by_4() { |
| 249 | f1 := fractions.fraction(1, 3) |
| 250 | f2 := fractions.fraction(2, 4) |
| 251 | assert f1 < f2 |
| 252 | assert f1 <= f2 |
| 253 | } |
| 254 | |
| 255 | fn test_2_by_3_greater_than_2_by_4() { |
| 256 | f1 := fractions.fraction(2, 3) |
| 257 | f2 := fractions.fraction(2, 4) |
| 258 | assert f1 > f2 |
| 259 | assert f1 >= f2 |
| 260 | } |
| 261 | |
| 262 | fn test_5_by_7_not_less_than_2_by_4() { |
| 263 | f1 := fractions.fraction(5, 7) |
| 264 | f2 := fractions.fraction(2, 4) |
| 265 | assert !(f1 < f2) |
| 266 | assert !(f1 <= f2) |
| 267 | } |
| 268 | |
| 269 | fn test_49_by_75_not_greater_than_2_by_3() { |
| 270 | f1 := fractions.fraction(49, 75) |
| 271 | f2 := fractions.fraction(2, 3) |
| 272 | assert !(f1 > f2) |
| 273 | assert !(f1 >= f2) |
| 274 | } |
| 275 | |
| 276 | fn test_i32_rational_addition() { |
| 277 | f1 := fractions.rational(i32(4), i32(8)) |
| 278 | f2 := fractions.rational(i32(5), i32(10)) |
| 279 | sum := f1 + f2 |
| 280 | assert sum.str() == '1/1' |
| 281 | assert sum == fractions.rational(i32(1), i32(1)) |
| 282 | } |
| 283 | |
| 284 | fn test_big_fraction_normalizes_and_reduces() { |
| 285 | f := fractions.big_fraction(bi('-14'), bi('-21')) |
| 286 | assert f.str() == '14/21' |
| 287 | assert f.reciprocal().str() == '21/14' |
| 288 | assert f.reduce().str() == '2/3' |
| 289 | } |
| 290 | |
| 291 | fn test_big_fraction_addition() { |
| 292 | f1 := fractions.big_fraction(bi('100000000000000000000000000000000000000'), bi('3')) |
| 293 | f2 := fractions.big_fraction(bi('5'), bi('6')) |
| 294 | sum := f1 + f2 |
| 295 | assert sum.str() == '200000000000000000000000000000000000005/6' |
| 296 | assert sum > f1 |
| 297 | } |
| 298 | |
| 299 | fn test_big_fraction_exact_comparison_beyond_i64() { |
| 300 | huge := bi('9223372036854775808123456789') |
| 301 | f1 := fractions.big_fraction(huge + big.one_int, huge) |
| 302 | f2 := fractions.big_fraction(huge, huge + big.one_int) |
| 303 | assert f1 > f2 |
| 304 | assert f1 != f2 |
| 305 | } |
| 306 | |