|
1 | 1 | package com.github.ephemient.aoc2022
|
2 | 2 |
|
3 |
| -import kotlin.math.abs |
4 |
| - |
5 | 3 | @Day
|
6 | 4 | class Day21(lines: List<String>) {
|
7 | 5 | private val monkeys = buildMap {
|
@@ -83,48 +81,51 @@ class Day21(lines: List<String>) {
|
83 | 81 | private data class Rational(val numerator: Long, val denominator: Long = 1) {
|
84 | 82 | init {
|
85 | 83 | require(denominator > 0)
|
| 84 | + assert(gcd(numerator, denominator) == 1L) |
86 | 85 | }
|
87 | 86 |
|
88 | 87 | operator fun plus(other: Rational): Rational {
|
89 |
| - val denominator = this.denominator * other.denominator / gcd(this.denominator, other.denominator) |
90 |
| - val numerator = this.numerator * (denominator / this.denominator) + |
91 |
| - other.numerator * (denominator / other.denominator) |
92 |
| - val gcd = abs(gcd(numerator, denominator)) |
93 |
| - return Rational(numerator / gcd, denominator / gcd) |
| 88 | + val gcd1 = gcd(this.denominator, other.denominator) |
| 89 | + val multiplier = this.denominator / gcd1 |
| 90 | + val denominator = multiplier * other.denominator |
| 91 | + val numerator = this.numerator * (other.denominator / gcd1) + other.numerator * multiplier |
| 92 | + val gcd2 = gcd(numerator, denominator) |
| 93 | + return Rational(numerator / gcd2, denominator / gcd2) |
94 | 94 | }
|
95 | 95 |
|
96 | 96 | operator fun minus(other: Rational): Rational {
|
97 |
| - val denominator = this.denominator * other.denominator / gcd(this.denominator, other.denominator) |
98 |
| - val numerator = this.numerator * (denominator / this.denominator) - |
99 |
| - other.numerator * (denominator / other.denominator) |
100 |
| - val gcd = abs(gcd(numerator, denominator)) |
101 |
| - return Rational(numerator / gcd, denominator / gcd) |
| 97 | + val gcd1 = gcd(this.denominator, other.denominator) |
| 98 | + val multiplier = this.denominator / gcd1 |
| 99 | + val denominator = multiplier * other.denominator |
| 100 | + val numerator = this.numerator * (other.denominator / gcd1) - other.numerator * multiplier |
| 101 | + val gcd2 = gcd(numerator, denominator) |
| 102 | + return Rational(numerator / gcd2, denominator / gcd2) |
102 | 103 | }
|
103 | 104 |
|
104 | 105 | operator fun times(other: Rational): Rational {
|
105 |
| - val numerator = this.numerator * other.numerator |
106 |
| - val denominator = this.denominator * other.denominator |
107 |
| - val gcd = abs(gcd(numerator, denominator)) |
108 |
| - return Rational(numerator / gcd, denominator / gcd) |
| 106 | + val gcd1 = gcd(this.numerator, other.denominator) |
| 107 | + val gcd2 = gcd(other.numerator, this.denominator) |
| 108 | + val numerator = (this.numerator / gcd1) * (other.numerator / gcd2) |
| 109 | + val denominator = (this.denominator / gcd2) * (other.denominator / gcd1) |
| 110 | + return Rational(numerator, denominator) |
109 | 111 | }
|
110 | 112 |
|
111 | 113 | operator fun div(other: Rational): Rational {
|
112 | 114 | require(other.numerator != 0L)
|
113 |
| - val numerator = this.numerator * other.denominator |
114 |
| - val denominator = this.denominator * other.numerator |
115 |
| - val gcd = gcd(numerator, denominator).let { if (it < 0 != denominator < 0) -it else it } |
116 |
| - return Rational(numerator / gcd, denominator / gcd) |
| 115 | + val gcd1 = gcd(this.numerator, other.numerator) |
| 116 | + val gcd2 = gcd(other.denominator, this.denominator) |
| 117 | + val numerator = (this.numerator / gcd1) * (other.denominator / gcd2) |
| 118 | + val denominator = (this.denominator / gcd2) * (other.numerator / gcd1) |
| 119 | + return Rational(numerator, denominator) |
117 | 120 | }
|
118 | 121 | }
|
119 | 122 |
|
120 | 123 | companion object {
|
121 | 124 | private fun gcd(a: Long, b: Long): Long {
|
122 | 125 | var x = a
|
123 | 126 | var y = b
|
124 |
| - while (y != 0L) { |
125 |
| - x = y.also { y = x % y } |
126 |
| - } |
127 |
| - return x |
| 127 | + while (y != 0L) x = y.also { y = x % y } |
| 128 | + return if (x < 0 != b < 0) -x else x |
128 | 129 | }
|
129 | 130 | }
|
130 | 131 | }
|
0 commit comments