Created
August 29, 2023 02:41
-
-
Save davidakoontz/1b0c88fcce0a7b8dab3be8f895865d87 to your computer and use it in GitHub Desktop.
Fraction class for Swift - provides support for rational number arithmetic.
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
// | |
// 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