我最近学得很快,但我有一个无法找到答案的基本问题
我想得到类似的东西
var a:Int = 3
var b:Int = 3
println( pow(a,b) ) // 27
但pow函数只能使用double数,它不能用整数运算,我甚至无法通过Double(a)或a.double()等函数将int转换为double。
为什么它不提供整数的幂?它肯定会返回一个没有歧义的整数!为什么我不能将整数转换为double?它只是改变3到3.0(或3.00000 ...无论如何)
如果我有两个整数并且我想进行电源操作,我该怎样才能顺利完成?
谢谢!
如果你愿意,你可以宣布一个infix
operator
来做。
// Put this at file level anywhere in your project
infix operator ^^ { associativity left precedence 160 }
func ^^ (radix: Int, power: Int) -> Int {
return Int(pow(Double(radix), Double(power)))
}
// ...
// Then you can do this...
let i = 2 ^^ 3
// ... or
println("2³ = \(2 ^^ 3)") // Prints 2³ = 8
我使用了两个插入符号,所以你仍然可以使用XOR operator。
Swift 3的更新
在Swift 3中,“幻数”precedence
被precedencegroups
取代:
precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence }
infix operator ^^ : PowerPrecedence
func ^^ (radix: Int, power: Int) -> Int {
return Int(pow(Double(radix), Double(power)))
}
// ...
// Then you can do this...
let i2 = 2 ^^ 3
// ... or
print("2³ = \(2 ^^ 3)") // Prints 2³ = 8
要不就 :
var a:Int = 3
var b:Int = 3
println(pow(Double(a),Double(b)))
要计算power(2, n)
,只需使用:
let result = 2 << (n-1)
Swift 4.x版本
precedencegroup ExponentiationPrecedence {
associativity: right
higherThan: MultiplicationPrecedence
}
infix operator ^^: ExponentiationPrecedence
public func ^^ (radix: Float, power: Float) -> Float {
return pow((radix), (power))
}
public func ^^ (radix: Double, power: Double) -> Double {
return pow((radix), (power))
}
public func ^^ (radix: Int, power: Int) -> Int {
return NSDecimalNumber(decimal: pow(Decimal(radix), power)).intValue
}
试图结合重载,我试图使用泛型,但无法使其工作。我终于想到使用NSNumber而不是试图重载或使用泛型。这简化了以下内容:
typealias Dbl = Double // Shorter form
infix operator ** {associativity left precedence 160}
func ** (lhs: NSNumber, rhs: NSNumber) -> Dbl {return pow(Dbl(lhs), Dbl(rhs))}
以下代码与上面的代码相同,但实现了错误检查,以查看参数是否可以成功转换为双打。
func ** (lhs: NSNumber, rhs: NSNumber) -> Dbl {
// Added (probably unnecessary) check that the numbers converted to Doubles
if (Dbl(lhs) ?? Dbl.NaN) != Dbl.NaN && (Dbl(rhs) ?? Dbl.NaN) != Dbl.NaN {
return pow(Dbl(lhs), Dbl(rhs))
} else {
return Double.NaN
}
}
在Swift 5中:
extension Int{
func expo(_ power: Int) -> Int {
var result = 1
var powerNum = power
var tempExpo = self
while (powerNum != 0){
if (powerNum%2 == 1){
result *= tempExpo
}
powerNum /= 2
tempExpo *= tempExpo
}
return result
}
}
像这样使用
2.expo(5) // pow(2, 5)
感谢@Paul Buis的回答。
我更喜欢这个
func ^ (left:NSNumber, right: NSNumber) -> NSNumber {
return pow(left.doubleValue,right.doubleValue)
}
var a:NSNumber = 3
var b:NSNumber = 3
println( a^b ) // 27
func calc (base:Int, number:Int) -> Int {
var answer : Int = base
for _ in 2...number {answer *= base }
return answer
}
calc (2,2)
除此之外,您的变量声明有语法错误,这完全符合您的预期。你所要做的就是将a
和b
投射到Double并将值传递给pow
。然后,如果你正在使用2个Int并且你想要在操作的另一侧返回Int,那么只需转回Int。
import Darwin
let a: Int = 3
let b: Int = 3
let x: Int = Int(pow(Double(a),Double(b)))
有时,将Int
投射到Double
并不是一个可行的解决方案。在某种程度上,这种转换会失去精确度。例如,以下代码不会返回您可能直观的预期。
Double(Int.max - 1) < Double(Int.max) // false!
如果你需要高强度的精度并且不需要担心负指数 - 无论如何通常无法用整数求解 - 那么tail-recursive exponentiation-by-squaring algorithm的这种实现是你最好的选择。根据this SO answer的说法,这是“在非对称密码学中对大量数字进行模幂运算的标准方法”。
// using Swift 5.0
func pow<T: BinaryInteger>(_ base: T, _ power: T) -> T {
func expBySq(_ y: T, _ x: T, _ n: T) -> T {
precondition(n >= 0)
if n == 0 {
return y
} else if n == 1 {
return y * x
} else if n.isMultiple(of: 2) {
return expBySq(y, x * x, n / 2)
} else { // n is odd
return expBySq(y * x, x * x, (n - 1) / 2)
}
}
return expBySq(1, base, power)
}
注意:在这个例子中,我使用了通用的T: BinaryInteger
。这样你可以使用Int
或UInt
或任何其他类似整数的类型。
如果你真的想要一个'Int only'实现并且不想强制到/从Double
,你需要实现它。这是一个简单的实现;有更快的算法,但这将工作:
func pow (base:Int, power:UInt) -> Int {
var answer : Int = 1
for _ in 0..power { answer *= base }
return answer
}
> pow (2, 4)
$R3: Int = 16
> pow (2, 8)
$R4: Int = 256
> pow (3,3)
$R5: Int = 27
在实际的实现中,您可能需要进行一些错误检查。
细节更多
infix operator ^^ { associativity left precedence 160 }
func ^^ (radix: Int, power: Int) -> Int {
return Int(pow(CGFloat(radix), CGFloat(power)))
}
如果您不愿意接受运算符重载(尽管^^
解决方案对于阅读代码的人来说可能很清楚),您可以快速实现:
let pwrInt:(Int,Int)->Int = { a,b in return Int(pow(Double(a),Double(b))) }
pwrInt(3,4) // 81
mklbtz通过平方作为计算整数幂的标准算法来进行求幂是正确的,但算法的尾递归实现似乎有点令人困惑。请参阅http://www.programminglogic.com/fast-exponentiation-algorithms/,通过在C中求平方来实现取幂的非递归实现。我试图将其转换为Swift:
func expo(_ base: Int, _ power: Int) -> Int {
var result = 1
while (power != 0){
if (power%2 == 1){
result *= base
}
power /= 2
base *= base
}
return result
}
当然,这可以通过创建一个重载的运算符来调用它,并且可以重新编写它以使其更通用,因此它适用于实现IntegerType
协议的任何东西。为了使它具有通用性,我可能会从类似的东西开始
func expo<T:IntegerType>(_ base: T, _ power: T) -> T {
var result : T = 1
但是,这可能会被带走。
将答案组合成一组重载函数(并使用“**”代替“^^”,就像其他语言一样使用 - 对我来说更清晰):
// http://stackoverflow.com/questions/24196689/how-to-get-the-power-of-some-integer-in-swift-language
// Put this at file level anywhere in your project
infix operator ** { associativity left precedence 160 }
func ** (radix: Double, power: Double) -> Double { return pow(radix, power) }
func ** (radix: Int, power: Int ) -> Double { return pow(Double(radix), Double(power)) }
func ** (radix: Float, power: Float ) -> Double { return pow(Double(radix), Double(power)) }
使用Float时,可能会失去精度。如果使用数字文字以及整数和非整数的混合,默认情况下最终会使用Double。我个人喜欢使用数学表达式而不是像pow(a,b)这样的函数出于风格/可读性的原因,但这只是我。
任何会导致pow()抛出错误的运算符也会导致这些函数抛出错误,因此错误检查的负担仍然在于使用power函数的代码。吻,恕我直言。
使用原生pow()函数允许例如取平方根(2 ** 0.5)或反转(2 ** -3 = 1/8)。由于可以使用反向或小数指数,我编写了所有代码来返回pow()函数的默认Double类型,它应返回最高精度(如果我记得正确的文档)。如果需要,可以将其类型化为Int或Float或其他任何东西,可能会导致精度损失。
2 ** -3 = 0.125
2 ** 0.5 = 1.4142135623731
2 ** 3 = 8
事实证明你也可以使用pow()
。例如,您可以使用以下内容表示10到9。
pow(10, 9)
与pow
一起,powf()
返回float
而不是double
。我只在Swift 4和macOS 10.13上测试了这个。