@@ -47,7 +47,7 @@ public struct Fraction {
4747
4848 /// Initialize by reducing and normalizing the fraction.
4949 public init ( reducing numerator: Int , _ denominator: Int ) {
50- let reduced = Self . reduce ( n: numerator, d: denominator)
50+ let reduced = reduce ( n: numerator, d: denominator)
5151 self . numerator = reduced. n
5252 self . denominator = reduced. d
5353 _isReduced = true
@@ -137,59 +137,18 @@ extension Fraction {
137137 return isNegative ? norm. negated ( ) : norm
138138 }
139139
140- /// Internal:
141- /// Reduce a fraction to its simplest form.
142- /// This also normalizes signs.
143- static func reduce( n: Int , d: Int ) -> ( n: Int , d: Int ) {
144- let ( absN, signN) = n < 0 ? ( - n, - 1 ) : ( n, 1 )
145- let ( absD, signD) = d < 0 ? ( - d, - 1 ) : ( d, 1 )
146- var v = n
147- var u = d
148-
149- // Euclid's solution to finding the Greatest Common Denominator
150- while ( v != 0 ) {
151- ( v, u) = ( u % v, v)
152- }
153-
154- var outN = absN / u * signN
155- var outD = absD / u * signD
156-
157- // final check to normalize if necessary
158- if outN >= 0 , outD < 0 {
159- outN = - outN
160- outD = - outD
161- }
162-
163- return ( outN, outD)
164- }
165-
166140 /// Returns a new instance reduced to its simplest form.
167141 /// This also normalizes signs.
168142 public func reduced( ) -> Self {
169143 if _isReduced == true { return self }
170144 return Fraction ( reducing: numerator, denominator)
171145 }
172146
173- /// Internal:
174- /// Normalize a fraction.
175- /// Fractions with two negative signs are normalized to two positive signs.
176- /// Fractions with negative denominator are normalized to negative numerator and positive denominator.
177- static func normalize( n: Int , d: Int ) -> ( n: Int , d: Int ) {
178- var n = n
179- var d = d
180- if n >= 0 && d >= 0 { return ( n: n, d: d) }
181- if ( n < 0 && d < 0 ) || ( d < 0 ) {
182- n *= - 1
183- d *= - 1
184- }
185- return ( n: n, d: d)
186- }
187-
188147 /// Returns a new instance normalized.
189148 /// Fractions with two negative signs are normalized to two positive signs.
190149 /// Fractions with negative denominator are normalized to negative numerator and positive denominator.
191150 func normalized( ) -> Self {
192- let result = Self . normalize ( n: numerator, d: denominator)
151+ let result = normalize ( n: numerator, d: denominator)
193152 return Fraction ( result. n, result. d)
194153 }
195154
@@ -208,7 +167,33 @@ extension Fraction {
208167 }
209168}
210169
211- // MARK: Double
170+ // MARK: - Math
171+
172+ extension Fraction {
173+ public static func + ( lhs: Self , rhs: Self ) -> Self {
174+ if lhs. denominator == rhs. denominator {
175+ return Fraction ( reducing: lhs. numerator + rhs. numerator, lhs. denominator)
176+ }
177+
178+ let lcm = leastCommonMultiple ( lhs: lhs. denominator, rhs: rhs. denominator)
179+
180+ let num = ( lhs. numerator * lcm. lhsMultiplier) + ( rhs. numerator * lcm. rhsMultiplier)
181+ return Fraction ( reducing: num, lcm. denominator)
182+ }
183+
184+ public static func - ( lhs: Self , rhs: Self ) -> Self {
185+ if lhs. denominator == rhs. denominator {
186+ return Fraction ( reducing: lhs. numerator - rhs. numerator, lhs. denominator)
187+ }
188+
189+ let lcm = leastCommonMultiple ( lhs: lhs. denominator, rhs: rhs. denominator)
190+
191+ let num = ( lhs. numerator * lcm. lhsMultiplier) - ( rhs. numerator * lcm. rhsMultiplier)
192+ return Fraction ( reducing: num, lcm. denominator)
193+ }
194+ }
195+
196+ // MARK: - Double
212197
213198extension Double {
214199 /// Internal:
@@ -236,7 +221,7 @@ extension Double {
236221 }
237222}
238223
239- // MARK: FCPXML Encoding
224+ // MARK: - FCPXML Encoding
240225
241226extension Fraction {
242227 /// Initializes from an encoded Final Cut Pro FCPXML time value string.
@@ -305,3 +290,78 @@ extension Fraction {
305290 : " \( reduced. numerator) / \( reduced. denominator) s "
306291 }
307292}
293+
294+ // MARK: - Math Functions
295+
296+ /// Internal:
297+ /// Normalize a fraction.
298+ /// Fractions with two negative signs are normalized to two positive signs.
299+ /// Fractions with negative denominator are normalized to negative numerator and positive denominator.
300+ func normalize( n: Int , d: Int ) -> ( n: Int , d: Int ) {
301+ var n = n
302+ var d = d
303+ if n >= 0 && d >= 0 { return ( n: n, d: d) }
304+ if ( n < 0 && d < 0 ) || ( d < 0 ) {
305+ n *= - 1
306+ d *= - 1
307+ }
308+ return ( n: n, d: d)
309+ }
310+
311+ /// Internal:
312+ /// Reduce a fraction to its simplest form.
313+ /// This also normalizes signs.
314+ func reduce( n: Int , d: Int ) -> ( n: Int , d: Int ) {
315+ let ( absN, signN) = n < 0 ? ( - n, - 1 ) : ( n, 1 )
316+ let ( absD, signD) = d < 0 ? ( - d, - 1 ) : ( d, 1 )
317+ var v = n
318+ var u = d
319+
320+ // Euclid's solution to finding the Greatest Common Denominator
321+ while ( v != 0 ) {
322+ ( v, u) = ( u % v, v)
323+ }
324+
325+ var outN = absN / u * signN
326+ var outD = absD / u * signD
327+
328+ // final check to normalize if necessary
329+ if outN >= 0 , outD < 0 {
330+ outN = - outN
331+ outD = - outD
332+ }
333+
334+ return ( outN, outD)
335+ }
336+
337+ /// Internal:
338+ /// Returns greatest common divisor of two numbers.
339+ func greatestCommonDivisor( _ n1: Int , _ n2: Int ) -> Int {
340+ var x = 0
341+ var y = max ( n1, n2)
342+ var z = min ( n1, n2)
343+
344+ while z != 0 {
345+ x = y
346+ y = z
347+ z = x % y
348+ }
349+
350+ return y
351+ }
352+
353+ /// Internal:
354+ /// Returns least common multiple of two numbers and their respective multipliers.
355+ func leastCommonMultiple(
356+ lhs: Int , rhs: Int
357+ ) -> ( denominator: Int , lhsMultiplier: Int , rhsMultiplier: Int ) {
358+ let denominator = lhs * rhs / greatestCommonDivisor( lhs, rhs)
359+ let lhsMultiplier = denominator / lhs
360+ let rhsMultiplier = denominator / rhs
361+
362+ return (
363+ denominator: denominator,
364+ lhsMultiplier: lhsMultiplier,
365+ rhsMultiplier: rhsMultiplier
366+ )
367+ }
0 commit comments