【发布时间】:2016-11-20 04:49:33
【问题描述】:
我经常需要计算数值数组的均值和标准差。所以我为数字类型编写了一个小协议和扩展,似乎可以工作。如果我这样做有什么问题,我只想得到反馈。具体来说,我想知道是否有更好的方法来检查类型是否可以转换为 Double 以避免需要 asDouble 变量和 init(_:Double) 构造函数。
我知道允许算术的协议存在问题,但这似乎工作正常,并且使我不必将标准差函数放入需要它的类中。
protocol Numeric {
var asDouble: Double { get }
init(_: Double)
}
extension Int: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Float: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Double: Numeric {var asDouble: Double { get {return Double(self)}}}
extension CGFloat: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Array where Element: Numeric {
var mean : Element { get { return Element(self.reduce(0, combine: {$0.asDouble + $1.asDouble}) / Double(self.count))}}
var sd : Element { get {
let mu = self.reduce(0, combine: {$0.asDouble + $1.asDouble}) / Double(self.count)
let variances = self.map{pow(($0.asDouble - mu), 2)}
return Element(sqrt(variances.mean))
}}
}
编辑:我知道获取[Int].mean 和sd 是没有意义的,但我可能会在其他地方使用数字,所以这是为了保持一致性..
编辑:正如 @Severin Pappadeux 所指出的,方差可以通过避免数组上的三次传递的方式表示 - 均值然后映射然后均值。这是最终的标准差扩展
extension Array where Element: Numeric {
var sd : Element { get {
let sss = self.reduce((0.0, 0.0)){ return ($0.0 + $1.asDouble, $0.1 + ($1.asDouble * $1.asDouble))}
let n = Double(self.count)
return Element(sqrt(sss.1/n - (sss.0/n * sss.0/n)))
}}
}
【问题讨论】:
-
Int通常与较新设备上的Int64大小相同(>=iPhone 5S,它引入了 64 位处理器),因此除非您处理非常大的数字,否则应该这样做这不是问题:但只要知道init(_: Double)可能导致整数溢出(运行时异常),在Element = Int类型无法存储给定(巨大)Double值的整数表示的情况下。如果您只是自己使用 Swift 应用程序,这可能不是问题,但如果您向客户发货,请记住这一点。 -
好的,很有趣,谢谢。我不太可能将它与整数一起使用,并且我正在使用的值在生理上被限制在此应用程序中
-
@dfri 非常有用的评论!我想没有办法“捕捉”这种溢出?
-
@matt 谢谢!我想我们可以在
Numeric中包含一个静态min和max属性并检查双重表示(假设所有数值都可以被视为有效@987654336 范围的子集) @ 值;即,始终可以转换为Double,而没有任何溢出风险,但我猜在最坏的情况下,我们会得到此属性的Double.infinity) 与上面reduce操作中的Double值总和。例如。某事along these lines. -
@dfri 我可能是错的,但是通过阅读 Swift 3 中的新 FloatingPoint 协议,我认为它可能会为您节省一些工作。 — 有趣的是,如何在添加两个 Int 时“捕捉”溢出(通过使用特殊运算符),但在强制为 Double 时却无法“捕捉”它。
标签: arrays swift mean numeric deviation