Come ottenere il potere di alcuni numeri interi nella lingua Swift?


102

Recentemente sto imparando rapidamente, ma ho un problema di base che non riesce a trovare una risposta

Voglio ottenere qualcosa di simile

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

ma la funzione pow può funzionare solo con il doppio numero, non funziona con il numero intero e non posso nemmeno lanciare l'int per raddoppiare con qualcosa come Double (a) o a.double () ...

Perché non fornisce la potenza dell'intero? restituirà sicuramente un numero intero senza ambiguità! e perché non riesco a trasmettere un numero intero a un doppio? cambia solo 3 in 3.0 (o 3.00000 ... qualunque)

se ho due numeri interi e voglio eseguire l'operazione di alimentazione, come posso farlo senza problemi?

Grazie!


Queste dichiarazioni di tipo sono sbagliate
Edgar Aroutiounian

la maggior parte delle lingue non ha una funzione di potenza intera per questo motivo
phuclv

1
La nota di @ phuclv indica una grande discussione sull'argomento.
Modificherei

Risposte:


78

Se vuoi, puoi dichiarare infix operatordi farlo.

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

Ho usato due caret in modo da poter ancora usare l' operatore XOR .

Aggiornamento per Swift 3

In Swift 3 il "numero magico" precedenceè sostituito da 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

Quindi, se volessi farlo per Floats, faresti questo: infix operator ^^ {} func ^^ (radix: Float, power: Float) -> Float {return Float (pow (Double (radix), Double (power )))}
padapa

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

3
Ho scoperto che questo non si è comportato come mi aspettavo perché la precedenza era disattivata. Per un operatore esponenziale, imposta la precedenza a 160 (vedi developer.apple.com/library/ios/documentation/Swift/Conceptual/… e developer.apple.com/library/ios/documentation/Swift/Conceptual/… ) in questo modo: infix operator ^^ { precedence 160 } func ^^... e così via
Tim Camber

Mi piace molto questa soluzione, ma con Swift 3 non funziona. Qualche idea su come farlo funzionare?
Vanya

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

59

Oltre al fatto che le tue dichiarazioni di variabili hanno errori di sintassi, funziona esattamente come ti aspettavi. Tutto quello che devi fare è lanciare ae bRaddoppiare e passare i valori a pow. Quindi, se stai lavorando con 2 Ints e vuoi un Int indietro sull'altro lato dell'operazione, torna semplicemente a Int.

import Darwin 

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

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

Questa risposta è la più chiara con i tipi Double e Int.
midtownguru

Questo è quello che voglio, grazie. In Python, solo 3 ** 3. A volte, ho bisogno di risolvere il problema dell'algoritmo usando Swift, è davvero doloroso confrontarlo con l'uso di Python.
ChuckZHB

13

A volte, lanciare un Inta a Doublenon è una soluzione praticabile. Ad alcune grandezze c'è una perdita di precisione in questa conversione. Ad esempio, il codice seguente non restituisce ciò che potresti aspettarti intuitivamente.

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

Se hai bisogno di precisione ad alte magnitudini e non devi preoccuparti degli esponenti negativi - che in genere non possono essere risolti comunque con numeri interi - allora questa implementazione dell'algoritmo di esponenziazione ricorsiva della coda per quadrato è la soluzione migliore. Secondo questa risposta SO , questo è "il metodo standard per fare esponenziazione modulare per numeri enormi nella crittografia asimmetrica".

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

Nota: in questo esempio ho usato un generico T: BinaryInteger. Questo è così si può utilizzare Into UInto qualsiasi altro tipo integer-like.


E ovviamente puoi sempre definirlo come un operatore (come suggeriscono le risposte più popolari) o un'estensione Into puoi fare in modo che quelle cose chiamino questa funzione libera, qualunque cosa il tuo cuore desideri.
mklbtz

Sembra che questa soluzione porti a un'eccezione stackoverflow
Vyacheslav

11

Se vuoi davvero un'implementazione "solo Int" e non vuoi forzare da / aDouble , dovrai implementarla. Ecco un'implementazione banale; ci sono algoritmi più veloci ma funzionerà:

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 un'implementazione reale probabilmente vorresti un po 'di controllo degli errori.


Questa è una risposta completamente valida. Ci sono alcuni casi in cui la conversione di Ints in Double perde precisione e quindi questa non è una soluzione praticabile per Int pow. Prova a eseguire Double(Int.max - 1) < Double(Int.max)Swift 3 REPL e potresti rimanere sorpreso.
mklbtz

2
Per accorciarlo, potresti implementarlo con una reducechiamata. return (2...power).reduce(base) { result, _ in result * base }
mklbtz

1
Forse puoi sbarazzarti della precondizione rendendo il potere un UInt
hashemi

4

piccolo dettaglio in più

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

swift - Espressioni binarie


4

Se non sei incline al sovraccarico dell'operatore (sebbene la ^^soluzione sia probabilmente chiara a qualcuno che legge il tuo codice) puoi eseguire un'implementazione rapida:

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

4

