web-dev-qa-db-ja.com

Swift言語で整数のパワーを取得する方法は?

最近Swiftを学んでいますが、答えが見つからない基本的な問題があります

次のようなものが欲しい

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

しかし、pow関数はdouble数でのみ機能し、整数では機能せず、Double(a)やa.double()などのようにintをdoubleにキャストすることもできません...

整数のべき乗を提供しないのはなぜですか?それは間違いなく整数を間違いなく返します!そして、なぜ整数をdoubleにキャストできないのですか? 3から3.0(または3.00000 ...)に変更するだけです

2つの整数を取得し、電源操作を行いたい場合、どのようにスムーズに行うことができますか?

ありがとう!

83
林鼎棋

必要に応じて、infixoperatorを宣言して実行できます。

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

2つのキャレットを使用したため、 XOR演算子 を引き続き使用できます。

Swift 3の更新

Swift 3では、「マジックナンバー」precedenceprecedencegroupsに置き換えられます。

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
73
Grimxn

変数宣言に構文エラーがあることを除いて、これは期待どおりに機能します。 abをDoubleにキャストし、値をpowに渡すだけです。次に、2つのIntを使用していて、操作の反対側にIntを戻す場合は、Intにキャストバックします。

import Darwin 

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

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

時々、IntDoubleにキャストすることは実行可能な解決策ではありません。ある大きさでは、この変換で精度が失われます。たとえば、次のコードは、直感的に期待するものを返しません。

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

高精度で精度が必要で、負の指数を心配する必要がない場合—とにかく整数では一般に解けない—そして、 tail-recursive exponentiation-by-squaring algorithm のこの実装が最善の策です。 this SO answer によれば、これは「非対称暗号法で膨大な数のモジュラーべき乗を行う標準的な方法」です。

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

注:この例では、汎用T: BinaryIntegerを使用しました。これは、IntまたはUIntまたはその他の整数型を使用できるようにするためです。

9
mklbtz

「Int only」の実装が本当に必要で、Doubleと強制的にやり取りしたくない場合、実装する必要があります。これは簡単な実装です。より高速なアルゴリズムがありますが、これは機能します:

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

実際の実装では、おそらくエラーチェックが必要になります。

5
GoZoner

mklbtzは、整数の累乗を計算するための標準アルゴリズムである2乗によるべき乗については正しいですが、アルゴリズムの末尾再帰実装は少し混乱しているようです。 http://www.programminglogic.com/fast-exponentiation-algorithms/ を参照してください。Cの2乗による累乗の非再帰的実装については、Swiftに変換しようとしました。ここに:

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
}

もちろん、これを呼び出すためにオーバーロードされた演算子を作成することでこれを空想することができ、IntegerTypeプロトコルを実装するあらゆるもので動作するように書き換えてより汎用的にすることができます。汎用的にするには、おそらく次のようなものから始めます

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

しかし、それはおそらく夢中になっています。

4
Paul Buis

少し詳細

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

Swift-Binary Expressions

4
tylyo

演算子のオーバーロードに気が進まない場合(^^ソリューションはおそらくコードを読んでいる人には明らかですが)、簡単な実装を行うことができます。

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

pow()を使用することもできます。たとえば、次を使用して10から9を表現できます。

pow(10, 9)

powとともに、powf()floatではなくdoubleを返します。これはSwift 4およびmacOS 10.13でのみテストしました。

3
Jake3231

回答をオーバーロードされた関数セットに結合します(他の言語が使用しているように「^^」の代わりに「**」を使用します-私にはわかりやすいです):

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

フロートを使用すると、精度が低下する場合があります。数値リテラルと整数と非整数の組み合わせを使用する場合、デフォルトでDoubleになります。私は個人的には、文体/読みやすさの理由で、pow(a、b)のような関数の代わりに数式を使用する機能が好きですが、それは私だけです。

Pow()にエラーをスローさせる演算子もこれらの関数にエラーをスローさせるため、エラーチェックの負担は、とにかくpower関数を使用するコードにあります。キス、私見。

ネイティブのpow()関数を使用すると、たとえば平方根(2 ** 0.5)または逆数(2 ** -3 = 1/8)を取ることができます。逆指数または小数指数を使用する可能性があるため、デフォルトのDouble型のpow()関数を返すコードをすべて作成しました。必要に応じて、これはIntまたはFloatなどに型キャストできますが、精度が低下する可能性があります。

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

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
Mahendra

power(2, n)を計算するには、単に次を使用します。

let result = 2 << (n-1)
1
Le Binh

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

このように使用する

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

@Paul Buisの回答に感謝します。

1
dengST30

あるいは単に :

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

オーバーロードを組み合わせようとして、ジェネリックを使用しようとしましたが、機能しませんでした。ジェネリックをオーバーロードしたり使用したりする代わりに、NSNumberを使用するように思いついた。これにより、次のことが簡単になります。

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

次のコードは上記と同じ機能ですが、エラーチェックを実装して、パラメーターをDoublesに正常に変換できるかどうかを確認します。

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
ECJB