Jak zdobyć moc jakiejś liczby całkowitej w języku Swift?


102

Ostatnio szybko się uczę, ale mam podstawowy problem, na który nie mogę znaleźć odpowiedzi

Chcę dostać coś takiego

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

ale funkcja pow może działać tylko z podwójną liczbą, nie działa z liczbą całkowitą, a nie mogę nawet rzutować int na double przez coś takiego jak Double (a) lub a.double () ...

Dlaczego nie dostarcza mocy liczby całkowitej? na pewno zwróci liczbę całkowitą bez dwuznaczności! i dlaczego nie mogę rzucić liczby całkowitej na podwójną? po prostu zmień 3 na 3.0 (lub 3.00000 ... cokolwiek)

jeśli mam dwie liczby całkowite i chcę wykonać operację zasilania, jak mogę to zrobić płynnie?

Dzięki!


Te deklaracje typu są błędne
Edgar Aroutiounian


1
Notatka @ phuclv wskazuje na świetną dyskusję na ten temat.
Zmieniłbym

Odpowiedzi:


78

Jeśli chcesz, możesz zadeklarować, że infix operatorto zrobisz.

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

Użyłem dwóch karetek, więc nadal możesz używać operatora XOR .

Aktualizacja dla Swift 3

W Swift 3 „magiczna liczba” precedencezostaje zastąpiona przez 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

Więc gdybyś chciał zrobić to dla Floats, zrobiłbyś to: operator infix ^^ {} func ^^ (radix: Float, power: Float) -> Float {return Float (pow (Double (radix), Double (potęga )))}
padapa

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

3
Okazało się, że nie działa to tak, jak się spodziewałem, ponieważ pierwszeństwo było wyłączone. W przypadku operatora wykładniczego ustaw priorytet na 160 (patrz developer.apple.com/library/ios/documentation/Swift/Conceptual/… i developer.apple.com/library/ios/documentation/Swift/Conceptual/ ... ) w następujący sposób: infix operator ^^ { precedence 160 } func ^^... i tak dalej
Tim Arnold

Bardzo podoba mi się to rozwiązanie, ale z Swift 3 nie działa. Masz pomysł, jak to działa?
Wania,

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

59

Poza tym, że deklaracje zmiennych mają błędy składniowe, działa to dokładnie tak, jak się tego spodziewałeś. Wszystko, co musisz zrobić, to rzucić ai bpodwoić i przekazać wartości pow. Następnie, jeśli pracujesz z 2 Ints i chcesz, aby Int z powrotem po drugiej stronie operacji, po prostu rzuć z powrotem do Int.

import Darwin 

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

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

Ta odpowiedź jest najwyraźniejsza w przypadku typów Double i Int.
midtownguru

Tego właśnie chcę, dzięki. W Pythonie po prostu 3 ** 3. Czasami muszę rozwiązać problem z algorytmem za pomocą Swift, jest to naprawdę bolesne w porównaniu do używania Pythona.
ChuckZHB

13

Czasami rzutowanie Intna a Doublenie jest dobrym rozwiązaniem. Przy niektórych wielkościach w tej konwersji występuje utrata precyzji. Na przykład poniższy kod nie zwraca tego, czego można by się intuicyjnie spodziewać.

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

Jeśli potrzebujesz precyzji przy dużych wielkościach i nie musisz martwić się o ujemne wykładniki - których i tak nie da się ogólnie rozwiązać za pomocą liczb całkowitych - to najlepszym rozwiązaniem jest ta implementacja algorytmu rekurencyjnego potęgowania ogona przez kwadrat . Zgodnie z tą odpowiedzią SO , jest to „standardowa metoda wykonywania modularnego potęgowania ogromnych liczb w kryptografii asymetrycznej”.

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

Uwaga: w tym przykładzie użyłem generycznego T: BinaryInteger. Dzięki temu możesz użyć Intlub UIntlub dowolnego innego typu podobnego do liczby całkowitej.


I oczywiście zawsze możesz zdefiniować to jako operator (jak sugerują bardziej popularne odpowiedzi) lub rozszerzenie Intlub możesz mieć te rzeczy, które nazywają tę bezpłatną funkcję - cokolwiek dusza zapragnie.
mklbtz,

Wygląda na to, że to rozwiązanie prowadzi do wyjątku
Wiaczesław

11

Jeśli naprawdę chcesz implementację „tylko int” i nie chcesz zmuszać do / zDouble , musisz ją zaimplementować. Oto trywialna implementacja; istnieją szybsze algorytmy, ale to zadziała:

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

W prawdziwej implementacji prawdopodobnie chciałbyś sprawdzić błędy.


To jest całkowicie poprawna odpowiedź. Istnieją przypadki, w których konwersja Ints na Doubles traci precyzję, więc nie jest to realne rozwiązanie dla Int pow. Po prostu spróbuj uruchomić Double(Int.max - 1) < Double(Int.max)w Swift 3 REPL, a możesz być zaskoczony.
mklbtz

2
Aby to skrócić, możesz to zaimplementować za pomocą reducepołączenia. return (2...power).reduce(base) { result, _ in result * base }
mklbtz

1
Być może możesz pozbyć się warunku wstępnego, czyniąc moc UInt
hashemi

4

trochę więcej szczegółów

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

swift - Wyrażenia binarne


4

Jeśli nie masz ochoty na przeciążanie operatorów (chociaż ^^rozwiązanie jest prawdopodobnie jasne dla kogoś czytającego Twój kod), możesz wykonać szybką implementację:

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

4

