Swift dilinde bir Tamsayının Gücü nasıl elde edilir?


102

Son zamanlarda hızlı öğreniyorum ama cevap bulamayan temel bir problemim var

Gibi bir şey almak istiyorum

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

ancak pow işlevi yalnızca çift sayı ile çalışabilir, tamsayı ile çalışmaz ve int'i Double (a) veya a.double () gibi bir şeyle ikiye katlayamıyorum bile ...

Neden tamsayının gücünü sağlamaz? kesinlikle belirsizlik olmadan bir tamsayı döndürecektir! ve neden bir tamsayıyı ikiye katlayamıyorum? sadece 3'ü 3.0'a (veya 3.00000 ... her neyse) değiştirir

iki tamsayım varsa ve güç işlemini yapmak istersem, bunu nasıl sorunsuz yapabilirim?

Teşekkürler!


Bu tür bildirimleri yanlış
Edgar Aroutiounian

çoğu dilde bu nedenle
phuclv

1
@ phuclv'nin notu, konuyla ilgili harika bir tartışmaya işaret ediyor. Bağlantıdaki metni "bu nedenlerle" değiştirirdim
eharo2

Yanıtlar:


78

İstersen, yapacağını ilan edebilirsin 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

XOR operatörünü kullanmaya devam edebilmeniz için iki imleç kullandım .

Swift 3 güncellemesi

Swift 3'te "sihirli sayı" precedenceşu şekilde değiştirilir 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

Yani bunu Floats için yapmak isteseydiniz, şunu yapar mıydınız: infix operatörü ^^ {} 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 (güç)))}
padapa

3
Bunun beklediğim gibi davranmadığını anladım çünkü öncelik kapalıydı. Üstel bir işleç için, önceliği şu şekilde 160'a ayarlayın (bkz. Developer.apple.com/library/ios/documentation/Swift/Conceptual/… ve developer.apple.com/library/ios/documentation/Swift/Conceptual/… ): infix operator ^^ { precedence 160 } func ^^... ve benzeri
Tim Arnold

Bu çözümü gerçekten seviyorum ama Swift 3 ile işe yaramıyor. Nasıl çalıştırılacağına dair bir fikrin var mı?
Vanya

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

59

Değişken bildirimlerinizde sözdizimi hataları olması dışında, bu tam olarak beklediğiniz gibi çalışır. Tek yapmanız gereken döküm ave bçift ve değerler geçirmek pow. Ardından, 2 Ints ile çalışıyorsanız ve operasyonun diğer tarafında bir Int istiyorsanız, sadece Int'e geri dönün.

import Darwin 

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

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

Bu cevap, Double ve Int türlerinde en net olanıdır.
midtownguru

İstediğim bu, teşekkürler. Python'da, sadece 3 ** 3. Bazen Swift kullanarak algoritma problemini çözmem gerekiyor, Python kullanmaya kıyasla gerçekten acı verici.
ChuckZHB

13

Bazen bir döküm Intbir karşı Doubleuygulanabilir bir çözüm değildir. Bazı büyüklüklerde, bu dönüşümde hassasiyet kaybı vardır. Örneğin, aşağıdaki kod sezgisel olarak beklediğiniz şeyi döndürmez.

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

Eğer yüksek büyüklüklerde hassasiyete ihtiyacınız varsa ve negatif üsler hakkında endişelenmeniz gerekmiyorsa - ki bu genellikle zaten tamsayılarla çözülemez - o zaman kareye göre kuyruklu üs alma algoritmasının bu uygulaması en iyi seçeneğinizdir. Göre bu SO cevap , bu "asimetrik kriptografi devasa sayılar için modüler üs yapmak için standart yöntem" dir.

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

Not: Bu örnekte bir jenerik kullandım T: BinaryInteger. Bu, Intveya UIntveya herhangi bir tamsayı benzeri türü kullanabilmeniz içindir.


Ve elbette bunu her zaman bir operatör (daha popüler cevapların önerdiği gibi) veya bir uzantı olarak tanımlayabilir Intveya bunlara bu özgür işlevi çağırabilirsiniz - kalbiniz ne isterse.
mklbtz

Görünüşe göre bu çözüm
Vyacheslav

11

Eğer gerçekten bir 'Yalnızca Int' uygulaması istiyorsanız ve zorlamak / almak istemiyorsanızDouble , onu uygulamanız gerekir. İşte önemsiz bir uygulama; daha hızlı algoritmalar var ama bu işe yarayacak:

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

Gerçek bir uygulamada muhtemelen bazı hata kontrolleri istersiniz.


Bu tamamen geçerli bir cevap. Ints'i Doubles'a dönüştürmenin hassasiyetini kaybettiği bazı durumlar vardır ve bu nedenle bu, Int pow için uygun bir çözüm değildir. Sadece Double(Int.max - 1) < Double(Int.max)bir Swift 3 REPL'de koşmayı deneyin ve şaşırabilirsiniz.
mklbtz

3
Kısaltmak için, bunu bir reduceçağrı ile uygulayabilirsiniz . return (2...power).reduce(base) { result, _ in result * base }
mklbtz

1
Belki de gücü bir UInt yaparak ön koşuldan kurtulabilirsiniz
hashemi

4

biraz detay daha fazla

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

swift - İkili İfadeler


4

Operatörün aşırı yüklenmesine karşı isteksizseniz ( ^^çözüm, kodunuzu okuyan biri için muhtemelen açık olsa da ) hızlı bir uygulama yapabilirsiniz:

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

4

mklbtz, tamsayı güçlerini hesaplamak için standart algoritmanın karesini alarak üs alma konusunda haklıdır, ancak algoritmanın kuyruk-özyinelemeli uygulaması biraz kafa karıştırıcı görünmektedir. C ile kare alarak üs almanın yinelemeli olmayan bir uygulaması için http://www.programminglogic.com/fast-exponentiation-algorithms/ adresine bakın . Bunu Swift'e çevirmeyi burada denedim:

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
}

Elbette, bu, onu aramak için aşırı yüklenmiş bir operatör oluşturarak tasarlanabilir ve IntegerTypeprotokolü uygulayan herhangi bir şey üzerinde çalışacak şekilde daha genel hale getirmek için yeniden yazılabilir . Genel yapmak için, muhtemelen şöyle bir şeyle başlarım

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

Ancak, bu muhtemelen gittikçe uzaklaşıyor.


1
Çok hoş! Bunu genel olarak Swift> 4.0'da (Xcode 9.0) yapmak için kullanmak istersiniz BinaryInteger. IntegerTypekullanımdan kaldırıldı.
mklbtz

3

Ya da sadece :

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

3

Cevapları aşırı yüklenmiş bir işlevler kümesinde birleştirmek (ve diğer bazı dillerin kullandığı gibi "^^" yerine "**" kullanmak - benim için daha anlaşılır):

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

Float kullanırken hassasiyeti kaybedebilirsiniz. Sayısal değişmez değerler ve tamsayılar ile tamsayı olmayanların bir karışımını kullanıyorsanız, varsayılan olarak Double ile sonuçlanırsınız. Kişisel olarak, üslup / okunabilirlik nedenleriyle pow (a, b) gibi bir işlev yerine matematiksel bir ifade kullanma becerisini seviyorum, ama bu sadece benim.

Pow () 'nun bir hata atmasına neden olacak herhangi bir işleç de bu işlevlerin bir hata atmasına neden olacaktır, bu nedenle hata kontrolünün yükü yine de güç işlevini kullanan kodda yatar. ÖPÜCÜK, IMHO.

Doğal pow () işlevinin kullanılması, örneğin karekök (2 ** 0.5) veya ters (2 ** -3 = 1/8) almaya izin verir. Ters veya kesirli üsler kullanma olasılığından dolayı, tüm kodumu pow () işlevinin varsayılan Double türünü döndürmek için yazdım, bu en kesinliği döndürmelidir (dokümantasyonu doğru hatırlıyorsam). Gerekirse, bu, muhtemelen hassasiyet kaybıyla, Int veya Float'a veya her neyse, tipe dönüştürülebilir.

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

pow (), kesirli kısmın da çok önemli olduğu büyük hesaplamalar için uygun değildir. Benim için cevabın bir ipucu veriyor. Teşekkürler :)
Mahendra

3

Ayrıca kullanabileceğiniz ortaya çıktı pow(). Örneğin, 10’dan 9’a kadar ifade etmek için aşağıdakileri kullanabilirsiniz.

pow(10, 9)

İle birlikte pow, powf()a floatyerine a döndürür double. Bunu yalnızca Swift 4 ve macOS 10.13'te test ettim.


1
pow (a, b), b <0 ise NaN döndürür; böylece bunun için bir test ekleyebilirsiniz: let power = (b> = 0)? pow (a, b): 1 / pow (a, -b); a'nın Decimal olarak bildirilmesi gerektiğine dikkat edin, let a: Decimal = 2; let b = -3
claude31

2

Hesaplamak için şunu power(2, n)kullanın:

let result = 2 << (n-1)

1

Swift 4.x sürümü

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

Swift 5'te:

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

Bunun gibi kullan

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

@Paul Buis'in cevabına teşekkürler.


1

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


1

Değeri doğrudan Swift 5'teki 2. taban için bit kaydırma aracılığıyla hesaplayan Int tabanlı bir güç işlevi:

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

(Sonucun Int aralığında olduğundan emin olun - bu, sınır dışı durumu kontrol etmez)


1

Diğer cevaplar harika ama eğer tercih edilirse Intüs pozitif olduğu sürece bir uzantı ile de yapabilirsiniz .

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

Aşırı yüklemeyi birleştirmeye çalışırken jenerik kullanmaya çalıştım ama çalışmasını sağlayamadım. Sonunda jenerikleri aşırı yüklemeye veya kullanmaya çalışmak yerine NSNumber kullanmayı düşündüm. Bu, aşağıdakileri basitleştirir:

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

Aşağıdaki kod, yukarıdaki ile aynı işlevdir ancak parametrelerin başarılı bir şekilde Çiftlere dönüştürülüp dönüştürülemeyeceğini görmek için hata kontrolü uygular.

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

Şaşırdım ama burada uygun bir doğru çözüm bulamadım.

Bu benim:

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

Misal:

CustomMath.pow(1,1)

-2

Bunu daha çok sevdim

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
Bu, standart xor operatörünün yerini alır. Bunu kullanmak, kodunuzun tek karatı geçersiz kıldığınızı bilmeyenlere çok beklenmedik bir şekilde davranmasını sağlayacaktır.
wjl

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

Misal:

calc (2,2)

1
Kodu bir cevaba dökmek yerine kodunuzun neden bir çözüm sunduğunu açıklamak iyi bir uygulamadır.
Rudi Kershaw

1
Ve doğru bir güç işlevinden uzaktır. Peki ya üs olarak 0 veya herhangi bir negatif değer.
macbirdie

Ayrıca, 'calc' adı böylesine özel bir işlemde kullanılamayacak kadar geneldir. Cal (2,2) 2 sayıya uygulamak istediğiniz olası herhangi bir hesaplama anlamına gelebilir ... 2 + 2, 2-2, 2 * 2, 2/2, 2pow2, 2root2, vb.
eharo2
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.