mklbtz è corretto riguardo all'esponenziazione in quanto il quadrato è l'algoritmo standard per il calcolo delle potenze intere, ma l'implementazione ricorsiva in coda dell'algoritmo sembra un po 'confusa. Vedi http://www.programminglogic.com/fast-exponentiation-algorithms/ per un'implementazione non ricorsiva dell'esponenziazione quadrata in C.Ho tentato di tradurlo in Swift qui:

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
}

Ovviamente, questo potrebbe essere immaginato creando un operatore sovraccarico per chiamarlo e potrebbe essere riscritto per renderlo più generico in modo che funzionasse su qualsiasi cosa che implementasse il IntegerTypeprotocollo. Per renderlo generico, probabilmente inizierei con qualcosa di simile

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

Ma probabilmente si sta facendo prendere la mano.


1
Molto bella! Per farlo genericamente in Swift> 4.0 (Xcode 9.0), dovresti usare BinaryInteger. IntegerTypeè stato deprecato.
mklbtz

3

O semplicemente:

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

3

Combinando le risposte in un insieme sovraccarico di funzioni (e usando "**" invece di "^^" come usano altri linguaggi - più chiaro per me):

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

Quando usi Float, potresti perdere la precisione. Se utilizzi valori letterali numerici e una combinazione di numeri interi e non interi, ti ritroverai con Double per impostazione predefinita. Personalmente mi piace la possibilità di usare un'espressione matematica invece di una funzione come pow (a, b) per ragioni stilistiche / di leggibilità, ma sono solo io.

Qualsiasi operatore che potrebbe causare la generazione di un errore da parte di pow () causerà anche la generazione di un errore da parte di queste funzioni, quindi l'onere del controllo degli errori ricade comunque sul codice che utilizza la funzione di alimentazione. BACIO, IMHO.

L'uso della funzione nativa pow () consente ad esempio di prendere radici quadrate (2 ** 0,5) o inverse (2 ** -3 = 1/8). A causa della possibilità di utilizzare esponenti inversi o frazionari, ho scritto tutto il mio codice per restituire il tipo Double predefinito della funzione pow (), che dovrebbe restituire la massima precisione (se ricordo correttamente la documentazione). Se necessario, questo può essere convertito in tipo Int o Float o qualsiasi altra cosa, possibilmente con la perdita di precisione.

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

pow () non è adatto per calcoli di grandi dimensioni in cui anche la parte frazionaria è molto importante. Per me la tua risposta dà un suggerimento. Grazie :)
Mahendra

3

Si scopre che puoi anche usare pow(). Ad esempio, puoi usare quanto segue per esprimere da 10 a 9.

pow(10, 9)

Insieme a pow, powf()restituisce a floatinvece di a double. L'ho testato solo su Swift 4 e macOS 10.13.


1
pow (a, b) restituisce NaN se b <0; quindi potresti aggiungere un test per questo: let power = (b> = 0)? pow (a, b): 1 / pow (a, -b); si noti che a deve essere dichiarato come Decimal let a: Decimal = 2; let b = -3
claude31

2

Per calcolare power(2, n), usa semplicemente:

let result = 2 << (n-1)

1

Versione 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

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

Usa in questo modo

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

Grazie alla risposta di @Paul Buis.


1

Array (ripetizione: a, count: b) .reduce (1, *)


1

Una funzione pow basata su Int che calcola il valore direttamente tramite spostamento di bit per la base 2 in 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, *)
}

(Assicurati che il risultato sia all'interno dell'intervallo di Int - questo non controlla il caso fuori limite)


1

Le altre risposte sono ottime ma se preferisci puoi anche farlo con Intun'estensione purché l'esponente sia positivo.

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

Cercando di combinare il sovraccarico, ho provato a usare i generici ma non sono riuscito a farlo funzionare. Alla fine ho pensato di usare NSNumber invece di provare a sovraccaricare o usare generici. Questo semplifica come segue:

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

Il codice seguente è la stessa funzione di cui sopra ma implementa il controllo degli errori per vedere se i parametri possono essere convertiti in Double correttamente.

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

Sono rimasto sorpreso, ma non ho trovato una soluzione corretta e corretta qui.

Questo è mio:

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

Esempio:

CustomMath.pow(1,1)

-2

Mi piace di più

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
Questo sostituisce l'operatore xor standard. Usando questo, il tuo codice si comporterà in un modo molto inaspettato per chiunque non sappia che stai sovrascrivendo il singolo carato.
wjl

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

Esempio:

calc (2,2)

1
È una buona pratica spiegare perché il codice offre una soluzione, piuttosto che scaricare il codice in una risposta.
Rudi Kershaw

1
Ed è tutt'altro che una corretta funzione di alimentazione. Che dire di 0 come esponente o qualsiasi valore negativo.
macbirdie

Inoltre, il nome "calc" è troppo generico per essere utilizzato in un'operazione così specifica .. cal (2,2) può significare qualsiasi possibile calcolo che si desidera applicare a 2 numeri ... 2 + 2, 2-2, 2 * 2, 2/2, 2pow2, 2root2, ecc.
eharo2
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.