Wie bekomme ich die Kraft einer ganzen Zahl in Swift-Sprache?


101

Ich lerne in letzter Zeit schnell, aber ich habe ein grundlegendes Problem, das keine Antwort finden kann

Ich möchte so etwas bekommen

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

Aber die pow-Funktion kann nur mit doppelter Zahl arbeiten, sie funktioniert nicht mit ganzzahliger Zahl, und ich kann das int nicht einmal durch Double (a) oder a.double () in double umwandeln ...

Warum liefert es nicht die Potenz der ganzen Zahl? es wird definitiv eine ganze Zahl ohne Mehrdeutigkeit zurückgeben! und warum kann ich keine ganze Zahl in ein Doppel umwandeln? es ändert sich nur 3 zu 3.0 (oder 3.00000 ... was auch immer)

Wie kann ich es reibungslos machen, wenn ich zwei Ganzzahlen habe und die Energieoperation ausführen möchte?

Vielen Dank!


Diese Typdeklarationen sind falsch
Edgar Aroutiounian

Die meisten Sprachen haben aus diesem Grund
phuclv

1
Die Notiz von @ phuclv weist auf eine großartige Diskussion zu diesem Thema hin. Ich würde den Text im Link zu "diesen Gründen"
ändern

Antworten:


78

Wenn Sie möchten, können Sie dies erklären infix operator.

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

Ich habe zwei Carets verwendet, damit Sie weiterhin den XOR-Operator verwenden können .

Update für Swift 3

In Swift 3 wird die "magische Zahl" precedenceersetzt durch 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

Wenn Sie dies für Floats tun möchten, würden Sie dies tun: Infix-Operator ^^ {} func ^^ (Radix: Float, Leistung: Float) -> Float {Rückgabe Float (pow (Double (radix), Double (Leistung) )))}
Padapa

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

3
Ich stellte fest, dass sich dies nicht ganz so verhielt, wie ich es erwartet hatte, da der Vorrang nicht stimmte. Setzen Sie für einen exponentiellen Operator den Vorrang auf 160 (siehe developer.apple.com/library/ios/documentation/Swift/Conceptual/… und developer.apple.com/library/ios/documentation/Swift/Conceptual/… ) wie folgt: infix operator ^^ { precedence 160 } func ^^... und so weiter
Tim Camber

Ich mag diese Lösung wirklich, aber mit Swift 3 funktioniert sie nicht. Irgendeine Idee, wie es funktioniert?
Wanja

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

58

Abgesehen davon, dass Ihre Variablendeklarationen Syntaxfehler aufweisen, funktioniert dies genau so, wie Sie es erwartet haben. Alles was Sie tun müssen, ist zu werfen aund bzu verdoppeln und die Werte an zu übergeben pow. Wenn Sie dann mit 2 Ints arbeiten und ein Int wieder auf der anderen Seite der Operation haben möchten, kehren Sie einfach zu Int zurück.

import Darwin 

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

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

Diese Antwort ist bei Double- und Int-Typen am klarsten.
Midtownguru

Das will ich, danke. In Python nur 3 ** 3. Manchmal muss ich das Algorithmusproblem mit Swift lösen, es ist wirklich schmerzhaft im Vergleich zur Verwendung von Python.
ChuckZHB

13

Manchmal ist das Casting von a Intzu a Doublekeine praktikable Lösung. Bei einigen Größen gibt es einen Genauigkeitsverlust bei dieser Umwandlung. Der folgende Code gibt beispielsweise nicht das zurück, was Sie intuitiv erwarten könnten.

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

Wenn Sie Präzision bei hohen Größen benötigen und sich keine Gedanken über negative Exponenten machen müssen - die im Allgemeinen ohnehin nicht mit ganzen Zahlen gelöst werden können -, ist diese Implementierung des Algorithmus für die rekursive Exponentiation durch Quadrieren die beste Wahl. Nach dieser SO-Antwort ist dies "die Standardmethode für die modulare Exponentiation für große Zahlen in der asymmetrischen Kryptographie".

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

