Bagaimana cara mendapatkan Power of some Integer dalam bahasa Swift?


102

Saya belajar dengan cepat baru-baru ini, tetapi saya memiliki masalah dasar yang tidak dapat menemukan jawabannya

Saya ingin mendapatkan sesuatu seperti

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

tetapi fungsi pow hanya dapat bekerja dengan angka ganda, tidak bekerja dengan integer, dan saya bahkan tidak dapat mengubah int menjadi dua kali lipat dengan sesuatu seperti Double (a) atau a.double () ...

Mengapa tidak memasok kekuatan integer? itu pasti akan mengembalikan integer tanpa ambiguitas! dan Mengapa saya tidak bisa mentransmisikan integer menjadi double? itu hanya mengubah 3 menjadi 3.0 (atau 3.00000 ... terserah)

jika saya mendapat dua bilangan bulat dan saya ingin melakukan operasi daya, bagaimana saya bisa melakukannya dengan lancar?

Terima kasih!


Deklarasi jenis ini salah
Edgar Aroutiounian

sebagian besar bahasa tidak memiliki fungsi daya integer karena alasan ini
phuclv

1
Catatan @ phuclv menunjukkan diskusi yang bagus tentang topik tersebut. Saya akan mengubah teks di tautan menjadi "alasan ini"
eharo2

Jawaban:


78

Jika Anda suka, Anda dapat menyatakan infix operatoruntuk melakukannya.

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

Saya menggunakan dua tanda sisipan jadi Anda masih bisa menggunakan operator XOR .

Pembaruan untuk Swift 3

Di Swift 3, "angka ajaib" precedencediganti dengan 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

Jadi jika Anda ingin melakukan ini untuk Floats, apakah Anda akan melakukannya: operator infix ^^ {} 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
Saya menemukan ini tidak berperilaku seperti yang saya harapkan karena presedensinya salah. Untuk operator eksponen, tetapkan prioritas ke 160 (lihat developer.apple.com/library/ios/documentation/Swift/Conceptual/… dan developer.apple.com/library/ios/documentation/Swift/Conceptual/… ) seperti: infix operator ^^ { precedence 160 } func ^^... dan seterusnya
Tim Camber

Saya sangat suka solusi ini, tetapi dengan Swift 3 itu tidak berhasil. Ada ide bagaimana membuatnya bekerja?
Vanya

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

59

Selain itu, deklarasi variabel Anda memiliki kesalahan sintaksis, ini berfungsi persis seperti yang Anda harapkan. Yang harus Anda lakukan adalah melemparkan adan bMenggandakan dan meneruskan nilainya ke pow. Kemudian, jika Anda bekerja dengan 2 Ints dan Anda menginginkan Int kembali di sisi lain operasi, cukup putar kembali ke Int.

import Darwin 

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

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

Jawaban ini paling jelas dengan tipe Double dan Int.
midtownguru

Itulah yang saya inginkan, terima kasih. Dengan Python, adil 3 ** 3. Terkadang, saya perlu menyelesaikan masalah algoritma menggunakan Swift, sangat menyakitkan dibandingkan menggunakan Python.
ChuckZHB

13

Terkadang, mentransmisikan Intke a Doublebukanlah solusi yang layak. Pada skala tertentu ada kehilangan ketepatan dalam konversi ini. Misalnya, kode berikut tidak mengembalikan apa yang mungkin Anda harapkan secara intuitif.

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

Jika Anda membutuhkan ketepatan pada besaran yang tinggi dan tidak perlu khawatir tentang eksponen negatif - yang umumnya tidak dapat diselesaikan dengan bilangan bulat - maka penerapan algoritme eksponen-demi-kuadrat rekursif-rekursif ini adalah taruhan terbaik Anda. Menurut jawaban SO ini , ini adalah "metode standar untuk melakukan eksponensial modular untuk bilangan besar dalam kriptografi asimetris."

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

Catatan: dalam contoh ini saya telah menggunakan file generik T: BinaryInteger. Ini agar Anda dapat menggunakan Intatau UIntjenis bilangan bulat lainnya.


Dan tentu saja Anda selalu dapat mendefinisikan ini sebagai operator (seperti yang disarankan oleh jawaban yang lebih populer) atau perpanjangan dari Intatau Anda dapat meminta hal-hal itu memanggil fungsi gratis ini - apa pun yang diinginkan hati Anda.
mklbtz

Tampaknya, solusi ini mengarah ke pengecualian stackoverflow
Vyacheslav

11

Jika Anda benar-benar menginginkan implementasi 'Int only' dan tidak ingin memaksa ke / dariDouble , Anda harus menerapkannya. Berikut adalah implementasi yang sepele; ada algoritma yang lebih cepat tetapi ini akan berhasil:

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

Dalam implementasi nyata, Anda mungkin menginginkan pemeriksaan kesalahan.


Ini adalah jawaban yang sepenuhnya valid. Ada beberapa contoh di mana mengonversi Ints ke Doubles kehilangan presisi, dan itu bukan solusi yang layak untuk Int pow. Coba saja menjalankan Double(Int.max - 1) < Double(Int.max)Swift 3 REPL dan Anda mungkin akan terkejut.
mklbtz

2
Untuk mempersingkatnya, Anda dapat menerapkan ini dengan reducepanggilan. return (2...power).reduce(base) { result, _ in result * base }
mklbtz

1
Mungkin Anda bisa menghilangkan prasyarat dengan membuat kekuatan UInt
hashemi

4

sedikit detail lagi

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

swift - Ekspresi Biner


4

Jika Anda tidak suka membebani operator (meskipun ^^solusinya mungkin jelas bagi seseorang yang membaca kode Anda), Anda dapat melakukan implementasi cepat:

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

