Comment obtenir la puissance de certains nombres entiers en langage Swift?


102

J'apprends rapidement, mais j'ai un problème de base auquel je 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 peut fonctionner uniquement avec un nombre double, elle ne fonctionne pas avec un entier, et je ne peux même pas convertir l'int en double par quelque chose comme Double (a) ou a.double () ...

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

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

Merci!


Ces déclarations de type sont fausses
Edgar Aroutiounian

la plupart des langues n'ont pas de fonction de puissance entière pour cette raison
phuclv

1
La note de @ phuclv indique une excellente discussion sur le sujet. Je changerais le texte dans le lien pour "ces raisons"
eharo2

Réponses:


78

Si vous le souhaitez, vous pouvez déclarer un infix operatorpour 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 pour que vous puissiez toujours utiliser l' opérateur XOR .

Mise à jour pour Swift 3

Dans Swift 3, le "nombre magique" precedenceest 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

Donc, si vous vouliez faire cela pour Floats, feriez-vous ceci: infix operator ^^ {} func ^^ (radix: Float, power: Float) -> Float {return Float (pow (Double (radix), Double (power )))}
padapa

func ^^ (base: Double, power: Double) -> Double {return Double (pow (Double (radix), Double (power)))}
padapa

3
J'ai trouvé que cela ne se comportait pas tout à fait comme prévu, car la priorité était désactivée. Pour un opérateur exponentiatif, définissez la priorité sur 160 (voir developer.apple.com/library/ios/documentation/Swift/Conceptual/… et developer.apple.com/library/ios/documentation/Swift/Conceptual/… ) comme ceci: infix operator ^^ { precedence 160 } func ^^... et ainsi de suite
Tim Camber

J'aime beaucoup cette solution, mais avec Swift 3 cela ne fonctionne pas. Une idée de comment le faire fonctionner?
Vanya le

1
func p(_ b: Bool) -> Double { return b?-1:1 }?
Grimxn

59

À part le fait que vos déclarations de variables comportent des erreurs de syntaxe, cela fonctionne exactement comme vous vous y attendiez. Tout ce que vous avez à faire est de lancer aet bde doubler et de transmettre les valeurs à pow. Ensuite, si vous travaillez avec 2 Ints et que vous voulez un Int de l'autre côté de l'opération, il vous suffit de le renvoyer vers Int.

import Darwin 

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

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

Cette réponse est la plus claire avec les types Double et Int.
midtownguru

C'est ce que je veux, merci. En Python, juste 3 ** 3. Parfois, j'ai besoin de résoudre un problème d'algorithme en utilisant Swift, c'est vraiment pénible par rapport à l'utilisation de Python.
ChuckZHB

13

Parfois, convertir un Inten un Doublen'est pas une solution viable. À certaines magnitudes, 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.

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

Si vous avez besoin de précision à des magnitudes élevées et que vous n'avez pas à vous soucier des exposants négatifs - qui ne peuvent généralement pas être résolus avec des entiers de toute façon - alors cette implémentation de l' algorithme d'exponentiation par quadrature récursive est votre meilleur pari. Selon cette réponse de SO , c'est "la méthode standard pour faire l'exponentiation modulaire pour des nombres énormes dans la cryptographie asymétrique."

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

Remarque: dans cet exemple, j'ai utilisé un fichier générique T: BinaryInteger. C'est ainsi que vous pouvez utiliser Intou UIntou tout autre type de type entier.


Et bien sûr, vous pouvez toujours définir cela comme un opérateur (comme le suggèrent les réponses les plus populaires) ou une extension de Intou vous pouvez faire appeler cette fonction gratuite - ce que votre cœur désire.
mklbtz

Il semble que cette solution conduit à une exception de stackoverflow
Vyacheslav

11

Si vous voulez vraiment une implémentation 'Int only' et que vous ne voulez pas forcer vers / depuisDouble , 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 voudrez probablement une vérification des erreurs.


C'est une réponse tout à fait valable. Il existe des cas où la conversion d'Ints en Doubles perd en précision, et ce n'est donc pas une solution viable pour Int pow. Essayez simplement de lancer Double(Int.max - 1) < Double(Int.max)un REPL Swift 3 et vous serez peut-être surpris.
mklbtz

2
Pour le raccourcir, vous pouvez l'implémenter avec un reduceappel. return (2...power).reduce(base) { result, _ in result * base }
mklbtz

