Swift中的通用平方根

时间:2014-11-02 12:51:02

标签: math swift sqrt square-root

我正在Swift中构建一个通用向量类,有三种类型:Float,Double和Int。到目前为止这是有效的,但是当我尝试计算向量的长度时,我遇到了一个问题。

向量长度的公式是(x²+y²)的平方根。但是因为我为我的向量使用泛型类,所以x和y的值被称为T.

Swift的sqrt函数只接受Double作为参数但不接受泛型参数。

有没有办法将sqrt函数与泛型参数一起使用?

以下是我用于矢量长度和点积的代码片段:

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
    }
}

3 个答案:

答案 0 :(得分:2)

在Swift 3中,只需使用属于标准库而不是FloatingPoint协议的ArithmeticType协议。 FloatDouble符合FloatingPoint协议。 FlotingPoint协议有一个squareRoot()方法,所以

class Vector<T where T: FloatingPoint> {
    var length: T { return (self ⋅ self).squareRoot() }
}

应该这样做。

无需导入任何库或进行任何运行时类型检查!调用此方法会变成内置的LLVM,因此甚至没有任何函数调用开销。在x86上,sqareRoot()应该只生成一个机器语言指令,将结果保留在寄存器中以便复制return语句。

答案 1 :(得分:1)

我发现您正在使用自定义Arithmetic协议来约束通用。

我的方法是在该协议中声明2个必需的方法:toDouble()fromDouble(),并在FloatDoubleInt扩展中实现。请注意,fromDouble()应该是静态方法。

这样您就可以将T转换为Double,从而能够使用sqrt(),并从Double转换回T

最后,您的代码中存在一个错误:如果left是一个空向量,该函数将崩溃,因为循环中的代码永远不会被执行,因此result将保持不变其nil初始值。 return语句中的强制解包将失败,从而导致异常。

答案 2 :(得分:0)

Swift中没有通用的sqrt。但你可以制作自己的通用。

tuple