Skip to content

Instantly share code, notes, and snippets.

@davidakoontz
Created August 29, 2023 02:41
Show Gist options
  • Save davidakoontz/1b0c88fcce0a7b8dab3be8f895865d87 to your computer and use it in GitHub Desktop.
Save davidakoontz/1b0c88fcce0a7b8dab3be8f895865d87 to your computer and use it in GitHub Desktop.
Fraction class for Swift - provides support for rational number arithmetic.
//
// Fraction.swift
//
// Created by David Koontz on 8/28/23.
//
import Foundation
// Wonder if a Rational Fraction class would be valuable in Swift.
// - Use Int to model the numerator & denominator
// - Provide several math functions (add, subtract, multiple, divide) need lots more...
// - needed a reduce() which calls GCD().
//
struct Fraction : Equatable {
var numerator: Int
var denominator: Int
init(_ numerator: Int, _ denominator: Int) {
assert(denominator != 0, "Denominator cannot be zero")
self.numerator = numerator
self.denominator = denominator
}
init( numerator: Int, denominator: Int) {
assert(denominator != 0, "Denominator cannot be zero")
self.numerator = numerator
self.denominator = denominator
}
init(_ numerator: Int ) {
self.denominator = 1 // when not specified
assert(denominator != 0, "Denominator cannot be zero")
self.numerator = numerator
}
init() {
self.denominator = 1 // when not specified
assert(denominator != 0, "Denominator cannot be zero")
self.numerator = 0 // when not specified
}
init(_ double: Double) {
let precision = 1000000 // Define the precision you want
let integerPart = Int(double)
let decimalPart = double - Double(integerPart)
let roundedDecimalPart = (decimalPart * Double(precision)).rounded()
self.numerator = integerPart * precision + Int(roundedDecimalPart)
self.denominator = precision
self.reduce() // Assuming you have a reduce function to simplify the fraction
}
func add(_ f: Fraction) -> Fraction {
let resultNumerator = numerator * f.denominator + denominator * f.numerator
let resultDenominator = denominator * f.denominator
return Fraction( resultNumerator, resultDenominator)
}
func subtract(_ f: Fraction) -> Fraction {
let resultNumerator = numerator * f.denominator - denominator * f.numerator
let resultDenominator = denominator * f.denominator
return Fraction( resultNumerator, resultDenominator)
}
func multiply(_ f: Fraction) -> Fraction {
return Fraction( numerator * f.numerator, denominator * f.denominator)
}
func divide(_ f: Fraction) -> Fraction {
assert(f.numerator != 0, "Cannot divide by zero")
return Fraction( numerator * f.denominator, denominator * f.numerator)
}
// Function to find the Greatest Common Divisor (GCD)
func gcd(_ a: Int, _ b: Int) -> Int {
let r = a % b
if r != 0 {
return gcd(b, r)
} else {
return b
}
}
/*
In this code, the `gcd` function uses the Euclidean algorithm to find the greatest common divisor of two integers. The `reduce` function then uses this to simplify the fraction. Note that the `reduce` function is marked with `mutating` keyword because it modifies the struct's properties.
*/
// Function to reduce the fraction to its simplest form
mutating func reduce() -> Fraction {
let gcdValue = gcd(numerator, denominator)
numerator /= gcdValue
denominator /= gcdValue
return Fraction( numerator, denominator)
}
}
/*
Include the Unit Test inside file for Gist
//
// FractionTests.swift
//
// Created by David Koontz on 8/28/23.
//
import XCTest
@testable import Kaktovik_Calculator
final class FractionTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func test_negitive_denominator() {
let sixteenTenths = Fraction( 16, -10)
let eightFifths = Fraction( -8, 5)
var sum = sixteenTenths.add(eightFifths)
let redux: Fraction = sum.reduce()
let known = Fraction( 16, -5)
XCTAssertEqual(redux, known)
}
func test_empty_denominator() {
let onetwentythree = Fraction( 123 )
let eightFifths = Fraction( 8, 5)
var sum = onetwentythree.add(eightFifths)
let redux: Fraction = sum.reduce()
let known = Fraction( 623, 5)
XCTAssertEqual(redux, known)
}
func test_denominator_of_one() {
let onetwentythree = Fraction( 123, 1)
let eightFifths = Fraction( 8, 5)
var sum = onetwentythree.add(eightFifths)
let redux: Fraction = sum.reduce()
let known = Fraction( 623, 5)
XCTAssertEqual(redux, known)
}
func test_denominator_of_zero() {
let zero = Fraction()
let known = Fraction( 0, 1)
XCTAssertEqual(zero, known)
}
func test_2476979795053773_BY_2251799813685248() {
var big = Fraction(2476979795053773, 2251799813685248)
let known = big.reduce()
XCTAssertEqual(big, known)
}
func test_11_BY_ten() {
var big = Fraction(11, 10)
let known = big.reduce()
XCTAssertEqual(big, known)
}
func test_Fraction_init_with_Double() {
var big = Fraction(11.11)
let known = Fraction(1111, 100)
XCTAssertEqual(big, known)
}
/* From Python Fraction class
from fractions import Fraction
done Fraction(16, -10)
done Fraction(-8, 5)
done Fraction(123)
done Fraction(123, 1)
done Fraction()
done Fraction(0, 1)
Fraction('3/7')
Fraction(3, 7)
Fraction(' -3/7 ')
Fraction(-3, 7)
Fraction('1.414213 \t\n')
Fraction(1414213, 1000000)
Fraction('-.125')
Fraction(-1, 8)
Fraction('7e-6')
Fraction(7, 1000000)
done Fraction(2.25)
Fraction(9, 4)
Fraction(1.1)
done Fraction(2476979795053773, 2251799813685248)
from decimal import Decimal
Fraction(Decimal('1.1'))
Fraction(11, 10)
*/
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment