web-dev-qa-db-fra.com

Comment obtenir le pouvoir d'un certain Integer en langue Swift?

J'apprends Swift récemment, mais j'ai un problème de base qui ne trouve pas de réponse

Je veux obtenir quelque chose comme 

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

mais la fonction pow ne peut fonctionner qu'avec un nombre double, elle ne fonctionne pas avec un entier, et je ne peux même pas transtyper int en doubler avec quelque chose comme Double (a) ou a.double () ...

Pourquoi ne fournit-il pas le pouvoir de l'entier? il retournera certainement un entier sans ambiguïté! et pourquoi je ne peux pas transtyper un entier en double? il suffit de changer 3 à 3.0 (ou 3.00000 ... peu importe)

si j'ai deux nombres entiers et que je veux effectuer l'opération d'alimentation, comment puis-je le faire en douceur?

Merci!

69
林鼎棋

Si vous le souhaitez, vous pouvez déclarer une infixoperator pour le faire.

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

J'ai utilisé deux caractères, vous pouvez donc toujours utiliser l'opérateur XOR .

Mise à jour pour Swift 3

Dans Swift 3, le "nombre magique" precedence est remplacé par 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
68
Grimxn

Hormis le fait que vos déclarations de variable comportent des erreurs de syntaxe, cela fonctionne exactement comme vous le souhaitiez. Tout ce que vous avez à faire est de convertir en Double et de transmettre les valeurs à pow. Ensuite, si vous travaillez avec 2 Ints et que vous voulez un Int de retour de l’autre côté de l’opération, revenez à Int

import Darwin 

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

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

Parfois, convertir une Int en une Double n'est pas une solution viable. À certaines grandeurs, il y a une perte de précision dans cette conversion. Par exemple, le code suivant ne renvoie pas ce à quoi vous pourriez vous attendre intuitivement. (Swift 3.0)

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

Si vous avez besoin de precision à haute magnitude et que vous n'avez pas à vous soucier de exposants négatifs - ce qui ne peut généralement pas être résolu avec des entiers - alors cette implémentation de l'exposantiation récursive-tail algorithme quadruple est votre meilleur pari. Selon cette SO réponse , il s'agit de "la méthode standard pour réaliser une exponentiation modulaire pour des nombres énormes en cryptographie asymétrique".

func pow(_ base: Int, _ power: Int) -> Int {
    func expBySq(_ y: Int, _ x: Int, _ n: Int) -> Int {
        precondition(n >= 0)
        if n == 0 {
            return y
        } else if n == 1 {
            return y * x
        } else if n % 2 == 0 {
            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) 
}
7
mklbtz

mklbtz a raison sur l'exponentiation en considérant que l'algorithme standard de calcul des puissances entières est la quadrature, mais l'implémentation de l'algorithme en mode récursif semble un peu déroutante. Voir http://www.programminglogic.com/fast-exponentiation-algorithms/ pour une implémentation non récursive de l'exponentiation en carré. J'ai essayé de le traduire en Swift ici:

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
}

Bien sûr, cela pourrait être simplifié en créant un opérateur surchargé pour l'appeler et il pourrait être réécrit pour le rendre plus générique afin qu'il fonctionne sur tout ce qui implémenterait le protocole IntegerType. Pour le rendre générique, je commencerais probablement par quelque chose comme

    func expo<T:IntegerType>(_ base: T, _ power: T) -> T {
    var result : T = 1

Mais, c'est probablement s'emballer.

4
Paul Buis

petit détail plus 

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

Swift - Expressions binaires

4
tylyo

Si vous êtes peu enclin à la surcharge d'opérateur (bien que la solution ^^ soit probablement claire pour quelqu'un qui lit votre code), vous pouvez effectuer une mise en œuvre rapide:

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

Il s'avère que vous pouvez également utiliser pow(). Par exemple, vous pouvez utiliser ce qui suit pour exprimer 10 au 9.

pow(10, 9)

Avec pow, powf() renvoie float au lieu de double. Je n’ai testé cela que sur Swift 4 et macOS 10.13.

3
Jake3231

Combinaison des réponses dans un ensemble surchargé de fonctions (et utilisation de "**" à la place de "^^" comme certaines langues l'utilisent - plus clair pour moi):

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

Lorsque vous utilisez Float, vous risquez de perdre en précision. Si vous utilisez des littéraux numériques et un mélange d'entiers et de non entiers, vous obtiendrez Double par défaut. Personnellement, j'aime bien la possibilité d'utiliser une expression mathématique au lieu d'une fonction comme pow (a, b) pour des raisons de style/lisibilité, mais ce n'est que moi.

Tous les opérateurs qui provoqueraient une erreur à pow () provoqueraient également une erreur à ces fonctions. Par conséquent, la charge de la vérification des erreurs incombe toujours au code utilisant la fonction power. KISS, à mon humble avis.

Utiliser la fonction native pow () permet par exemple de prendre des racines carrées (2 ** 0,5) ou inverses (2 ** -3 = 1/8). En raison de la possibilité d'utiliser des exposants inverses ou fractionnaires, j'ai écrit tout mon code pour renvoyer le type Double par défaut de la fonction pow (), qui devrait renvoyer le plus de précision possible (si je me souviens bien de la documentation). Si nécessaire, cela peut être moulé en Int, Float ou autre, éventuellement avec une perte de précision.

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

Si vous voulez vraiment une implémentation 'Int seulement' et que vous ne voulez pas forcer vers/depuis Double, vous devrez l'implémenter. Voici une implémentation triviale; il existe des algorithmes plus rapides mais cela fonctionnera:

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

Dans une implémentation réelle, vous souhaiterez probablement une vérification d'erreur.

3
GoZoner

Pour calculer power(2, n), utilisez simplement:

let result = 2 << (n-1)
1
Le Binh

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

Utiliser comme ça

2.expo(5) // pow(2, 5)

Merci à la réponse de @Paul Buis.

1
dengST30

Ou juste : 

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

En essayant de combiner la surcharge, j'ai essayé d'utiliser des génériques mais je ne pouvais pas le faire fonctionner. J'ai finalement décidé d'utiliser NSNumber au lieu d'essayer de surcharger ou d'utiliser des génériques. Cela simplifie ce qui suit:

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

Le code suivant a la même fonction que ci-dessus mais implémente le contrôle d'erreur pour voir si les paramètres peuvent être convertis en Doubles avec succès.

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
ECJB

Version 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
Mahendra GP