如何在 Swift 语言中获得一些整数的力量?

Posted

技术标签:

【中文标题】如何在 Swift 语言中获得一些整数的力量?【英文标题】:How to get the Power of some Integer in Swift language? 【发布时间】: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 的注释指出了关于该主题的精彩讨论。我会将链接中的文字更改为“这些原因” 提示:(^) 是按位异或运算符,或“异或运算符”。以防您在来到这里之前想知道您的代码在做什么。 【参考方案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://***.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 的扩展,或者您可以让这些东西称之为免费功能 - 无论您的心愿。 看来,这个解决方案导致了***异常【参考方案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。

以上是关于如何在 Swift 语言中获得一些整数的力量?的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 5 中,如何以可读的方式(使用整数)显示从 range.UpperBound 或 range.LowerBound 返回的原始位?

如何在 Swift 3 中使用 NSLocale 获取国家代码

使用 Swift 和 XCode 在 Core Data 中存储整数

如何在 Swift 中使用 htonl 设置整数字节顺序?

如何在 Swift 中获得 Bool 的相反值?

如何在 swift 中使用 HealthKit 获得步行和跑步距离