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