【发布时间】:2014-07-26 18:39:53
【问题描述】:
我没有在 Swift 语言参考中看到基本算术运算符中定义的幂运算符。
语言中真的没有预定义的整数或浮点取幂运算符吗?
【问题讨论】:
-
就我而言,这是解决方案:stackoverflow.com/a/28710112/2161007
标签: swift exponentiation
我没有在 Swift 语言参考中看到基本算术运算符中定义的幂运算符。
语言中真的没有预定义的整数或浮点取幂运算符吗?
【问题讨论】:
标签: swift exponentiation
没有运算符,但您可以像这样使用 pow 函数:
return pow(num, power)
如果你愿意,你也可以让操作员像这样调用 pow 函数:
infix operator ** { associativity left precedence 170 }
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
2.0**2.0 //4.0
【讨论】:
**,这样你就可以在整数上使用它并且不会与XOR冲突。
-2.0**2.0 = -(2.0**2.0) = -4.0。但是,这里是-2.0**2.0 = (-2.0)**2.0 = 4.0,这可能不是预期用途,可能会导致非常讨厌且难以追踪的错误。
<< 和 >>。不同的优先级会导致不同的代码解释,因此对通用运算符的优先级进行标准化很重要。我不知道最好的标准是什么,但是给予<< 2 和** 2 相同的优先级是有道理的。 nshipster.com/swift-operators
如果您碰巧将 2 提高到某个幂,则可以使用按位左移运算符:
let x = 2 << 0 // 2
let y = 2 << 1 // 4
let z = 2 << 7 // 256
请注意,“功率”值比您想象的要小 1。
请注意,这比 pow(2.0, 8.0) 更快,并且可以避免使用双打。
【讨论】:
let x = 0b00000001 << exponent // 2**exponent let x = 1 << 0 // 1 let x = 1 << 2 // 4 let x = 1 << 8 // 256
1 << exponent,因为你实际上是在一个小的字节序值上向左移动位。 1 << 1 == 2,或者想象 00000001 得到左移 1,得到 00000010,即二进制 2。我喜欢这个解决方案。我将其合并到下面的comprehensive answer 中。
对于正在寻找** 中缀运算符的 Swift 3 版本的任何人:
precedencegroup ExponentiationPrecedence {
associativity: right
higherThan: MultiplicationPrecedence
}
infix operator ** : ExponentiationPrecedence
func ** (_ base: Double, _ exp: Double) -> Double {
return pow(base, exp)
}
func ** (_ base: Float, _ exp: Float) -> Float {
return pow(base, exp)
}
2.0 ** 3.0 ** 2.0 // 512
(2.0 ** 3.0) ** 2.0 // 64
【讨论】:
import Darwin 获取pow
2**3**2 是 512,而不是 64。我不知道任何具有左关联幂运算符的编程语言。它们都是右联想。如果你在 Swift 中实现它,你绝对应该使用右关联来与其他流行语言保持一致,以及mathematical convention。
我是这样做的:
operator infix ** { associativity left precedence 200 }
func ** (base: Double, power: Double) -> Double {
return exp(log(base) * power)
}
【讨论】:
斯威夫特 4.2
import Foundation
var n = 2.0 // decimal
var result = 5 * pow(n, 2)
print(result)
// 20.0
【讨论】:
没有,但你有 pow 函数。
【讨论】:
像大多数 C 系列语言一样,没有一种。
【讨论】:
如果您对 Int 类型的求幂运算符特别感兴趣,我认为现有的答案对于大数不会特别有效,因为浮点数在内存中的表示方式。当从Int 转换为Float 或Double 然后返回(这是Darwin 模块中的pow、powf 和powl 函数所必需的)you may lose precision。这是Int 的精确版本:
let pow = { Array(repeating: $0, count: $1).reduce(1, *) }
请注意,此版本的内存效率不是特别高,并且针对源代码大小进行了优化。
另一个不会创建中间数组的版本:
func pow(_ x: Int, _ y: Int) -> Int {
var result = 1
for i in 0..<y {
result *= x
}
return result
}
【讨论】:
-1**-1 = -1, -10**-1 = -0.1.
pow(Double, Double) 结果转换为 Int 得到的结果相匹配。我已经为该解决方案提供了new answer,但还通过处理边界情况和使用位左移运算符来优化速度以实现 2 和 -2 的幂。
另一种答案是使用 NSExpression
let mathExpression = NSExpression(format:"2.5**2.5")
let answer = mathExpression.expressionValue(with: nil, context: nil) as? Double
或
let mathExpression = NSExpression(format:"2**3")
let answer = mathExpression.expressionValue(with: nil, context: nil) as? Int
【讨论】:
这个答案提供了一个经过测试和优化的*函数,用于计算整数的整数幂,同时还提供了几个版本的自定义 ** 运算符用于求幂。
* 根据我在此页面上阅读的内容,至少我认为它已经过优化。
我的猜测是 Swift 故意不提供此功能,因为需要选择如何处理绝对值小于 1 的结果。您希望它舍入为 0 还是隐式转换为十进制类型?编译器不知道,选择默认值可能会导致人们在使用它时没有意识到他们刚刚做了什么数学选择。
在 Swift 5.3 中:
import Foundation
precedencegroup ExponeniationPrecedence {
associativity: right // This makes Towers of Powers work correctly
higherThan: MultiplicationPrecedence
}
infix operator ** : ExponeniationPrecedence
public func **(_ base: Int, _ exponent: Int) -> Int {
return pow(base, exponent)
}
public func **(_ base: Double, _ exponent: Double) -> Double {
return pow(base, exponent)
}
public func **(_ base: Decimal, _ exponent: Int) -> Decimal {
return pow(base, exponent)
}
public func **(_ base: Float, _ exponent: Float) -> Float {
return powf(base, exponent)
}
/// Calculate exponentiation of integer base and integer exponent, returning integer result.
///
/// Exponentiation that would result in absolute values of less than 1 (i.e. exponent is negative and base is not 1 or -1) are rounded 0.
public func pow(_ base: Int, _ exponent: Int) -> Int {
// Optimize cases for certain exponents
switch exponent {
case 0:
return 1
case 1:
return base
case _ where exponent < 0 && base != -1 && base != 1:
// Negative exponents of integers always round to zero, except if the base is 1 or -1
return 0
default:
break
}
// Optimize cases for certain bases
switch base {
case -1:
if exponent % 2 == 0 {
return -1 * base
} else {
return base
}
case 0, 1:
return base
case -2, 2:
// Use the bitwise left shift operator to efficiently calculate powers of 2 and -2
let result = 1 << exponent
if base == -2 && exponent % 2 == 1 {
return -1 * result
}
return result
default:
var result = 1
for i in 1 ... exponent {
result *= base
}
return result
}
}
/// Calculate powers of integer base and integer exponent using Foundation's pow function by casting both the base and the exponent as Doubles, calling pow, but without casting the result.
/// Useful if rounding results between -1 and 1 to zero is not acceptable.
public func pow(_ base: Int, _ exponent: Int) -> Double {
return pow(Double(base), Double(exponent))
}
/// Calculate powers of integer base and integer exponent using Foundation's pow function by casting both the base and the exponent as Doubles, calling pow, and then casting the result as an Int
/// If results are -1<x<1, round to 0.
public func castPow(_ base: Int, _ exponent: Int) -> Int {
return Int(pow(base, exponent))
}
pow(Int, Int) 函数的测试用例:
// Test Exponent = 0
assert(0**0 == 1)
assert(1**0 == 1)
assert(2**0 == 1)
// Test Exponent = 1
assert(-1**1 == -1)
assert(0**1 == 0)
assert(1**1 == 1)
assert(2**1 == 2)
// Test Exponent = -1
assert(-1 ** -1 == -1)
assert(0 ** -1 == 0)
assert(1 ** -1 == 1)
assert(2 ** -1 == 0)
// Test Exponent = 2
assert(-1 ** 2 == 1)
assert(0 ** 2 == 0)
assert(1 ** 2 == 1)
assert(2 ** 2 == 4)
assert(3 ** 2 == 9)
// Test Base = 0
assert(0**0 == 1)
assert(0**1 == 0)
assert(0**2 == 0)
// Test Base = 1
assert(1 ** -1 == 1)
assert(1**0 == 1)
assert(1**1 == 1)
assert(1**2 == 1)
// Test Base = -1
assert(-1 ** -1 == -1)
assert(-1**0 == 1)
assert(-1**1 == -1)
assert(-1**2 == 1)
assert(-1**2 == 1)
assert(-1**3 == -1)
// Test Base = 2
assert(2 ** -1 == 0)
assert(2**0 == 1)
assert(2**1 == 2)
assert(2**2 == 4)
assert(2**3 == 8)
// Test Base = -2
assert(-2 ** -1 == 0)
assert(-2**0 == 1)
assert(-2**1 == -2)
assert(-2**2 == 4)
assert(-2**3 == -8)
// Test Base = 3
assert(3 ** -1 == 0)
assert(3**0 == 1)
assert(3**1 == 3)
assert(3**2 == 9)
assert(3**3 == 27)
// Test Towers of Powers
assert(2**2**2 == 16)
assert(3**2**2 == 81)
assert(2**2**3 == 256)
assert(2**3**2 == 512)
【讨论】:
标准库旨在保持精简和小型,因此它们不包含所有算术函数。它们实际上是 BinaryInteger 和 BinaryFloatingPoint 可能组合的 4 种情况。
我已经看到了使用Double 或Int 的答案,这会产生各种令人困惑的编译器错误。使用generics 的美,我们可以覆盖所有情况,编译器不会再抱怨了:
infix operator **
func **<I: BinaryInteger>(lhs: I, rhs: I) -> I {
return I(pow(Double(lhs), Double(rhs)))
}
func **<I: BinaryInteger, F: BinaryFloatingPoint>(lhs: I, rhs: F) -> F {
return F(pow(Double(lhs), Double(rhs)))
}
func **<I: BinaryInteger, F: BinaryFloatingPoint>(lhs: F, rhs: I) -> F {
return F(pow(Double(lhs), Double(rhs)))
}
func **<F: BinaryFloatingPoint>(lhs: F, rhs: F) -> F {
return F(pow(Double(lhs), Double(rhs)))
}
【讨论】: