¿Cómo obtener el Poder de algún Entero en el lenguaje Swift?


Estoy aprendiendo swift recientemente, pero tengo un problema básico que no puedo encontrar una respuesta

Quiero conseguir algo como

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

Pero la función pow solo puede funcionar con número doble, no funciona con número entero, y ni siquiera puedo convertir el int en doble por algo como Double(a) o a.double()...

¿Por qué no suministra la potencia de integer? ¡definitivamente devolverá un entero sin ambigüedad ! ¿y por qué no puedo convertir un entero a un doble? acaba de cambiar 3 a 3.0 (o 3.00000... lo que sea)

Si tengo dos enteros y quiero hacer la operación de energía, ¿cómo puedo hacerlo sin problemas?

Gracias!

Author: 林鼎棋, 2014-06-13

15 answers

Si lo desea, puede declarar un infix operator para hacerlo.

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

Usé dos comillas para que aún puedas usar el operador XOR .

Actualización para Swift 3

En Swift 3 el "número mágico" precedence se sustituye 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
 62
Author: Grimxn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-20 08:04:42

Aparte de que sus declaraciones de variables tienen errores de sintaxis, esto funciona exactamente como lo esperaba. Todo lo que tienes que hacer es lanzar al Doble, y pasar los valores a pow. Entonces, si usted está trabajando con 2 Ints, y usted quiere una parte posteriora del Int en el otro lado de la operación, apenas caso detrás a Int

import Darwin 

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

let x: Int = Int(pow(Double(a),Double(b)))
 34
Author: Mick MacCallum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-22 22:13:35

A veces, lanzar un Int a un Double no es una solución viable. En algunas magnitudes hay una pérdida de precisión en esta conversión. Por ejemplo, el siguiente código no devuelve lo que podría esperar intuitivamente. (Swift 3.0)

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

Si necesita precisión a altas magnitudes y no necesita preocuparse por exponentes negativos - que generalmente no se pueden resolver con enteros de todos modos-entonces esta implementación de la cola recursiva el algoritmo de exponenciación por cuadratura es su mejor apuesta. De acuerdo con this SO answer, este es "el método estándar para hacer exponenciación modular para números enormes en criptografía asimétrica."

func pow(_ base: Int, _ power: Int) -> Int {
    func expBySq(_ y: Int, _ x: Int, _ n: Int) -> Int {
        precondition(n >= 0)
        if n == 0 {
            return y
        } else if n == 1 {
            return y * x
        } else if n % 2 == 0 {
            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) 
}
 6
Author: mklbtz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:51

Pequeño detalle más

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

Swift-Expresiones binarias

 4
Author: tylyo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-18 22:36:29

Si no está inclinado hacia la sobrecarga del operador (aunque la solución ^^ probablemente sea clara para alguien que lea su código), puede hacer una implementación rápida:

let pwrInt:(Int,Int)->Int = { a,b in return Int(pow(Double(a),Double(b))) }
pwrInt(3,4) // 81
 4
Author: HenryRootTwo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-08 22:50:25

Combinando las respuestas en un conjunto sobrecargado de funciones (y usando "**" en lugar de "^^" como usan otros lenguajes - más claro para mí):

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

Al usar Float, puede perder precisión. Si usa literales numéricos y una mezcla de enteros y no enteros, terminará con Double por defecto. Personalmente me gusta la capacidad de usar una expresión matemática en lugar de una función como pow(a, b) por razones de estilo/legibilidad, pero eso es solo yo.

Cualquier operador que causaría que pow () lanzara un error también causaría que estas funciones lanzaran un error, por lo que la carga de la comprobación de errores aún recae en el código que usa la función power de todos modos. BESO, EN MI HUMILDE OPINIÓN.

Usando la función nativa pow() permite por ejemplo tomar raíces cuadradas (2 ** 0.5) o inversas (2 ** -3 = 1/8). Debido a la posibilidad de usar exponentes inversos o fraccionarios, escribí todo mi código para devolver el tipo Doble predeterminado de la función pow (), que debería devolver la mayor precisión (si recuerde la documentación correctamente). Si es necesario, esto puede ser tipo-fundido abajo a Int o flotar o lo que sea, posiblemente con la pérdida de precisión.

2 ** -3  = 0.125
2 ** 0.5 = 1.4142135623731
2 ** 3   = 8
 3
Author: ECJB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-17 15:00:20

Mklbtz tiene razón sobre la exponenciación por cuadratura siendo el algoritmo estándar para calcular potencias enteras, pero la implementación recursiva de cola del algoritmo parece un poco confusa. Véase http://www.programminglogic.com/fast-exponentiation-algorithms / para una implementación no recursiva de la exponenciación por cuadratura en C. He intentado traducirla a Swift aquí:

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
}

Por supuesto, esto podría imaginarse creando un operador sobrecargado para llamarlo y podría reescribirse para hacerlo más genérico para que funcionara en cualquier cosa que implementara el protocolo IntegerType. Para hacerlo genérico, probablemente comenzaría con algo como

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

Pero, eso es probablemente dejarse llevar.

 3
Author: Paul Buis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-01 11:20:25

Si realmente quieres una implementación 'solo Int' y no quieres coaccionar hacia / desde Double, tendrás que implementarlo. Aquí hay una implementación trivial; hay algoritmos más rápidos, pero esto 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

En una implementación real, probablemente querrá alguna comprobación de errores.

 2
Author: GoZoner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-06 18:48:23

Resulta que también puedes usar pow(). Por ejemplo, puede usar lo siguiente para expresar del 10 al 9.

pow(10, 9)

Junto con pow, powf() devuelve un float en lugar de double. Solo he probado esto en Swift 4 y macOS 10.13.

 2
Author: Jake3231,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-14 23:38:29

O simplemente:

var a:Int = 3
var b:Int = 3
println(pow(Double(a),Double(b)))
 1
Author: Fafa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-31 18:46:37

Tratando de combinar la sobrecarga, traté de usar genéricos pero no pude hacerlo funcionar. Finalmente pensé en usar NSNumber en lugar de tratar de sobrecargar o usar genéricos. Esto se simplifica a lo siguiente:

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

El siguiente código es la misma función que la anterior, pero implementa la comprobación de errores para ver si los parámetros se pueden convertir a Dobles con é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
    }
}
 0
Author: ECJB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-22 04:59:45

Para calcular power(2, n), simplemente use:

let result = 2 << (n-1)
 0
Author: Le Binh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-06 02:06:27

Swift 4.x version

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
}
 0
Author: Mahendra GP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-12 04:22:50

Esto me gusta más

func ^ (left:NSNumber, right: NSNumber) -> NSNumber {
    return pow(left.doubleValue,right.doubleValue)
}
var a:NSNumber = 3
var b:NSNumber = 3 
println( a^b ) // 27
 -1
Author: Cody Crank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-06 02:24:45
    func calc (base:Int, number:Int) -> Int {
    var answer : Int = base
    for _ in 2...number {answer *= base } 
    return answer
    }
    calc (2,2)
 -3
Author: artnazar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-24 14:47:21