Created
February 8, 2018 16:16
-
-
Save bppr/9cd96215d04e2f9562ee58fd8e21184e to your computer and use it in GitHub Desktop.
Ratio.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// expressible as integer literal | |
// due to type inference from our variable declaration, | |
// 1/5 really evaluates to Ratio(1) / Ration(5), | |
// which returns Ratio(1, 5) | |
let r: Ratio = 1/5 // => 1/5 | |
// simple arithmetic operations available | |
r + 1/5 // => 2/5 | |
r / 5 // => 1/25 | |
// displays whole numbers without a denominator | |
r * -5 // => -1 | |
var r2: Ratio = 1/4 // => 1/4 | |
// allows re-assignment arithmetic operators | |
r2 /= 4 // => 1/16 | |
r2 += 1/16 // => 1/8 | |
// can be equated to other rationals | |
r2 == 1/8 // => true | |
// can be compared to other rationals | |
r2 < 1/4 // => true | |
// can be converted to decimal types | |
// as with all fp operations, potential precision-loss | |
r2.asFloat // => 0.125 | |
// normalizes negativity to numerator-side | |
let n: Ratio = 1 / -5 // => -1/5 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fileprivate func gcd(_ a: Int, _ b: Int) -> Int { | |
return b == 0 ? a : gcd(b, a % b) | |
} | |
fileprivate func abs(_ n: Int) -> Int { | |
return n > 0 ? n : -n | |
} | |
struct Ratio { | |
let numerator: Int | |
let denominator: Int | |
init(_ numerator: Int, _ denominator: Int = 1) { | |
var (numerator, denominator) = (numerator, denominator) | |
let divisor = gcd(numerator, denominator) | |
numerator /= divisor | |
denominator /= divisor | |
if denominator < 0 { | |
(numerator, denominator) = (-numerator, -denominator) | |
} | |
self.numerator = numerator | |
self.denominator = denominator | |
} | |
var asDouble: Double { return Double(numerator) / Double(denominator) } | |
var asFloat: Float { return Float(numerator) / Float(denominator) } | |
var abs: Ratio { return self.numerator < 0 ? -self : self } | |
} | |
extension Ratio: CustomDebugStringConvertible { | |
var debugDescription: String { | |
let denom = denominator == 1 ? "" : "/\(String(describing: denominator))" | |
return "\(numerator)\(denom)" | |
} | |
} | |
extension Ratio: ExpressibleByIntegerLiteral { | |
init(integerLiteral value: IntegerLiteralType) { | |
self.init(value) | |
} | |
} | |
extension Ratio: Equatable {} | |
func ==(lhs: Ratio, rhs: Ratio) -> Bool { | |
return lhs.numerator == rhs.numerator && lhs.denominator == rhs.denominator | |
} | |
extension Ratio: Comparable {} | |
func <(lhs: Ratio, rhs: Ratio) -> Bool { | |
return (rhs.abs - lhs.abs).numerator > 0 | |
} | |
func +(lhs: Ratio, rhs: Ratio) -> Ratio { | |
return Ratio( | |
lhs.numerator * rhs.denominator + rhs.numerator * lhs.denominator, | |
lhs.denominator * rhs.denominator | |
) | |
} | |
func +=(lhs: inout Ratio, rhs: Ratio) { | |
lhs = lhs + rhs | |
} | |
prefix func -(r: Ratio) -> Ratio { | |
return Ratio(-r.numerator, r.denominator) | |
} | |
func -(lhs: Ratio, rhs: Ratio) -> Ratio { | |
return lhs + (-rhs) | |
} | |
func -=(lhs: inout Ratio, rhs: Ratio) { | |
lhs = lhs - rhs | |
} | |
func *(lhs: Ratio, rhs: Ratio) -> Ratio { | |
return Ratio(lhs.numerator * rhs.numerator,lhs.denominator * rhs.denominator) | |
} | |
func *=(lhs: inout Ratio, rhs: Ratio) { | |
lhs = lhs * rhs | |
} | |
func /(lhs: Ratio, rhs: Ratio) -> Ratio { | |
return lhs * Ratio(rhs.denominator, rhs.numerator) | |
} | |
func /=(lhs: inout Ratio, rhs: Ratio) { | |
lhs = lhs / rhs | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment