如何在 Swift 语言中得到某个整数的幂?

我最近学得很快,但是我有一个基本的问题找不到答案

我想要

var a:Int = 3
var b:Int = 3
println( pow(a,b) ) // 27

但是 pow 函数只能处理双精度数它不能处理整型数我甚至不能把 int 转换成双精度数比如 Double (a)或 a.Double () ..。

为什么它不提供整数的力量? 它肯定会返回一个整数没有歧义! 为什么我不能把一个整数转换成一个双精度数? 它只是变化3到3.0(或者3.00000... 随便什么)

如果我得到两个整数,我想做幂运算,我怎样才能平稳地做呢?

谢谢!

151378 次浏览

除了您的变量声明有语法错误之外,这正是您所期望的工作方式。您所要做的就是将 ab强制转换为 Double 并将值传递给 pow。然后,如果您使用的是2 Ints,并且希望在操作的另一端返回一个 Int,那么只需要将其转换回 Int。

import Darwin


let a: Int = 3
let b: Int = 3


let x: Int = Int(pow(Double(a),Double(b)))

如果您真的想要一个“仅内部”实现,并且不想强制从 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来做这件事。

// 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 操作员

Swift 3的更新

在 Swift 3中,“神奇数字”precedenceprecedencegroups所取代:

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
func calc (base:Int, number:Int) -> Int {
var answer : Int = base
for _ in 2...number {answer *= base }
return answer
}

例如:

calc (2,2)

我更喜欢这样

func ^ (left:NSNumber, right: NSNumber) -> NSNumber {
return pow(left.doubleValue,right.doubleValue)
}
var a:NSNumber = 3
var b:NSNumber = 3
println( a^b ) // 27

更多的细节

   infix operator ^^ { associativity left precedence 160 }
func ^^ (radix: Int, power: Int) -> Int {
return Int(pow(CGFloat(radix), CGFloat(power)))
}

快速二进制表达式

或者只是:

var a:Int = 3
var b:Int = 3
println(pow(Double(a),Double(b)))

如果你不喜欢运算符重载(尽管读者可能已经清楚了 ^^解决方案) ,你可以快速实现:

let pwrInt:(Int,Int)->Int = { a,b in return Int(pow(Double(a),Double(b))) }
pwrInt(3,4) // 81

将答案组合成一组重载的函数(使用“ * *”而不是其他语言使用的“ ^ ^”——对我来说更清楚) :

// 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 ()抛出错误的操作符也会导致这些函数抛出错误,因此错误检查的负担仍然在使用幂函数的代码身上。亲一个,恕我直言。

使用本机 pow ()函数允许例如取平方根(2 * * 0.5)或逆(2 * * -3 = 1/8)。由于可以使用逆指数或小数指数,我编写了所有代码来返回 pow ()函数的默认 Double 类型,它应该返回最高的精度(如果我没有记错文档的话)。如果需要,可以将类型强制转换为 Int 或 Float 或其他类型,这可能会损失精度。

2 ** -3  = 0.125
2 ** 0.5 = 1.4142135623731
2 ** 3   = 8

我试图结合使用过载,我试图使用泛型,但无法使其工作。我最终决定使用 NSNumber,而不是试图使用泛型。这就简化为:

typealias Dbl = Double // Shorter form
infix operator ** {associativity left precedence 160}
func ** (lhs: NSNumber, rhs: NSNumber) -> Dbl {return pow(Dbl(lhs), Dbl(rhs))}

下面的代码与上面的函数相同,但是实现了错误检查,以查看参数是否可以成功地转换为 Doubles。

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
}
}

有时,将 Int转换为 Double不是一种可行的解决方案。在某种程度上,这种转换有精度损失。例如,下面的代码不会返回您可能直观期望的结果。

Double(Int.max - 1) < Double(Int.max) // false!

如果您需要 高星等精度,并且不需要担心 负指数ーー无论如何通常不能用整数来解决这个问题ーー那么 尾部递归平方幂运算法则的这个实现是您最好的选择。根据 这么回答的说法,这是“在非对称密码学中对大数进行模幂运算的标准方法”

// 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。这样您就可以使用 IntUInt或任何其他类整数类型。

Mklbtz 关于平方乘法是计算整数幂的标准算法的说法是正确的,但是该算法的尾部递归实现似乎有点混乱。参见 http://www.programminglogic.com/fast-exponentiation-algorithms/,它是一个非递归的求幂运算的实现。我在这里尝试把它翻译成 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

但是,这可能有点过头了。

要计算 power(2, n),只需使用:

let result = 2 << (n-1)

原来你也可以使用 pow()。例如,您可以使用以下内容来表示10的9次方。

pow(10, 9)

pow一起,powf()返回 float而不是 double。我只在 Swift 4和 macOS 10.13上测试过。

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
}

雨燕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 的回答。

数组(重复: a,count: b) . reduce (1,*)

Swift 5

我很惊讶,但我没有找到正确的解决方案。

这是我的:

enum CustomMath<T: BinaryInteger> {


static func pow(_ base: T, _ power: T) -> T {
var tempBase = base
var tempPower = power
var result: T = 1


while (power != 0) {
if (power % 2 == 1) {
result *= base
}
tempPower = tempPower >> 1
tempBase *= tempBase
}
return result
}
}

例如:

CustomMath.pow(1,1)

一个基于整数的幂函数,它通过位移直接计算 Swift 5中基数2的值:

func pow(base: Int, power: UInt) -> Int {
if power == 0 { return 1 }
// for base 2, use a bit shift to compute the value directly
if base == 2 { return 2 << Int(power - 1) }
// otherwise multiply base repeatedly to compute the value
return repeatElement(base, count: Int(power)).reduce(1, *)
}

(确保结果在 Int 的范围内-这不会检查出界情况)

其他的答案很好,但是如果你喜欢,你也可以用 Int扩展,只要指数是正的。

extension Int {
func pow(toPower: Int) -> Int {
guard toPower > 0 else { return 0 }
return Array(repeating: self, count: toPower).reduce(1, *)
}
}


2.pow(toPower: 8) // returns 256