¿Cómo obtener el poder de un entero en lenguaje Swift?


102

Estoy aprendiendo rápido 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 puede funcionar solo con un número doble, no funciona con un número entero, y ni siquiera puedo convertir el int para doblar con algo como Double (a) o a.double () ...

¿Por qué no proporciona el poder del número entero? ¡definitivamente devolverá un número entero sin ambigüedad! y ¿Por qué no puedo convertir un número entero en un doble? simplemente cambia 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!


Estas declaraciones de tipo son incorrectas
Edgar Aroutiounian

la mayoría de los idiomas no tienen una función de potencia entera debido a esta razón
phuclv

1
La nota de @ phuclv apunta a una gran discusión sobre el tema. Cambiaría el texto en el enlace a "estos motivos"
eharo2

Respuestas:


78

Si lo desea, puede declarar un infix operatorpara 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 signos de intercalación para que puedas seguir usando el operador XOR .

Actualización para Swift 3

En Swift 3, el "número mágico" precedencese reemplaza 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

Entonces, si quisieras hacer esto para Floats, harías esto: 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
Encontré que esto no se comportaba como esperaba porque la precedencia estaba apagada. Para un operador exponencial, establezca precedencia en 160 (consulte developer.apple.com/library/ios/documentation/Swift/Conceptual/… y developer.apple.com/library/ios/documentation/Swift/Conceptual/… ) así: infix operator ^^ { precedence 160 } func ^^... y así sucesivamente
Tim Camber

Realmente me gusta esta solución, pero con Swift 3 no funciona. ¿Alguna idea de cómo hacer que funcione?
Vanya

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

59

Aparte de que sus declaraciones de variables tienen errores de sintaxis, esto funciona exactamente como esperaba. Todo lo que tienes que hacer es lanzar ay bduplicar y pasar los valores a pow. Luego, si está trabajando con 2 Ints y quiere un Int de vuelta en el otro lado de la operación, simplemente devuelva a Int.

import Darwin 

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

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

Esta respuesta es la más clara con los tipos Double e Int.
midtownguru

Eso es lo que quiero, gracias. En Python, solo 3 ** 3. A veces, necesito resolver un problema de algoritmo usando Swift, es realmente doloroso en comparación con el uso de Python.
ChuckZHB

13

A veces, lanzar un Intto a Doubleno 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.

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

Si necesita precisión en magnitudes altas y no necesita preocuparse por exponentes negativos , que generalmente no se pueden resolver con números enteros de todos modos, entonces esta implementación del algoritmo de exponenciación por cuadratura recursiva de cola es su mejor opción. Según esta respuesta SO , este es "el método estándar para hacer exponenciación modular para grandes números en criptografía asimé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: en este ejemplo he usado un archivo T: BinaryInteger. Esto es lo que puede utilizar Into UInt, o cualquier otro tipo entero similar.


Y, por supuesto, siempre puede definir esto como un operador (como sugieren las respuestas más populares) o una extensión Into puede hacer que esas cosas llamen a esta función gratuita, lo que su corazón desee.
mklbtz

Parece que esta solución conduce a una excepción de desbordamiento de pila
Vyacheslav

11

Si realmente desea una implementación 'Int solo' y no desea forzar a / desdeDouble , deberá implementarla. 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á verificar algunos errores.


Esta es una respuesta completamente válida. Hay algunos casos en los que la conversión de Ints en Doubles pierde precisión, por lo que no es una solución viable para Int pow. Simplemente intente ejecutar Double(Int.max - 1) < Double(Int.max)Swift 3 REPL y se sorprenderá.
mklbtz

2
Para acortarlo, puede implementar esto con una reducellamada. return (2...power).reduce(base) { result, _ in result * base }
mklbtz

1
Tal vez pueda deshacerse de la condición previa haciendo que el poder sea una UInt
hashemi

4

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

Si no está inclinado a la sobrecarga de operadores (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

mklbtz tiene razón acerca de la exponenciación al elevar al cuadrado como algoritmo estándar para calcular potencias enteras, pero la implementación recursiva de cola del algoritmo parece un poco confusa. Consulte http://www.programminglogic.com/fast-exponentiation-algorithms/ para ver una implementación no recursiva de exponenciación al elevar al cuadrado C. Intenté traducirlo 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 inventarse creando un operador sobrecargado para llamarlo y podría reescribirse para hacerlo más genérico para que funcione en cualquier cosa que implemente el IntegerTypeprotocolo. 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 probablemente se esté dejando llevar.


1
¡Muy agradable! Para hacer esto de forma genérica en Swift> 4.0 (Xcode 9.0), querrá usar BinaryInteger. IntegerTypeestaba en desuso.
mklbtz

3

O solo :

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

3

Combinando las respuestas en un conjunto de funciones sobrecargadas (y usando "**" en lugar de "^^" como usan otros idiomas, 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 combinación 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 así soy yo.

Cualquier operador que cause que pow () arroje un error también hará que estas funciones arrojen un error, por lo que la carga de la verificació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.

El uso de 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 Double predeterminado de la función pow (), que debería devolver la mayor precisión (si recuerdo la documentación correctamente). Si es necesario, esto se puede convertir en Int o Float o lo que sea, posiblemente con la pérdida de precisión.

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

pow () no es adecuado para cálculos grandes donde la parte fraccionaria también es muy importante. Para mí, tu respuesta da una pista. Gracias :)
Mahendra

3

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

pow(10, 9)

Junto con pow, powf()devuelve a en floatlugar de a double. Solo lo he probado en Swift 4 y macOS 10.13.


1
pow (a, b) devuelve NaN si b <0; para que pueda agregar una prueba para esto: let power = (b> = 0)? pow (a, b): 1 / pow (a, -b); tenga en cuenta que a debe declararse como decimal, deje a: decimal = 2; let b = -3
claude31

2

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

let result = 2 << (n-1)

1

Versión 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

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

Úselo así

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

Gracias a la respuesta de @Paul Buis.



1

Una función de pow basada en Int que calcula el valor directamente a través del desplazamiento de bits para la base 2 en 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, *)
}

(Asegúrese de que el resultado esté dentro del rango de Int; esto no verifica el caso fuera de límites)


1

Las otras respuestas son excelentes, pero si lo prefiere, también puede hacerlo con una Intextensión siempre que el exponente sea 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

Intentando combinar la sobrecarga, intenté usar genéricos pero no pude hacerlo funcionar. Finalmente pensé en usar NSNumber en lugar de intentar 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 el anterior, pero implementa la verificació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
    }
}

-1

Rápido 5

Me sorprendió, pero no encontré una solución correcta y adecuada aquí.

Esto es mío:

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

Ejemplo:

CustomMath.pow(1,1)

-2

Me gusta mas esto

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
Eso reemplaza al operador xor estándar. Usar esto hará que su código se comporte de una manera muy inesperada para cualquiera que no sepa que está anulando el quilate.
wjl

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

Ejemplo:

calc (2,2)

1
Es una buena práctica explicar por qué su código ofrece una solución, en lugar de simplemente volcar código en una respuesta.
Rudi Kershaw

1
Y está lejos de ser una función de potencia correcta. ¿Qué tal 0 como exponente o cualquier valor negativo?
Macbirdie

Además, el nombre "calc" es demasiado genérico para ser utilizado en una operación tan específica. Cal (2,2) puede significar cualquier cálculo posible que desee aplicar a 2 números ... 2 + 2, 2-2, 2 * 2, 2/2, 2pow2, 2root2, etc.
eharo2
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.