4

mklbtz benar tentang eksponen dengan mengkuadratkan menjadi algoritma standar untuk menghitung kekuatan integer, tetapi implementasi algoritma rekursif-ekor tampaknya agak membingungkan. Lihat http://www.programminglogic.com/fast-exponentiation-algorithms/ untuk implementasi eksponen non-rekursif dengan mengkuadratkan di C. Saya telah mencoba menerjemahkannya ke Swift di sini:

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
}

Tentu saja, ini bisa dibayangkan dengan membuat operator yang kelebihan beban untuk memanggilnya dan bisa ditulis ulang untuk membuatnya lebih umum sehingga bekerja pada apa pun yang mengimplementasikan IntegerTypeprotokol. Untuk membuatnya umum, saya mungkin akan mulai dengan sesuatu seperti

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

Tapi, itu mungkin terbawa suasana.


1
Sangat bagus! Untuk melakukan ini secara umum di Swift> 4.0 (Xcode 9.0), Anda ingin menggunakan BinaryInteger. IntegerTypesudah tidak digunakan lagi.
mklbtz

3

Atau hanya :

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

3

Menggabungkan jawaban menjadi sekumpulan fungsi yang kelebihan beban (dan menggunakan "**" alih-alih "^^" seperti yang digunakan beberapa bahasa lain - lebih jelas bagi saya):

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

Saat menggunakan Float, Anda mungkin kehilangan presisi. Jika menggunakan literal numerik dan campuran bilangan bulat dan non-bilangan bulat, Anda akan mendapatkan Double secara default. Saya pribadi menyukai kemampuan untuk menggunakan ekspresi matematika daripada fungsi seperti pow (a, b) karena alasan gaya / keterbacaan, tapi itu hanya saya.

Setiap operator yang akan menyebabkan pow () melakukan kesalahan juga akan menyebabkan fungsi-fungsi ini melakukan kesalahan, sehingga beban pemeriksaan kesalahan tetap terletak pada kode yang menggunakan fungsi daya. KISS, IMHO.

Menggunakan fungsi native pow () memungkinkan untuk misalnya mengambil akar kuadrat (2 ** 0,5) atau invers (2 ** -3 = 1/8). Karena kemungkinan untuk menggunakan eksponen invers atau pecahan, saya menulis semua kode saya untuk mengembalikan tipe ganda default fungsi pow (), yang akan mengembalikan presisi paling tinggi (jika saya mengingat dokumentasi dengan benar). Jika perlu, ini bisa diketikkan ke Int atau Float atau apa pun, mungkin dengan hilangnya presisi.

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

pow () tidak cocok untuk kalkulasi besar di mana bagian pecahan juga sangat penting. Bagi saya jawaban Anda memberi petunjuk. Terima kasih :)
Mahendra

3

Ternyata Anda juga bisa menggunakan pow(). Misalnya, Anda dapat menggunakan berikut ini untuk mengekspresikan 10 hingga 9.

pow(10, 9)

Seiring dengan pow, powf()mengembalikan a, floatbukan double. Saya hanya menguji ini di Swift 4 dan macOS 10.13.


1
pow (a, b) mengembalikan NaN jika b <0; jadi Anda bisa menambahkan tes untuk ini: let power = (b> = 0)? pow (a, b): 1 / pow (a, -b); Perhatikan bahwa a harus dideklarasikan sebagai Desimal biarkan a: Decimal = 2; biarkan b = -3
claude31

2

Untuk menghitung power(2, n), cukup gunakan:

let result = 2 << (n-1)

1

Versi 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

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

Gunakan seperti ini

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

Terima kasih atas jawaban @Paul Buis.


1

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


1

Fungsi pow berbasis Int yang menghitung nilai secara langsung melalui bit shift untuk basis 2 di 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, *)
}

(Pastikan hasilnya berada dalam kisaran Int - ini tidak memeriksa kasus di luar batas)


1

Jawaban lainnya bagus, tetapi jika diinginkan, Anda juga dapat melakukannya dengan Intekstensi selama eksponennya positif.

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

Mencoba menggabungkan overloading, saya mencoba menggunakan obat generik tetapi tidak berhasil. Saya akhirnya berpikir untuk menggunakan NSNumber daripada mencoba membebani atau menggunakan obat generik. Ini menyederhanakan menjadi berikut:

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

Kode berikut adalah fungsi yang sama seperti di atas tetapi mengimplementasikan pemeriksaan kesalahan untuk melihat apakah parameter berhasil diubah menjadi Ganda.

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

Cepat 5

Saya terkejut, tetapi saya tidak menemukan solusi yang tepat di sini.

Ini adalah milikku:

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

Contoh:

CustomMath.pow(1,1)

-2

Saya lebih suka ini

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
Itu menggantikan operator xor standar. Menggunakan ini akan membuat kode Anda berperilaku dengan cara yang sangat tidak terduga bagi siapa pun yang tidak tahu Anda mengganti karat tunggal.
wjl

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

Contoh:

calc (2,2)

1
Praktik yang baik untuk menjelaskan mengapa kode Anda menawarkan solusi, daripada hanya membuang kode ke dalam jawaban.
Rudi Kershaw

1
Dan itu jauh dari fungsi daya yang benar. Bagaimana dengan 0 sebagai eksponen atau nilai negatif apa pun.
macbirdie

Selain itu, nama 'calc "terlalu umum untuk digunakan dalam operasi spesifik seperti itu .. cal (2,2) dapat berarti kemungkinan kalkulasi yang ingin Anda terapkan pada 2 angka ... 2 + 2, 2-2, 2 * 2, 2/2, 2pow2, 2root2, dll.
eharo2
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.