Skip to content

Instantly share code, notes, and snippets.

@kitschpatrol
Last active October 10, 2019 17:30
Show Gist options
  • Save kitschpatrol/5ce41e8505639eb5e9ce31a14815b43b to your computer and use it in GitHub Desktop.
Save kitschpatrol/5ce41e8505639eb5e9ce31a14815b43b to your computer and use it in GitHub Desktop.
Turn a decimal number into a fractional approximation rounded to a maximum denominator
import Foundation
import UIKit
// Turn a decimal number into a fractional approximation rounded to a maximum denominator
// https://github.com/jadengeller/fractional?
// https://stackoverflow.com/questions/35895154/decimal-to-fraction-conversion-in-swift#35895607
typealias Rational = (whole: Int, numerator: Int, denominator: Int)
func decimalToRational(of value: Double, withDenominator denominator: Int) -> Rational {
let wholePortion = floor(value)
let decimalPortion = value - wholePortion
let numerator: Int = Int(round(decimalPortion * Double(denominator)))
guard numerator != 0 else { return (Int(wholePortion), 0, 0) }
guard numerator != denominator else { return (Int(wholePortion + 1), 0, 0) }
return (Int(wholePortion), numerator, denominator)
}
func gcd(_ m: Int, _ n: Int) -> Int {
let r: Int = m % n
if r != 0 {
return gcd(n, r)
} else {
return n
}
}
func reduce(rational: Rational) -> Rational {
guard rational.denominator != 0 else { return rational }
var divisor = gcd(rational.numerator, rational.denominator)
if divisor < 0 { divisor *= -1 }
guard divisor != 0 else { return (rational.whole, rational.numerator, 0) }
return (rational.whole, rational.numerator / divisor, rational.denominator / divisor)
}
// Quick Test
for index in 1 ... 150 {
let measurementCm = Double(index)
let measurementInchDecimal = measurementCm / 2.54
let measurementInch = reduce(rational: decimalToRational(of: measurementInchDecimal, withDenominator: 8))
let measurementInchDecimalTruncated = String(format: "%.3f", measurementInchDecimal)
print("\(measurementCm) cm = \(measurementInchDecimalTruncated) in ≈ \(measurementInch.whole) \(measurementInch.numerator)/\(measurementInch.denominator) in")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment