Como obter o poder de algum inteiro na linguagem Swift?


102

Estou aprendendo rápido recentemente, mas tenho um problema básico que não consigo encontrar uma resposta

Eu quero conseguir algo como

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

mas a função pow pode funcionar apenas com número duplo, não funciona com número inteiro, e eu não consigo nem converter o int para dobrar por algo como Double (a) ou a.double () ...

Por que ele não fornece a potência do inteiro? ele definitivamente retornará um número inteiro sem ambigüidade! e por que não consigo converter um inteiro em duplo? basta alterar 3 para 3.0 (ou 3.00000 ... qualquer)

se eu tenho dois inteiros e quero fazer a operação de energia, como posso fazer isso sem problemas?

Obrigado!


Essas declarações de tipo estão erradas
Edgar Aroutiounian

a maioria das línguas não tem uma função de potência inteira devido a este motivo
phuclv

1
A nota de @phuclv aponta para uma grande discussão sobre o assunto. Eu mudaria o texto no link para "estes motivos"
eharo2

Respostas:


78

Se quiser, você pode declarar um infix operatorpara fazer isso.

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

Usei dois circunflexos para que você ainda possa usar o operador XOR .

Atualização para Swift 3

No Swift 3, o "número mágico" precedenceé substituído por 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

Então, se você quiser fazer isso para Floats, você faria o seguinte: infix operator ^^ {} 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
Achei que isso não se comportou exatamente como eu esperava porque a precedência estava desativada. Para um operador exponencial, defina a precedência para 160 (consulte developer.apple.com/library/ios/documentation/Swift/Conceptual/… e developer.apple.com/library/ios/documentation/Swift/Conceptual/… ) assim: infix operator ^^ { precedence 160 } func ^^... e assim por diante
Tim Camber

Gosto muito dessa solução, mas com o Swift 3 ela não funciona. Alguma ideia de como fazer funcionar?
Vanya

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

59

Além de que suas declarações de variáveis ​​têm erros de sintaxe, isso funciona exatamente como você esperava. Tudo que você tem a fazer é lançado ae bpara Double e passar os valores para pow. Então, se você estiver trabalhando com 2 Ints e quiser um Int de volta do outro lado da operação, basta lançar de volta para Int.

import Darwin 

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

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

Essa resposta é mais clara com os tipos Double e Int.
midtownguru

É isso que eu quero, obrigado. Em Python, apenas 3 ** 3. Às vezes, preciso resolver problemas de algoritmo usando Swift, é realmente doloroso em comparação com o uso de Python.
ChuckZHB

13

Às vezes, lançar um Intem a Doublenão é uma solução viável. Em algumas magnitudes, há perda de precisão nessa conversão. Por exemplo, o código a seguir não retorna o que você pode esperar intuitivamente.

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

Se você precisa de precisão em altas magnitudes e não precisa se preocupar com expoentes negativos - que geralmente não podem ser resolvidos com inteiros de qualquer maneira - então esta implementação do algoritmo de exponenciação por quadratura recursiva de cauda é sua melhor aposta. De acordo com esta resposta do SO , este é "o método padrão para fazer exponenciação modular para grandes números em criptografia assimétrica."

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

Nota: neste exemplo, usei um genérico T: BinaryInteger. Isso é para que você possa usar Intou UIntou qualquer outro tipo de número inteiro.


E, claro, você sempre pode definir isso como uma operadora (como as respostas mais populares sugerem) ou uma extensão para Intou pode fazer com que essas coisas chamem essa função gratuita - o que seu coração desejar.
mklbtz

Parece que essa solução leva a uma exceção stackoverflow
Vyacheslav

11

Se você realmente deseja uma implementação 'Int only' e não quer forçar de / paraDouble , você precisará implementá-la. Aqui está uma implementação trivial; existem algoritmos mais rápidos, mas isso funcionará:

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

Em uma implementação real, você provavelmente deseja alguma verificação de erros.


Esta é uma resposta totalmente válida. Existem alguns casos em que converter Ints em Doubles perde a precisão e, portanto, essa não é uma solução viável para Int pow. Apenas tente rodar Double(Int.max - 1) < Double(Int.max)em um REPL Swift 3 e você ficará surpreso.
mklbtz

2
Para encurtar, você pode implementar isso com uma reducechamada. return (2...power).reduce(base) { result, _ in result * base }
mklbtz

1
Talvez você possa se livrar da pré-condição tornando a energia um UInt
hashemi

4

pequeno detalhe mais

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

swift - Expressões binárias


4

Se você não está inclinado a sobrecarregar o operador (embora a ^^solução provavelmente seja clara para alguém que está lendo seu código), você pode fazer uma implementação rápida:

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

4

