Math Swift中的一般平方根

Math Swift中的一般平方根,math,swift,sqrt,square-root,Math,Swift,Sqrt,Square Root,我正在Swift中构建一个通用的向量类,它有三种类型:Float、Double和Int。到目前为止,这是有效的,但是当我试图计算向量的长度时,我遇到了一个问题 矢量长度的公式是(x²+y²)的平方根。但是,因为我对向量使用了泛型类,所以x和y的值被称为T Swift的sqrt函数只接受Double作为参数,而不接受泛型参数 有没有办法将sqrt函数与通用参数一起使用 下面是我用于向量长度和点积的代码片段: protocol ArithmeticType { func + (left: S

我正在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
    }
}
协议算术类型{
func+(左:自,右:自)->Self
func-(左:自,右:自)->Self
func*(左:自,右:自)->Self
func/(左:自,右:自)->Self
前缀func-(左:Self)->Self
func toDouble()->Double
}
扩展双精度:算术类型{
func toDouble()->Double{
返回双(自我)
}
}
扩展浮点:算术类型{
func toDouble()->Double{
返回双(自我)
}
}
扩展名Int:算术类型{
func toDouble()->Double{
返回双(自我)
}
}
类向量{
变量长度:T{return sqrt((self⋅ self.toDouble())}
}
中缀运算符⋅ {左结合性}
func⋅ (左:向量,右:向量)->T{
var结果:T=零
用于枚举(左.值)中的(索引,值){
让加法=值*右。值[索引]
如果结果==nil{
结果=加法
}否则,如果让oldResult=result{
结果=旧结果+加法
}
}
如果让unwrappedResult=结果{
返回未包装结果
}
}

我看到您正在使用自定义的
算术协议来约束泛型

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

通过这种方式,您可以将
T
转换为
Double
,因此可以使用
sqrt()
,并从
Double
转换回
T


最后,代码中有一个bug:如果
left
是一个空向量,函数将崩溃,因为循环中的代码永远不会执行,因此
result
将保留其
nil
初始值。
return
语句中的强制展开将失败,导致异常。

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

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
<代码>导入基础//用于SqRT-SqRTF 公共职能sqrt(v:T)->T{ 如果让vv=v为?双{ 将sqrt(vv)返回为!T } 如果让vv=v作为浮动{ 将sqrtf(vv)返回为!T } 预处理失败() } 打印(sqrt(Float(9)))/==3 打印(sqrt(双(9))//==3
在Swift 3中,只需使用标准库中的
浮点
协议,而不是您的
算术类型
协议
Float
Double
符合
FloatingPoint
协议。
FlotingPoint
协议有一个
squareRoot()方法,所以

class Vector<T where T: FloatingPoint> {
    var length: T { return (self ⋅ self).squareRoot() }
}
类向量{
变量长度:T{return(self⋅ self).平方根()}
}
我们应该做到这一点


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

即使对于整数向量,长度通常也是一个浮点数(例如,长度([1,1]=sqrt(2)),所以您可以转换为双精度。–顺便说一句,
算术类型在哪里定义?为什么不编写您自己的sqrt函数。对于我来说,这似乎是很多额外的膨胀代码,只是为了获得类似c11的功能。然后您可以自定义整数来执行ceil、floor等操作,或者使用任意精度的libI现在已经在算术类型协议中实现了toDouble()方法,并且做了
sqrt((self⋅ self).toDouble())
在长度变量中。但现在Swift抛出此错误:
无法使用类型为“Double”的参数调用“sqrt”
,而当我键入
sqrt
Xcode时,它会自动完成并显示sqrt(Double)有效。我的ArithmeticType协议中的代码现在是:protocol ArithmeticType{func toDouble()->Double}扩展Int:算术类型{func toDouble()->Double{return self}}浮点和Double实现是相等的,认为
func toDouble()->Double{return self}
应该是
func toDouble()->Double{return Double(self)}
-您必须转换,因为没有从
Int
Double
的隐式转换,我现在应用了该更改,但是sqrt函数仍然需要一个双参数,即使我为它提供了一个双参数。它似乎正确地转换了它,因为在.toDouble()之前它给了我一个类型为T的参数。你能发布代码吗?请在你的问题中添加一个更新,这样代码更容易阅读。length属性的类型现在应该是Double而不是T。你不处理Int的情况。