I am trying to make a quadratic equation function in Swift.
While working on this, I found that I needed to overload some operators so that I could work with tuples alongside other numbers (Double
in this case), this is because I needed to use my custom ±
operator. Despite the fact that I was only working with value of type Double
in my quadratic function, I decided that I wanted to use generics to make my overloaded operators more flexible for future use.
But–for a reason I don't understand–I am receiving errors regarding the declaration of the overloaded /
operator.
±
Operator - Workinginfix operator ± : AdditionPrecedence
public func ± <T: Numeric>(left: T, right: T) -> (T, T) {
return (left + right, left - right)
}
func quadratic(a: Double, b: Double, c: Double) -> (Double, Double) {
return (-b ± sqrt((b * b) - (4 * a * c))) / (2 * a)
}
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 / rhs, lhs.1 / rhs)
}
func * <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 * rhs, lhs.1 * rhs)
}
func - <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 - rhs, lhs.1 - rhs)
}
func + <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 + rhs, lhs.1 + rhs)
}
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs / rhs.0, lhs / rhs.1)
}
func * <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs * rhs.0, lhs * rhs.1)
}
func - <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs - rhs.0, lhs - rhs.1)
}
func + <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs + rhs.0, lhs + rhs.1)
}
1. I only receive these errors with the /
operator, not with any of the other overloaded operators (+
, -
, or *
).
/
s) - Not Working//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: (T, T), rhs: T) -> (T, T) {
return (lhs.0 / rhs, lhs.1 / rhs)
}
//Binary operator '/' cannot be applied to two 'T' operands
func / <T: Numeric>(lhs: T, rhs: (T, T)) -> (T, T) {
return (lhs / rhs.0, lhs / rhs.1)
}
Hypothesis: I think that the fact that I am using the operator /
within the declaration of the overloaded /
operator itself–despite the fact that it is being used in a different context–is causing the error.
How do I resolve the errors while still maintaining the flexibility of my overloaded operators?
Bonus Question 1: If I can (I think that I would probably have to return a String
to accomplish this), I would also like to make a separate quadratic function that can return an exact solution?
Bonus Question 2: Also if anyone knows how to make a separate function that can solve a cubic equation rather than quadratic, that would be appreciated too.
The key is to define /
when T
is FloatingPoint
or BinaryInteger
, and not just any Numeric
. Furthermore, I would recommend you use an enum, to properly model the three possible outcomes of a quadratic function:
import Foundation
infix operator ± : AdditionPrecedence
public enum QuadraticRoots<T> {
case two(T, T)
case one(T)
case none
func applyWithSelfOnLeft(_ fn: (T, T) -> T, withOperand value: T) -> QuadraticRoots {
switch self {
case let .two(a, b): return .two(fn(a, value), fn(b, value))
case let .one(a): return .one(fn(a, value))
case .none: return .none
}
}
func applyWithSelfOnRight(withOperand value: T, _ fn: (T, T) -> T) -> QuadraticRoots {
switch self {
case let .two(a, b): return .two(fn(value, a), fn(value, b))
case let .one(a): return .one(fn(value, a))
case .none: return .none
}
}
}
public func ± <T: Numeric>(left: T, right: T) -> QuadraticRoots<T> {
return QuadraticRoots.two(left + right, left - right)
}
extension QuadraticRoots where T: Numeric {
static func + (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((+), withOperand: rhs)
}
static func - (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((-), withOperand: rhs)
}
static func * (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((*), withOperand: rhs)
}
static func + (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (+))
}
static func - (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (-))
}
static func * (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (*))
}
static func discriminantOf(xSquared a: T, x b: T, c: T) -> T { return b*b - 4*a*c }
}
extension QuadraticRoots where T: FloatingPoint {
static func / (quadRoots: QuadraticRoots, rhs: T) -> QuadraticRoots {
return quadRoots.applyWithSelfOnLeft((/), withOperand: rhs)
}
static func / (lhs: T, quadRoots: QuadraticRoots) -> QuadraticRoots {
return quadRoots.applyWithSelfOnRight(withOperand: lhs, (/))
}
static func solveFrom(xSquared a: T, x b: T, c: T) -> QuadraticRoots {
let discriminant = self.discriminantOf(xSquared: a, x: b, c: c)
return (-b ± sqrt(discriminant)) / (2 * a)
}
}
let a = 5 ± 10
print(a)
print(a + 2)
print(a - 2)
print(a * 2)
print(2 + a)
print(2 - a)
print(2 * a)
//print(a / 2)