Swift 언어로 Integer의 힘을 얻는 방법은 무엇입니까?


102

최근 빠르게 배우고 있는데 답을 찾을 수없는 기본적인 문제가 있습니다

나는 같은 것을 얻고 싶다.

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

그러나 pow 함수는 이중 숫자로만 작동 할 수 있으며 정수로는 작동하지 않으며 Double (a) 또는 a.double ()과 같은 것으로 int를 이중으로 캐스팅 할 수도 없습니다.

정수의 거듭 제곱을 제공하지 않는 이유는 무엇입니까? 명확하게 모호하지 않은 정수를 반환합니다! 왜 정수를 double로 캐스트 할 수 없습니까? 3을 3.0 (또는 3.00000 ... 무엇이든)으로 변경합니다.

정수가 두 개 있고 전원 연산을하고 싶다면 어떻게하면 원활하게 할 수 있습니까?

감사!


이 타입 선언은 잘못
에드가 Aroutiounian


1
@phuclv의 메모는 주제에 대한 훌륭한 토론을 나타냅니다. 링크의 텍스트를 "이러한 이유"로 변경합니다
eharo2

답변:


78

원하는 경우를 선언 할 수 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 연산자를 사용할 수 있습니다 .

Swift 3 업데이트

Swift 3에서 "magic number" precedence는 다음으로 대체됩니다 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

따라서 Floats에 대해이 작업을 수행하려면 다음과 같이 하시겠습니까 : 중위 연산자 ^^ {} func ^^ (radix : Float, power : Float)-> Float {return Float (pow (Double (radix), Double (power) )))}
padapa 2015-04-17

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

3
우선 순위가 떨어져서 예상대로 작동하지 않는 것으로 나타났습니다. 지수 연산자의 경우 우선 순위를 160으로 설정합니다 ( developer.apple.com/library/ios/documentation/Swift/Conceptual/…developer.apple.com/library/ios/documentation/Swift/Conceptual/… 참조 ). infix operator ^^ { precedence 160 } func ^^... 등등
Tim Camber 2015 년

이 솔루션은 정말 마음에 들지만 Swift 3에서는 작동하지 않습니다. 어떻게 작동하는지 아십니까?
Vanya

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

59

변수 선언에 구문 오류가 있다는 것 외에는 예상대로 정확히 작동합니다. 당신이해야 할 일은 캐스트 abDouble로 값을 전달하는 것 pow입니다. 그런 다음 2 개의 Int로 작업하고 작업의 다른쪽에 Int를 다시 사용하려면 Int로 다시 캐스팅하십시오.

import Darwin 

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

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

이 대답은 Double 및 Int 유형에서 가장 명확합니다.
midtownguru

그것이 내가 원하는 것입니다. 감사합니다. Python에서는 3 ** 3. 때로는 Swift를 사용하여 알고리즘 문제를 해결해야하는데, Python 사용에 비해 정말 고통 스럽습니다.
ChuckZHB

13

때때로, 캐스팅 IntA를하는 것은 Double실행 가능한 해결책이 아니다. 어떤 규모에서는이 변환에서 정밀도가 손실됩니다. 예를 들어 다음 코드는 직관적으로 예상 할 수있는 내용을 반환하지 않습니다.

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

당신은 필요한 경우 높은 크기의 정밀도를 걱정할 필요가 없습니다 부정적인 지수 - 일반적으로 어쨌든 정수로 해결할 수없는 -의 다음이 구현 꼬리 재귀 지수별로 제곱 알고리즘 되는 가장 좋은 건. 이 SO 답변 에 따르면 이것은 "비대칭 암호화에서 거대한 숫자에 대한 모듈 식 지수화를 수행하는 표준 방법"입니다.

// 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또는 다른 정수와 유사한 유형을 사용할 수 있도록하기위한 것 입니다.


그리고 물론 당신은 이것을 연산자 (더 대중적인 대답이 제안하는 것처럼) 또는 확장으로 정의 Int할 수 있거나 당신의 마음이 원하는대로이 무료 기능을 호출하도록 할 수 있습니다.
mklbtz

이 솔루션은 stackoverflow 예외로 이어지는 것 같습니다
Vyacheslav

11

정말로 '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

실제 구현에서는 오류 검사를 원할 것입니다.


이것은 완전히 유효한 대답입니다. Int를 Doubles로 변환하면 정밀도가 떨어 지므로 Int pow에 대한 실행 가능한 솔루션이 아닌 경우가 있습니다. Double(Int.max - 1) < Double(Int.max)Swift 3 REPL에서 실행 해보면 놀랄 것입니다.
mklbtz

2
길이를 줄이려면 reduce호출로 이를 구현할 수 있습니다. return (2...power).reduce(base) { result, _ in result * base }
mklbtz

1
아마도 당신은 파워를 UInt로 만들어서 전제 조건을 없앨 수있을 것입니다
hashemi

4

조금 더 자세히

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

swift-이진 표현식


4

연산자 오버로딩 ^^이 마음에 들지 않는다면 ( 솔루션은 코드를 읽는 사람에게 분명 할 수 있지만) 빠른 구현을 수행 할 수 있습니다.

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

4

mklbtz는 제곱이 정수 거듭 제곱을 계산하는 표준 알고리즘 인 지수화에 대해 정확하지만 알고리즘의 꼬리 재귀 구현은 약간 혼란스러워 보입니다. C로 제곱하여 지수를 비재 귀적으로 구현하려면 http://www.programminglogic.com/fast-exponentiation-algorithms/ 를 참조 하십시오 . 여기에서 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

그러나 그것은 아마도 사라질 것입니다.


1
아주 좋아요! 일반적으로 Swift> 4.0 (Xcode 9.0)에서이 작업을 수행하려면 BinaryInteger. IntegerType더 이상 사용되지 않습니다.
mklbtz

3

또는 그냥 :

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

3

답변을 오버로드 된 함수 집합으로 결합 (다른 언어에서 사용하는 "^^"대신 "**"사용-더 명확함) :

// 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를 사용하면 정밀도가 떨어질 수 있습니다. 숫자 리터럴과 정수와 정수가 아닌 혼합을 사용하는 경우 기본적으로 Double이됩니다. 저는 개인적으로 스타일 / 가독성을 위해 pow (a, b)와 같은 함수 대신 수학적 표현을 사용하는 기능을 좋아하지만 그게 바로 저입니다.

pow ()로 인해 오류가 발생하는 모든 연산자는 이러한 함수에서 오류를 발생 시키므로 오류 검사의 부담은 어쨌든 power 함수를 사용하는 코드에 있습니다. 키스, IMHO.

기본 pow () 함수를 사용하면 제곱근 (2 ** 0.5) 또는 역 (2 ** -3 = 1/8)을 사용할 수 있습니다. 역 지수 또는 분수 지수를 사용할 수 있기 때문에 모든 코드를 작성하여 pow () 함수의 기본 Double 유형을 반환했습니다.이 함수는 가장 정밀도를 반환해야합니다 (문서를 올바르게 기억한다면). 필요한 경우 Int 또는 Float 등으로 형변환 할 수 있으며 정밀도가 떨어질 수 있습니다.

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

pow ()는 분수 부분도 매우 중요한 대규모 계산에는 적합하지 않습니다. 나를 위해 당신의 대답은 힌트를 제공합니다. 감사합니다 :)
마헨드라

3

을 사용할 수도 있습니다 pow(). 예를 들어 다음을 사용하여 10에서 9까지를 표현할 수 있습니다.

pow(10, 9)

와 함께 pow, 대신 powf()a float를 반환 합니다 double. Swift 4 및 macOS 10.13에서만 테스트했습니다.


1
pow (a, b)는 b <0이면 NaN을 반환합니다. 그래서 이것에 대한 테스트를 추가 할 수 있습니다 : let power = (b> = 0)? pow (a, b) : 1 / pow (a, -b); a는 Decimal로 선언되어야합니다. let a : Decimal = 2; 하자 B = -3
claude31

2

을 계산하려면 다음 power(2, n)을 사용하십시오.

let result = 2 << (n-1)

1

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

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

Swift 5에서 base 2에 대한 비트 시프트를 통해 직접 값을 계산하는 Int 기반 pow 함수입니다.

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

(결과가 Int 범위 내에 있는지 확인하십시오. 범위를 벗어난 경우를 확인하지 않습니다.)


1

다른 답변은 훌륭하지만 원하는 경우 Int지수가 양수인 한 확장명으로 도 할 수 있습니다 .

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

오버로딩을 결합하려고 시도하면서 제네릭을 사용하려고했지만 작동하지 못했습니다. 마침내 오버로드를 시도하거나 제네릭을 사용하는 대신 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
    }
}

-1

스위프트 5

놀랐지 만 여기서 올바른 해결책을 찾지 못했습니다.

이 내 꺼야:

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

예:

CustomMath.pow(1,1)

-2

나는 이것을 더 좋아한다

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
표준 xor 연산자를 대체합니다. 이를 사용하면 단일 캐럿을 재정의하는 것을 모르는 사람에게 코드가 예상치 못한 방식으로 동작하게됩니다.
wjl

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

예:

calc (2,2)

1
코드를 답에 덤핑하는 것보다 코드가 솔루션을 제공하는 이유를 설명하는 것이 좋습니다.
Rudi Kershaw 2014

1
그리고 그것은 올바른 멱 함수와는 거리가 멀다. 지수 또는 음수 값으로 0은 어떻습니까?
macbirdie 2014

또한 'calc'라는 이름은 이러한 특정 작업에 사용하기에는 너무 일반적입니다. cal (2,2)는 2 개의 숫자에 적용하려는 모든 가능한 계산을 의미 할 수 있습니다. 2 + 2, 2-2, 2 * 2, 2/2, 2pow2, 2root2 등
eharo2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.