如何在Swift语言中获得某些Integer的强大功能?

问题描述 投票:78回答:15

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

我想得到类似的东西

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 ...无论如何)

如果我有两个整数并且我想进行电源操作,我该怎样才能顺利完成?

谢谢!

integer double swift pow
15个回答
72
投票

如果你愿意,你可以宣布一个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中,“幻数”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

1
投票

要不就 :

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

1
投票

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

let result = 2 << (n-1)

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
}

0
投票

试图结合重载,我试图使用泛型,但无法使其工作。我终于想到使用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
    }
}

0
投票

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


-1
投票

我更喜欢这个

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

-3
投票
    func calc (base:Int, number:Int) -> Int {
    var answer : Int = base
    for _ in 2...number {answer *= base } 
    return answer
    }
    calc (2,2)

43
投票

除此之外,您的变量声明有语法错误,这完全符合您的预期。你所要做的就是将ab投射到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)))

8
投票

有时,将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。这样你可以使用IntUInt或任何其他类似整数的类型。


5
投票

如果你真的想要一个'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

在实际的实现中,您可能需要进行一些错误检查。


4
投票

细节更多

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

swift - Binary Expressions


4
投票

如果您不愿意接受运算符重载(尽管^^解决方案对于阅读代码的人来说可能很清楚),您可以快速实现:

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

4
投票

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

但是,这可能会被带走。


3
投票

将答案组合成一组重载函数(并使用“**”代替“^^”,就像其他语言一样使用 - 对我来说更清晰):

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

3
投票

事实证明你也可以使用pow()。例如,您可以使用以下内容表示10到9。

pow(10, 9)

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

© www.soinside.com 2019 - 2024. All rights reserved.