Exponentiationsoperator in Swift

80

Ich sehe keinen Exponentiationsoperator, der in den Basisarithmetikoperatoren in der Swift-Sprachreferenz definiert ist.

Gibt es wirklich keinen vordefinierten Integer- oder Float-Exponentiationsoperator in der Sprache?

mcgregor94086
quelle
In meinem Fall funktionierte dies als Lösung: stackoverflow.com/a/28710112/2161007
Nayyar

Antworten:

96

Es gibt keinen Operator, aber Sie können die pow-Funktion folgendermaßen verwenden:

return pow(num, power)

Wenn Sie möchten, können Sie auch einen Operator veranlassen, die pow-Funktion wie folgt aufzurufen:

infix operator ** { associativity left precedence 170 }

func ** (num: Double, power: Double) -> Double{
    return pow(num, power)
}

2.0**2.0 //4.0
Connor
quelle
Besser zu verwenden **, damit Sie es für Ints verwenden können und nicht mit XOR in Konflikt stehen.
Kevin
3
Der Operator ^ wird in Swift als XOR definiert.
Kostiantyn Koval
21
Warnung! Hier gibt es ein Problem. Zum Beispiel normalerweise in Programmiersprachen -2.0**2.0 = -(2.0**2.0) = -4.0. Dies ist jedoch -2.0**2.0 = (-2.0)**2.0 = 4.0möglicherweise nicht die beabsichtigte Verwendung und kann zu einem ziemlich bösen und schwer auffindbaren Fehler führen.
Daniel Farrell
NSHipster verwendet eine ähnliche Beschreibung, jedoch mit einer Priorität von 160, um mit <<und übereinzustimmen >>. Unterschiedliche Prioritäten führen zu unterschiedlichen Code-Interpretationen. Daher ist es wichtig, eine Priorität für gemeinsame Operatoren festzulegen. Ich weiß nicht, was der beste Standard ist, aber Geben << 2und ** 2der gleiche Vorrang machen Sinn. nshipster.com/swift-operators
Omegaman
8
Ist Potenzierung nicht richtig assoziativ? en.wikipedia.org/wiki/Operator_associativity
vwvan
28

Wenn Sie zufällig 2 auf eine bestimmte Leistung erhöhen, können Sie den bitweisen Linksverschiebungsoperator verwenden:

let x = 2 << 0    // 2
let y = 2 << 1    // 4
let z = 2 << 7    // 256

Beachten Sie, dass der Wert 'power' 1 weniger ist, als Sie vielleicht denken.

Beachten Sie, dass dies schneller ist als pow(2.0, 8.0)und Sie vermeiden müssen, Doppel zu verwenden.

zufällige Operation
quelle
2
Das ist soweit schön, beantwortet aber die Frage nicht wirklich.
Chris
1
Ich war an Zweierpotenzen interessiert, also antwortete es mir.
dldnh
@chanceoperation Alternativ können Sie für 2 hoch n 1 oder 0b00000001 um n Stellen nach links verschieben. Swift Advanced Operators let x = 0b00000001 << exponent // 2**exponent let x = 1 << 0 // 1 let x = 1 << 2 // 4 let x = 1 << 8 // 256
Beepscore
13

Für alle, die nach einer Swift 3-Version des **Infix-Operators suchen :

precedencegroup ExponentiationPrecedence {
  associativity: right
  higherThan: MultiplicationPrecedence
}

infix operator ** : ExponentiationPrecedence

func ** (_ base: Double, _ exp: Double) -> Double {
  return pow(base, exp)
}

func ** (_ base: Float, _ exp: Float) -> Float {
  return pow(base, exp)
}

2.0 ** 3.0 ** 2.0    // 512
(2.0 ** 3.0) ** 2.0  // 64
reitermarkus
quelle
5
Nett. Vergessen Sie nicht import Darwinzu bekommenpow
iainH
4
Ziemlich sicher, dass die Assoziativität links und nicht rechts sein sollte. 2 ^ 3 ^ 2 ist 64, nicht 512.
Brandonscript
Nun, sowohl in Python als auch in JavaScript 2**3**2ist 512, nicht 64. Ich kenne keine Programmiersprache mit einem linksassoziativen Exponentiationsoperator. Sie sind alle richtig assoziativ. Wenn Sie dies in Swift implementieren, sollten Sie es auf jeden Fall richtig assoziativ tun, um mit anderen gängigen Sprachen sowie mit mathematischen Konventionen konsistent zu sein .
Ray Toal
5

Ich habe es so gemacht:

operator infix ** { associativity left precedence 200 }

func ** (base: Double, power: Double) -> Double {
    return exp(log(base) * power)
}
ldanilek
quelle
das scheint ... ineffizient
sam-w
4

Swift 4.2

import Foundation

var n = 2.0 // decimal
var result = 5 * pow(n, 2)
print(result)
// 20.0
Edison
quelle
3

Es gibt keine, aber Sie haben die powFunktion.

Stange
quelle
2

Wenn Sie sich speziell für den Exponentiationsoperator für IntTyp interessieren , denke ich nicht, dass vorhandene Antworten aufgrund der Art und Weise, wie Gleitkommazahlen im Speicher dargestellt werden, für große Zahlen besonders gut funktionieren würden. Wenn zu konvertieren Floatoder Doubleaus Intund dann wieder zurück (die durch erforderlich ist pow, powfund powlFunktionen in DarwinModul) können Sie Präzision verlieren . Hier ist eine genaue Version für Int:

let pow = { Array(repeating: $0, count: $1).reduce(1, *) }

Beachten Sie, dass diese Version nicht besonders speichereffizient ist und für die Quellcodegröße optimiert ist.

Eine andere Version, die kein Zwischenarray erstellt:

func pow(_ x: Int, _ y: Int) -> Int {
  var result = 1
  for i in 0..<y {
    result *= x
  }
  return result
}
Max Desiatov
quelle
1

Wie die meisten Sprachen der C-Familie gibt es keine.

David Berry
quelle
0

Eine alternative Antwort ist die Verwendung von NSExpression

let mathExpression = NSExpression(format:"2.5**2.5")
let answer = mathExpression.expressionValue(with: nil, context: nil) as? Double

oder

let mathExpression = NSExpression(format:"2**3")
let answer = mathExpression.expressionValue(with: nil, context: nil) as? Int
Ryan Heitner
quelle