Hinweis: In diesem Beispiel habe ich ein Generikum verwendet T: BinaryInteger. Dies ist , so können Sie verwenden , Intoder UIntoder eine beliebige andere ganze Zahl artigen Typ.


Und natürlich können Sie dies immer als Operator (wie die populäreren Antworten vermuten lassen) oder als Erweiterung von definieren, Intoder Sie können diese Dinge diese freie Funktion nennen lassen - was auch immer Ihr Herz begehrt.
mklbtz

Es scheint, dass diese Lösung zu einer Stackoverflow-Ausnahme führt
Vyacheslav

11

Wenn Sie wirklich eine "Nur Int" -Implementierung wünschen und nicht zu / von zwingenDouble müssen, müssen Sie sie implementieren. Hier ist eine triviale Implementierung; Es gibt schnellere Algorithmen, aber das wird funktionieren:

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

In einer realen Implementierung möchten Sie wahrscheinlich eine Fehlerprüfung.


Dies ist eine vollständig gültige Antwort. Es gibt einige Fälle, in denen die Konvertierung von Ints in Doubles an Präzision verliert. Dies ist daher keine praktikable Lösung für Int pow. Versuchen Sie einfach, Double(Int.max - 1) < Double(Int.max)in einem Swift 3 REPL zu laufen, und Sie werden überrascht sein.
mklbtz

2
Um es zu verkürzen, können Sie dies mit einem reduceAufruf implementieren . return (2...power).reduce(base) { result, _ in result * base }
mklbtz

1
Vielleicht können Sie die Voraussetzung loswerden, indem Sie Macht zu einem UInt machen
hashemi

4

kleines Detail mehr

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

schnell - Binäre Ausdrücke


4

Wenn Sie nicht zur Überlastung des Bedieners neigen (obwohl die ^^Lösung wahrscheinlich für jemanden klar ist, der Ihren Code liest), können Sie eine schnelle Implementierung durchführen:

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

4

mklbtz hat Recht mit der Potenzierung, indem das Quadrieren der Standardalgorithmus für die Berechnung ganzzahliger Potenzen ist, aber die schwanzrekursive Implementierung des Algorithmus scheint etwas verwirrend. Unter http://www.programminglogic.com/fast-exponentiation-algorithms/ finden Sie eine nicht rekursive Implementierung der Exponentiation durch Quadrieren in C. Ich habe versucht, sie hier in Swift zu übersetzen:

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
}

Dies könnte natürlich durch Erstellen eines überladenen Operators zum Aufrufen erfunden und neu geschrieben werden, um es allgemeiner zu gestalten, sodass es an allem funktioniert, was das IntegerTypeProtokoll implementiert . Um es generisch zu machen, würde ich wahrscheinlich mit so etwas beginnen

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

Aber das wird wahrscheinlich mitgerissen.


1
Sehr schön! Um dies generisch in Swift> 4.0 (Xcode 9.0) zu tun, möchten Sie verwenden BinaryInteger. IntegerTypewurde veraltet.
mklbtz

3

Oder nur :

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

3

Kombinieren Sie die Antworten zu einem überladenen Satz von Funktionen (und verwenden Sie "**" anstelle von "^^", wie es einige andere Sprachen verwenden - für mich klarer):

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

Bei Verwendung von Float können Sie an Präzision verlieren. Wenn Sie numerische Literale und eine Mischung aus Ganzzahlen und Nicht-Ganzzahlen verwenden, erhalten Sie standardmäßig Double. Ich persönlich mag die Möglichkeit, aus stilistischen / lesbaren Gründen einen mathematischen Ausdruck anstelle einer Funktion wie pow (a, b) zu verwenden, aber das bin nur ich.

Alle Operatoren, die bewirken würden, dass pow () einen Fehler auslöst, führen auch dazu, dass diese Funktionen einen Fehler auslösen. Die Last der Fehlerprüfung liegt also weiterhin beim Code, der die Power-Funktion verwendet. KUSS, IMHO.