mklbtz está correto sobre a exponenciação por quadrado ser o algoritmo padrão para calcular potências inteiras, mas a implementação recursiva de cauda do algoritmo parece um pouco confusa. Veja http://www.programminglogic.com/fast-exponentiation-algorithms/ para uma implementação não recursiva de exponenciação por quadrado em C. Eu tentei traduzi-lo para Swift aqui:

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
}

Claro, isso poderia ser imaginado criando um operador sobrecarregado para chamá-lo e poderia ser reescrito para torná-lo mais genérico para que funcionasse em qualquer coisa que implementasse o IntegerTypeprotocolo. Para torná-lo genérico, provavelmente começaria com algo como

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

Mas, isso provavelmente está se deixando levar.


1
Muito agradável! Para fazer isso genericamente em Swift> 4.0 (Xcode 9.0), você deseja usar BinaryInteger. IntegerTypefoi descontinuado.
mklbtz

3

Ou apenas :

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

3

Combinar as respostas em um conjunto sobrecarregado de funções (e usar "**" em vez de "^^" como algumas outras linguagens usam - mais claro para mim):

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

Ao usar Float, você pode perder a precisão. Se estiver usando literais numéricos e uma mistura de inteiros e não inteiros, você terminará com Double por padrão. Pessoalmente, gosto da capacidade de usar uma expressão matemática em vez de uma função como pow (a, b) por motivos estilísticos / legibilidade, mas sou só eu.

Quaisquer operadores que façam pow () lançar um erro também farão com que essas funções gerem um erro, portanto, o fardo da verificação de erros ainda recai sobre o código que usa a função power de qualquer maneira. KISS, IMHO.

Usar a função nativa pow () permite, por exemplo, obter raízes quadradas (2 ** 0,5) ou inversa (2 ** -3 = 1/8). Por causa da possibilidade de usar expoentes inversos ou fracionários, escrevi todo o meu código para retornar o tipo Double padrão da função pow (), que deve retornar a maior precisão (se bem me lembro da documentação). Se necessário, isso pode ser convertido em tipo para Int ou Float ou qualquer outro, possivelmente com perda de precisão.

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

pow () não é adequado para cálculos grandes onde a parte fracionária também é muito importante. Para mim, sua resposta dá uma dica. Obrigado :)
Mahendra

3

Acontece que você também pode usar pow(). Por exemplo, você pode usar o seguinte para expressar 10 à 9ª.

pow(10, 9)

Junto com pow, powf()retorna um em floatvez de a double. Eu testei isso apenas no Swift 4 e no macOS 10.13.


1
pow (a, b) retorna NaN se b <0; então você poderia adicionar um teste para isso: let power = (b> = 0)? pow (a, b): 1 / pow (a, -b); observe que a deve ser declarado como Decimal seja a: Decimal = 2; deixe b = -3
claude31

2

Para calcular power(2, n), basta usar:

let result = 2 << (n-1)

1

Versão 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

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

Usar assim

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

Obrigado a resposta de @Paul Buis.


1

Array (repetindo: a, contagem: b) .reduce (1, *)


1

Uma função de potência baseada em Int que calcula o valor diretamente por meio do deslocamento de bits para a base 2 no 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, *)
}

(Certifique-se de que o resultado está dentro do intervalo de Int - isso não verifica o caso fora dos limites)


1

As outras respostas são ótimas, mas se preferir, você também pode fazer isso com uma Intextensão, desde que o expoente seja positivo.

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

Tentando combinar a sobrecarga, tentei usar genéricos, mas não consegui fazer funcionar. Finalmente decidi usar o NSNumber em vez de tentar sobrecarregar ou usar genéricos. Isso simplifica o seguinte:

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

O código a seguir tem a mesma função acima, mas implementa a verificação de erros para ver se os parâmetros podem ser convertidos para Doubles com êxito.

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

Fiquei surpreso, mas não encontrei uma solução correta adequada aqui.

Isso é meu:

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

Exemplo:

CustomMath.pow(1,1)

-2

Eu gosto mais disso

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
Isso substitui o operador xor padrão. Usar isso fará com que seu código se comporte de uma maneira muito inesperada para qualquer um que não saiba que você está substituindo o quilate individual.
wjl

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

Exemplo:

calc (2,2)

1
É uma boa prática explicar por que seu código oferece uma solução, em vez de apenas despejar o código em uma resposta.
Rudi Kershaw

1
E está longe de ser uma função de alimentação correta. Que tal 0 como expoente ou qualquer valor negativo.
macbirdie

Além disso, o nome 'calc "é muito genérico para ser usado em uma operação específica .. cal (2,2) pode significar qualquer cálculo possível que você deseja aplicar a 2 números ... 2 + 2, 2-2, 2 * 2, 2/2, 2pow2, 2root2, etc.
eharo2
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.