Добавление двух дробей должно возвращать Fraction
, а не строку.Преобразование в строки выполняется только в том случае, если вам необходимо текстовое представление (например, для печати конечного результата).
Арифметические операции могут быть реализованы как операторы типа дроби:
struct Fraction {
// ...
static func +(lhs: Fraction, rhs: Fraction) -> Fraction { ... }
}
Это позволяет писать
let result = Fraction(1, 2) + Fraction(-1, 6)
Также предпочитайте типы значений над ссылочными типами, а постоянные свойства - над переменными.Первой реализацией может быть
struct Fraction {
let numerator: Int
let denominator: Int
init (_ numer: Int, _ denom: Int) {
self.numerator = numer
self.denominator = denom
}
static func +(lhs: Fraction, rhs: Fraction) -> Fraction {
return Fraction(lhs.numerator * rhs.denominator + lhs.denominator * rhs.numerator,
lhs.denominator * rhs.denominator)
}
}
Протокол CustomStringConvertible
принят для обеспечения текстового представления:
extension Fraction: CustomStringConvertible {
var description: String {
return "\(numerator)/\(denominator)"
}
}
Это уже работает
// Compute 1/2 - 1/6 + 1/3:
let result = Fraction(1, 2) + Fraction(-1, 6) + Fraction(1, 3)
print(result) // 24/36
, норезультат не является полностью удовлетворительным, потому что он не сводится к самым низким общим срокам.Также
print(Fraction(2, -3)) // 2/-3
не является оптимальным.
Вот немного более сложная версия, где результаты сводятся к самым низким показателям.Помимо служебной функции gcd
, все определяется внутри типа Fraction
.
// Greatest common divisor
func gcd(_ a : Int, _ b : Int) -> Int {
var (a, b) = (a, b)
while b != 0 {
(a, b) = (b, a % b)
}
return a
}
struct Fraction {
let numerator: Int
let denominator: Int
init (_ numer: Int, _ denom: Int, reduce: Bool = false) {
if reduce {
let commonFactor = gcd(numer, denom)
self.numerator = numer / commonFactor
self.denominator = denom / commonFactor
} else {
self.numerator = numer
self.denominator = denom
}
}
static func +(lhs: Fraction, rhs: Fraction) -> Fraction {
return Fraction(lhs.numerator * rhs.denominator + lhs.denominator * rhs.numerator,
lhs.denominator * rhs.denominator, reduce: true)
}
}
extension Fraction: CustomStringConvertible {
var description: String {
if denominator == 1 {
return "\(numerator)"
} else if denominator < 0 {
return "\(-numerator)/\(-denominator)"
} else {
return "\(numerator)/\(denominator)"
}
}
}
Пример использования:
// Compute 1/2 - 1/6 + 1/3:
let result = Fraction(1, 2) + Fraction(-1, 6) + Fraction(1, 3)
print(result) // 2/3
Теперь вы можете добавлять другие операторы (например, * 1035).*, *
, /
), проверка ошибок (например, для нулевого знаменателя или целочисленное переполнение), дополнительные методы экземпляра (например, «абсолютное значение») и т. Д.