Die Verwendung der nativen pow () -Funktion ermöglicht es beispielsweise, Quadratwurzeln (2 ** 0,5) oder inverse (2 ** -3 = 1/8) zu ziehen. Aufgrund der Möglichkeit, inverse oder gebrochene Exponenten zu verwenden, habe ich meinen gesamten Code geschrieben, um den Standard-Double-Typ der pow () -Funktion zurückzugeben, der die höchste Genauigkeit zurückgeben sollte (wenn ich mich richtig an die Dokumentation erinnere). Bei Bedarf kann dies auf Int oder Float oder was auch immer typisiert werden, möglicherweise mit Genauigkeitsverlust.

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

pow () ist nicht für große Berechnungen geeignet, bei denen auch ein Bruchteil des Anteils sehr wichtig ist. Für mich gibt Ihre Antwort einen Hinweis. Danke :)
Mahendra

3

Es stellt sich heraus, dass Sie auch verwenden können pow(). Sie können beispielsweise Folgendes verwenden, um 10 bis 9 auszudrücken.

pow(10, 9)

Zusammen mit pow, powf()gibt ein floatanstelle eines double. Ich habe dies nur auf Swift 4 und macOS 10.13 getestet.


1
pow (a, b) gibt NaN zurück, wenn b <0 ist; Sie könnten also einen Test hinzufügen: let power = (b> = 0)? pow (a, b): 1 / pow (a, -b); Beachten Sie, dass a als Dezimal deklariert werden muss. Lassen Sie a: Dezimal = 2; sei b = -3
claude31

2

Zum Berechnen verwenden Sie power(2, n)einfach:

let result = 2 << (n-1)

1

Swift 4.x Version

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

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

Verwenden Sie so

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

Vielen Dank an die Antwort von @Paul Buis.


1

Eine Int-basierte pow-Funktion, die den Wert direkt über die Bitverschiebung für Basis 2 in Swift 5 berechnet:

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

(Stellen Sie sicher, dass das Ergebnis im Bereich von Int liegt - dies prüft nicht, ob der Fall außerhalb der Grenzen liegt.)


0

Beim Versuch, die Überladung zu kombinieren, habe ich versucht, Generika zu verwenden, aber es konnte nicht funktionieren. Ich dachte schließlich, ich würde NSNumber verwenden, anstatt zu versuchen, Generika zu überladen oder zu verwenden. Dies vereinfacht sich zu Folgendem:

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

Der folgende Code ist dieselbe Funktion wie oben, implementiert jedoch die Fehlerprüfung, um festzustellen, ob die Parameter erfolgreich in Doubles konvertiert werden können.

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

Die anderen Antworten sind großartig, aber wenn Sie es vorziehen, können Sie dies auch mit einer IntErweiterung tun, solange der Exponent positiv ist.

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

-1

Swift 5

Ich war überrascht, aber ich habe hier keine richtige Lösung gefunden.

Das ist meins:

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

Beispiel:

CustomMath.pow(1,1)

-2

Mir gefällt das besser

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
Das ersetzt den Standardoperator xor. Wenn Sie dies verwenden, verhält sich Ihr Code für jeden, der nicht weiß, dass Sie das einzelne Karat überschreiben, auf sehr unerwartete Weise.
wjl

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

Beispiel:

calc (2,2)

1
Es empfiehlt sich zu erklären, warum Ihr Code eine Lösung bietet, anstatt nur Code in eine Antwort zu kopieren.
Rudi Kershaw

1
Und es ist weit von einer korrekten Power-Funktion entfernt. Was ist mit 0 als Exponent oder einem negativen Wert?
Macbirdie

Außerdem ist der Name 'calc' zu allgemein, um in einer solchen spezifischen Operation verwendet zu werden. Cal (2,2) kann jede mögliche Berechnung bedeuten, die Sie auf 2 Zahlen anwenden möchten ... 2 + 2, 2-2, 2 * 2, 2/2, 2pow2, 2root2 usw.
eharo2
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.