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!
Réponses:
Si vous le souhaitez, vous pouvez déclarer un
infix
operator
pour le faire.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"
precedence
est remplacé parprecedencegroups
:la source
infix operator ^^ { precedence 160 } func ^^
... et ainsi de suitefunc p(_ b: Bool) -> Double { return b?-1:1 }
?À 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
a
etb
de 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.la source
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.Parfois, convertir un
Int
en unDouble
n'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.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."
Remarque: dans cet exemple, j'ai utilisé un fichier générique
T: BinaryInteger
. C'est ainsi que vous pouvez utiliserInt
ouUInt
ou tout autre type de type entier.la source
Int
ou vous pouvez faire appeler cette fonction gratuite - ce que votre cœur désire.Si vous voulez vraiment une implémentation 'Int only' 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:Dans une implémentation réelle, vous voudrez probablement une vérification des erreurs.
la source
Double(Int.max - 1) < Double(Int.max)
un REPL Swift 3 et vous serez peut-être surpris.reduce
appel.return (2...power).reduce(base) { result, _ in result * base }
petit détail plus
swift - Expressions binaires
la source
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:la source
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:
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
IntegerType
protocole. Pour le rendre générique, je commencerais probablement par quelque chose commeMais, cela s'emballe probablement.
la source
BinaryInteger
.IntegerType
est obsolète.Ou juste :
la source
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):
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.
la source
Il s'avère que vous pouvez également utiliser
pow()
. Par exemple, vous pouvez utiliser ce qui suit pour exprimer 10 au 9.Avec
pow
,powf()
renvoie afloat
au lieu de adouble
. Je n'ai testé cela que sur Swift 4 et macOS 10.13.la source
Pour calculer
power(2, n)
, utilisez simplement:la source
Version Swift 4.x
la source
Dans Swift 5:
Utilisez comme ça
Merci à la réponse de @Paul Buis.
la source
Array (répétition: a, count: b) .reduce (1, *)
la source
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:
(Assurez-vous que le résultat est dans la plage de Int - cela ne vérifie pas le cas hors limites)
la source
Les autres réponses sont excellentes, mais si vous préférez, vous pouvez également le faire avec une
Int
extension tant que l'exposant est positif.la source
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:
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.
la source
Swift 5
J'ai été surpris, mais je n'ai pas trouvé de bonne solution ici.
C'est à moi:
Exemple:
la source
J'aime mieux ça
la source
Exemple:
la source