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!
Si vous le souhaitez, vous pouvez déclarer une infix
operator
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
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)))
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)
}
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.
petit détail plus
infix operator ^^ { associativity left precedence 160 }
func ^^ (radix: Int, power: Int) -> Int {
return Int(pow(CGFloat(radix), CGFloat(power)))
}
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
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.
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
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.
Pour calculer power(2, n)
, utilisez simplement:
let result = 2 << (n-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
}
}
Utiliser comme ça
2.expo(5) // pow(2, 5)
Merci à la réponse de @Paul Buis.
Ou juste :
var a:Int = 3
var b:Int = 3
println(pow(Double(a),Double(b)))
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
}
}
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
}