Common square root in Swift
I am creating a generic vector class in Swift with three types: Float, Double and Int. This works so far, but when I try to calculate the length of a vector, I run into a problem.
The formula for vector length is the square root of (xΒ² + yΒ²). But since I am using a generic class for my vectors, the x and y values ββare named T.
The sqrt Swift function only accepts Double as an argument, but has no common argument.
Can the sqrt function be used with shared parameters?
Here is the piece of code I am using for the vector length and dot product:
protocol ArithmeticType {
func + (left: Self, right: Self) -> Self
func - (left: Self, right: Self) -> Self
func * (left: Self, right: Self) -> Self
func / (left: Self, right: Self) -> Self
prefix func - (left: Self) -> Self
func toDouble() -> Double
}
extension Double: ArithmeticType {
func toDouble() -> Double {
return Double(self)
}
}
extension Float: ArithmeticType {
func toDouble() -> Double {
return Double(self)
}
}
extension Int: ArithmeticType {
func toDouble() -> Double {
return Double(self)
}
}
class Vector<T where T: ArithmeticType, T: Comparable> {
var length: T { return sqrt((self β
self).toDouble()) }
}
infix operator β
{ associativity left }
func β
<T: ArithmeticType> (left: Vector<T>, right: Vector<T>) -> T {
var result: T? = nil
for (index, value) in enumerate(left.values) {
let additive = value * right.values[index]
if result == nil {
result = additive
} else if let oldResult = result {
result = oldResult + additive
}
}
if let unwrappedResult = result {
return unwrappedResult
}
}
source to share
I see you are using a custom protocol Arithmetic
to limit the general.
My approach would be to declare the 2 required method in this protocol: toDouble()
and fromDouble()
and implemented as extensions Float
, Double
as well Int
. Note that it fromDouble()
must be a static method.
So you can convert T
to Double
, hence you can use sqrt()
and convert back from Double
to T
.
Finally, there is an error in your code: if left
is an empty vector, the function will fail because the code in the loop will never be executed, so it will result
keep the initial value nil
. Forcing unwrapping in a statement return
will fail, throwing an exception.
source to share
In Swift 3, just use a protocol FloatingPoint
that is part of the standard library instead of your protocol ArithmeticType
. Float
and Double
comply with the protocol FloatingPoint
. The protocol FlotingPoint
has a method squareRoot()
, so
class Vector<T where T: FloatingPoint> {
var length: T { return (self β
self).squareRoot() }
}
must do the trick.
No need to import any libraries or runtime type checking! Calling this method turns into inline LLVM, so there are no function overhead calls. On x86, sqareRoot () should just generate one machine language instruction, leaving the result in register for a return statement to copy.
source to share
There is no common sqrt in Swift. But you can make your own generic.
import Foundation // for sqrt sqrtf
public func sqrt<T:FloatingPointType>(v:T) -> T {
if let vv = v as? Double {
return sqrt(vv) as! T
}
if let vv = v as? Float {
return sqrtf(vv) as! T
}
preconditionFailure()
}
print(sqrt(Float(9))) // == 3
print(sqrt(Double(9))) // == 3
source to share