mklbtz ma rację co do potęgowania przez podniesienie do kwadratu, będącego standardowym algorytmem obliczania mocy całkowitych, ale rekurencyjna implementacja ogona algorytmu wydaje się nieco zagmatwana. Zobacz http://www.programminglogic.com/fast-exponentiation-algorithms/ dla nierekurencyjnej implementacji potęgowania przez podniesienie do kwadratu w C. Próbowałem przetłumaczyć to na Swift tutaj:

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
}

Oczywiście można to sobie wyobrazić, tworząc przeciążony operator, który będzie to wywoływał, i może zostać przepisany, aby uczynić go bardziej ogólnym, aby działał na wszystkim, co implementuje IntegerTypeprotokół. Aby było to ogólne, prawdopodobnie zacząłbym od czegoś takiego

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

Ale to prawdopodobnie daje się ponieść emocjom.


1
Bardzo dobrze! Aby zrobić to ogólnie w Swift> 4.0 (Xcode 9.0), chciałbyś użyć BinaryInteger. IntegerTypezostał wycofany.
mklbtz

3

Lub tylko :

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

3

Łączenie odpowiedzi w przeładowany zestaw funkcji (i używanie „**” zamiast „^^”, jak używają niektóre inne języki - jaśniejsze dla mnie):

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

Używając Float, możesz stracić precyzję. Jeśli używasz literałów numerycznych i kombinacji liczb całkowitych i niecałkowitych, domyślnie otrzymasz Double. Osobiście lubię możliwość używania wyrażenia matematycznego zamiast funkcji takiej jak pow (a, b) ze względów stylistycznych / czytelności, ale to tylko ja.

Każdy operator, który spowodowałby, że pow () wyrzuci błąd, spowoduje również, że te funkcje będą generować błąd, więc ciężar sprawdzania błędów i tak spoczywa na kodzie używającym funkcji power. KISS, IMHO.

Użycie natywnej funkcji pow () pozwala np. Wziąć pierwiastek kwadratowy (2 ** 0,5) lub odwrotnie (2 ** -3 = 1/8). Ze względu na możliwość użycia wykładników odwrotnych lub ułamkowych napisałem cały swój kod tak, aby zwracał domyślny typ Double funkcji pow (), który powinien zwracać największą precyzję (o ile dobrze pamiętam dokumentację). W razie potrzeby można to obniżyć do typu Int, Float lub cokolwiek innego, prawdopodobnie z utratą precyzji.

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

Funkcja pow () nie nadaje się do dużych obliczeń, w których bardzo ważna jest również część ułamkowa. Twoja odpowiedź jest dla mnie wskazówką. Dzięki :)
Mahendra

3

Okazuje się, że możesz również użyć pow(). Na przykład możesz użyć następującego wyrażenia, aby wyrazić 10 do 9.

pow(10, 9)

Wraz z pow, powf()zwraca floatzamiast double. Przetestowałem to tylko w Swift 4 i macOS 10.13.


1
pow (a, b) zwraca NaN, jeśli b <0; więc możesz dodać test na to: niech moc = (b> = 0)? pow (a, b): 1 / pow (a, -b); zauważ, że a musi być zadeklarowane jako Decimal niech a: Decimal = 2; let b = -3
claude 31

2

Aby obliczyć power(2, n), po prostu użyj:

let result = 2 << (n-1)

1

Wersja 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

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

Użyj w ten sposób

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

Dzięki odpowiedzi @Paul Buis.



1

Funkcja pow oparta na liczbach Int, która oblicza wartość bezpośrednio poprzez przesunięcie bitowe dla podstawy 2 w języku 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, *)
}

(Upewnij się, że wynik mieści się w zakresie Int - to nie sprawdza przypadku poza zakresem)


1

Inne odpowiedzi są świetne, ale jeśli wolisz, możesz to również zrobić z Intprzedłużeniem, o ile wykładnik jest dodatni.

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

Próbując połączyć przeciążenie, próbowałem użyć leków generycznych, ale nie mogłem tego zrobić. W końcu doszedłem do wniosku, że zamiast próbować przeciążać lub używać leków generycznych, należy użyć NSNumber. Upraszcza to do następujących:

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

Poniższy kod jest tą samą funkcją co powyżej, ale implementuje sprawdzanie błędów, aby sprawdzić, czy parametry można pomyślnie przekonwertować na podwójne.

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

Szybki 5

Byłem zaskoczony, ale nie znalazłem tutaj odpowiedniego rozwiązania.

To jest moje:

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

Przykład:

CustomMath.pow(1,1)

-2

To mi się bardziej podoba

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
To zastępuje standardowy operator xor. Użycie tego spowoduje, że twój kod będzie zachowywał się w bardzo nieoczekiwany sposób dla każdego, kto nie wie, że zastępujesz pojedynczy karat.
wjl

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

Przykład:

calc (2,2)

1
Dobrą praktyką jest wyjaśnienie, dlaczego kod oferuje rozwiązanie, zamiast po prostu wrzucać kod do odpowiedzi.
Rudi Kershaw

1
I daleko mu do prawidłowej funkcji mocy. A co z 0 jako wykładnikiem lub jakąkolwiek wartością ujemną.
Macbirdie

Ponadto nazwa „calc” jest zbyt ogólna, aby jej używać w tak konkretnej operacji. Cal (2,2) może oznaczać wszelkie możliwe obliczenia, które chcesz zastosować do 2 liczb ... 2 + 2, 2-2, 2 * 2, 2/2, 2pow2, 2root2, etc.
eharo2
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.