1
Peut-être que vous pouvez vous débarrasser de la condition préalable en faisant du pouvoir un UInt
hashemi

4

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

Si vous n'êtes pas enclin à la surcharge des opérateurs (bien que la ^^solution soit probablement claire pour quelqu'un qui lit votre code), vous pouvez faire une implémentation rapide:

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

4

mklbtz a raison à propos de l'exponentiation par quadrillage étant l'algorithme standard pour le calcul des puissances entières, mais l'implémentation récursive de queue de l'algorithme semble un peu déroutante. Voir http://www.programminglogic.com/fast-exponentiation-algorithms/ pour une implémentation non récursive de l'exponentiation par quadrillage en C. 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 imaginé 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émentait le IntegerTypeprotocole. 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, cela s'emballe probablement.


1
Très agréable! Pour faire cela de manière générique dans Swift> 4.0 (Xcode 9.0), vous voudrez utiliser BinaryInteger. IntegerTypeest obsolète.
mklbtz

3

Ou juste :

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

3

Combiner les réponses dans un ensemble surchargé de fonctions (et utiliser "**" au lieu de "^^" comme certains autres langages 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 vous retrouverez avec Double par défaut. Personnellement, j'aime la possibilité d'utiliser une expression mathématique au lieu d'une fonction comme pow (a, b) pour des raisons stylistiques / lisibles, mais ce n'est que moi.

Tous les opérateurs qui provoqueraient le déclenchement d'une erreur par pow () entraîneront également l'émission d'une erreur par ces fonctions, de sorte que le fardeau de la vérification des erreurs incombe toujours au code utilisant la fonction d'alimentation de toute façon. KISS, à mon humble avis.

L'utilisation de 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 (si je me souviens bien de la documentation). Si nécessaire, cela peut être transtypé en Int ou Float ou autre, éventuellement avec une perte de précision.

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

pow () ne convient pas aux grands calculs où la partie fractionnaire est également très importante. Pour moi, votre réponse donne un indice. Merci :)
Mahendra

3

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 a floatau lieu de a double. Je n'ai testé cela que sur Swift 4 et macOS 10.13.


1
pow (a, b) renvoie NaN si b <0; vous pouvez donc ajouter un test pour cela: let power = (b> = 0)? pow (a, b): 1 / pow (a, -b); notez que a doit être déclaré comme décimal soit a: Decimal = 2; let b = -3
claude31

2

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

let result = 2 << (n-1)

1

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
}

1

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

Utilisez comme ça

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

Merci à la réponse de @Paul Buis.


1

Array (répétition: a, count: b) .reduce (1, *)


1

Une fonction pow basée sur Int qui calcule la valeur directement via le décalage de bits pour la base 2 dans Swift 5:

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, *)
}

(Assurez-vous que le résultat est dans la plage de Int - cela ne vérifie pas le cas hors limites)


1

Les autres réponses sont excellentes, mais si vous préférez, vous pouvez également le faire avec une Intextension tant que l'exposant est positif.

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

0

En essayant de combiner la surcharge, j'ai essayé d'utiliser des génériques mais je n'ai pas pu le faire fonctionner. J'ai finalement pensé utiliser NSNumber au lieu d'essayer de surcharger ou d'utiliser des génériques. Cela se simplifie comme 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 est la même fonction que ci-dessus mais implémente la vérification des erreurs pour voir si les paramètres peuvent être convertis en double 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
    }
}

-1

Swift 5

J'ai été surpris, mais je n'ai pas trouvé de bonne solution ici.

C'est à moi:

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

Exemple:

CustomMath.pow(1,1)

-2

J'aime mieux ça

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
Cela remplace l'opérateur xor standard. En utilisant cela, votre code se comportera d'une manière très inattendue pour quiconque ne sait pas que vous remplacez le carat unique.
wjl

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

Exemple:

calc (2,2)

1
Il est recommandé d'expliquer pourquoi votre code offre une solution, plutôt que de simplement jeter du code dans une réponse.
Rudi Kershaw

1
Et c'est loin d'être une fonction d'alimentation correcte. Qu'en est-il de 0 comme exposant ou de toute valeur négative.
macbirdie

De plus, le nom «calc» est trop générique pour être utilisé dans une telle opération spécifique .. cal (2,2) peut signifier tout calcul possible que vous souhaitez appliquer à 2 nombres ... 2 + 2, 2-2, 2 * 2, 2/2, 2pow2, 2root2, etc.
eharo2
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.