【问题标题】:How to get the Power of some Integer in Swift language?如何在 Swift 语言中获得一些整数的力量?
【发布时间】:2014-08-03 12:05:22
【问题描述】:

我最近在学习swift,但是我有一个基本问题找不到答案

我想得到类似的东西

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

但是 pow 函数只能使用双精度数,它不能使用整数,而且我什至不能通过 Double(a) 或 a.double() 之类的方法将 int 转换为双精度...

为什么它不提供整数的幂?它肯定会返回一个没有歧义的整数! 以及为什么我不能将整数转换为双精度数?它只是将 3 更改为 3.0(或 3.00000...随便)

如果我有两个整数,我想做幂运算,如何才能顺利完成?

谢谢!

【问题讨论】:

  • 这些类型声明是错误的
  • 由于this reason,大多数语言没有整数幂函数
  • @phuclv 的注释指出了关于该主题的精彩讨论。我会将链接中的文字更改为“这些原因”
  • 提示:(^) 是按位异或运算符,或“异或运算符”。以防您在来到这里之前想知道您的代码在做什么。

标签: integer double swift pow


【解决方案1】:

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

【讨论】:

  • 这个答案对于 Double 和 Int 类型来说是最清楚的。
  • 这就是我想要的,谢谢。在 Python 中,只需 3 ** 3。有时候,我需要使用 Swift 解决算法问题,这比使用 Python 真的很痛苦。
  • @ChuckZHB 你知道运算符重载吗?
【解决方案2】:

如果您真的想要一个“仅 Int”实现并且不想强制转换为 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

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

【讨论】:

  • 这是一个完全有效的答案。在某些情况下,将 Int 转换为 Doubles 会丢失精度,因此这不是 Int pow 的可行解决方案。只需尝试在 Swift 3 REPL 中运行 Double(Int.max - 1) &lt; Double(Int.max),您可能会感到惊讶。
  • 为了缩短它,您可以通过reduce 调用来实现它。 return (2...power).reduce(base) { result, _ in result * base }
  • 也许你可以通过将 power 设为 UInt 来摆脱前提条件
【解决方案3】:

如果你愿意,你可以声明一个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

【讨论】:

  • 所以如果你想为浮点数做这个,你会这样做:中缀运算符^^ {} func ^^(radix:Float,power:Float)-> Float { return Float(pow(双(基数),双(幂)))}
  • func ^^ (radix: Double, power: Double) -> Double { return Double(pow(Double(radix), Double(power))) }
  • 我发现这并没有达到我的预期,因为优先级已关闭。对于指数运算符,将优先级设置为 160(参见 developer.apple.com/library/ios/documentation/Swift/Conceptual/…developer.apple.com/library/ios/documentation/Swift/Conceptual/…),如下所示:infix operator ^^ { precedence 160 } func ^^... 以此类推
  • 我真的很喜欢这个解决方案,但是在 Swift 3 中它不起作用。知道如何使它工作吗?
  • func p(_ b: Bool) -&gt; Double { return b?-1:1 } ?
【解决方案4】:
func calc (base:Int, number:Int) -> Int {
    var answer : Int = base
    for _ in 2...number {answer *= base } 
    return answer
}

例子:

calc (2,2)

【讨论】:

  • 最好解释一下为什么您的代码提供了解决方案,而不是仅仅将代码转储到答案中。
  • 它远非正确的幂函数。 0 作为指数或任何负值怎么样?
  • 另外,“calc”这个名字太笼统了,不能用在这样一个特定的操作中。cal(2,2) 可以表示您想应用于 2 个数字的任何可能的计算... 2 +2、2-2、2*2、2/2、2pow2、2root2等
  • 时间复杂度为 O(n)。使用 bit shifting 表示 O(1)
【解决方案5】:

我更喜欢这个

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

【讨论】:

  • 这取代了标准的异或运算符。使用它会使你的代码以一种非常意想不到的方式表现给任何不知道你正在覆盖单克拉的人。
  • 是的,它取代了标准的xor operator
【解决方案6】:

更多细节

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

swift - Binary Expressions

【讨论】:

    【解决方案7】:

    或者只是:

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

    【讨论】:

      【解决方案8】:

      如果您不喜欢运算符重载(尽管阅读您的代码的人可能清楚^^ 解决方案),您可以快速实现:

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

      【讨论】:

        【解决方案9】:

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

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

        使用浮点数时,您可能会丢失精度。如果使用数字文字以及整数和非整数的混合,您将默认使用 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】:

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

        【讨论】:

          【解决方案11】:

          有时,将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 或任何其他类似整数的类型。

          【讨论】:

          • 当然,您始终可以将其定义为运算符(正如更流行的答案所建议的那样)或Int 的扩展,或者您可以让这些东西称之为免费功能 - 无论您的心愿。
          • 看来,这个解决方案导致了stackoverflow异常
          【解决方案12】:

          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
          

          但是,这可能会被带走。

          【讨论】:

          • 非常好!要在 Swift > 4.0 (Xcode 9.0) 中进行一般性操作,您需要使用 BinaryIntegerIntegerType 已弃用。
          【解决方案13】:

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

          let result = 2 << (n-1)
          

          【讨论】:

            【解决方案14】:

            原来你也可以使用pow()。例如,您可以使用以下来表示 10 到 9。

            pow(10, 9)
            

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

            【讨论】:

            • pow(a, b) 如果 b = 0) ? pow(a, b) : 1 / pow(a, -b) ;注意 a 必须声明为 Decimal let a : Decimal = 2 ;让 b = -3
            【解决方案15】:

            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
            }
            

            【讨论】:

              【解决方案16】:

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

              【讨论】:

                【解决方案17】:

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

                【讨论】:

                  【解决方案18】:

                  斯威夫特 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)
                  

                  【讨论】:

                  • 如果性能发挥作用,这是一个很好的解决方案。出于所有正常目的,其他解决方案更容易理解。
                  【解决方案19】:

                  一个基于 Int 的 pow 函数,在 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 范围内 - 这不会检查越界情况)

                  【讨论】:

                    【解决方案20】:

                    其他答案很好,但如果您愿意,也可以使用 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
                    

                    【讨论】:

                    • 我认为第 3 行应该是 guard toPower &lt; 0 else { return 0 },因为 n^0 = 1。
                    猜你喜欢
                    • 2022-01-20
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-05-21
                    • 1970-01-01
                    • 2013-07-24
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多