﻿ How to Make My Exponentiation Operator Work With All Numeric Types in Swift - ITCodar

# How to Make My Exponentiation Operator Work With All Numeric Types in Swift

## How do I make my exponentiation operator work with all numeric types in Swift?

Here is a more type-safe implementation, using operator overloading. For integer types,
you can define `^^` as

``infix operator ^^ { associativity left precedence 170 }func ^^<T : IntegerType, U : IntegerType> (base: T, var power: U) -> T {    if power < 0 { return 0 }    var result : T = 1    var square : T = base    if power > 0 {        if power % 2 == 1 { result *= square }        power /= 2    }    while power > 0 {        square *= square        if power % 2 == 1 { result *= square }        power /= 2    }    return result}``

(I have chosen a more efficient variant called "exponentiation by repeated squaring and multiplication".)

For floating point types, define a protocol the covers all types that can be
converted from and to `Double`:

``protocol DoubleConvertible {    init(_ value: Double)    var doubleValue : Double { get }}``

and make `Float`, `Double` and `CGFloat` conform to that protocol:

``extension Double : DoubleConvertible {    var doubleValue : Double { return self }}extension Float : DoubleConvertible {    var doubleValue : Double { return Double(self) }}extension CGFloat : DoubleConvertible {    var doubleValue : Double { return Double(self) }}``

Now the floating point exponentiation can simply be defined as

``func ^^<T : DoubleConvertible, U:DoubleConvertible> (base: T, power: U) -> T {    return T(pow(base.doubleValue, power.doubleValue))}``

Examples:

``let x1 = 2^^3               // Intlet x2 = UInt64(2)^^3       // UInt64 let x3 = 2.0 ^^ 3           // Doublelet x4 = Float(2.0) ^^ 3    // Floatlet x5 = "a" ^^ "b"         // Compiler error``

Update for Swift 4:

`IntegerType` has become `BinaryInteger` (SE-0104 Protocol-oriented integers) and
the syntax for declaring operators has changed
(SE-0077 Improved operator declarations.)

Here is an implementation for all integer and floating point
bases with `Int` exponents:

``precedencegroup ExponentiationPrecedence { associativity: right higherThan: MultiplicationPrecedence }infix operator ^^: ExponentiationPrecedencefunc ^^<T : BinaryInteger>(base: T, power: Int) -> T {    if power < 0 { return 0 }    var power = power    var result: T = 1    var square = base    if power > 0 {        if power % 2 == 1 { result *= square }        power /= 2    }    while power > 0 {        square *= square        if power % 2 == 1 { result *= square }        power /= 2    }    return result}func ^^(base: Float, power: Int) -> Float {    return pow(base, Float(power))}func ^^(base: Double, power: Int) -> Double {    return pow(base, Double(power))}func ^^(base: CGFloat, power: Int) -> CGFloat {    return pow(base, CGFloat(power))}``

Examples:

``let x1 = 2^^3            // Intlet x2 = UInt64(2)^^3    // UInt64let x3 = 2.0 ^^ -3       // Doublelet x4 = Float(2.0) ^^ 3 // Float// let x6 = "a" ^^ 5      // Compiler error``

See SE-0104 Protocol-oriented integers
about the new protocol hierarchy introduced in Swift 4.

## Exponentiation operator in Swift

There isn't an operator but you can use the pow function like this:

``return pow(num, power)``

If you want to, you could also make an operator call the pow function like this:

``infix operator ** { associativity left precedence 170 }func ** (num: Double, power: Double) -> Double{    return pow(num, power)}2.0**2.0 //4.0``

## Swift How combine to Numeric Type

You don't have to re-invent the wheel, there is already protocol which you need: `Numeric`.

Its description is very self-descriptive:

A type with values that support multiplication

And the types like `Int`, `Double`, ... already conform to it.

Anyway, if you wonder why your code doesn't work, it's because protocol provides interface and tells what implementations should contain and what is possible to do with them.

So, if you need that your `Number`s can be multiplied, you need to describe it in protocol's declaration.

``protocol Number {    static func * (lhs: Self, rhs: Self) -> Self}``

... now you described that every `Number` can be multiplied by other `Number`. /p>

## How to get the Power of some Integer in Swift language?

If you like, you could declare an `infix` `operator` to do it.

``// Put this at file level anywhere in your projectinfix 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// ... orprintln("2³ = \(2 ^^ 3)") // Prints 2³ = 8``

I used two carets so you can still use the XOR operator.

Update for Swift 3

In Swift 3 the "magic number" `precedence` is replaced by `precedencegroups`:

``precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence }infix operator ^^ : PowerPrecedencefunc ^^ (radix: Int, power: Int) -> Int {    return Int(pow(Double(radix), Double(power)))}// ...// Then you can do this...let i2 = 2 ^^ 3// ... orprint("2³ = \(2 ^^ 3)") // Prints 2³ = 8``

## How can I raise all the elements in an int array by a power of 3 in Swift?

You can use map() and pow() together:

``import Foundationlet nums = [1, 2, 3, 4, 5, 6]let cubes = nums.map { Int(pow(Double(\$0), 3)) }let raisedBySix = nums.map { Int(pow(Double(\$0), 6)) }print(cubes)       // [1, 8, 27, 64, 125, 216]print(raisedBySix) // [1, 64, 729, 4096, 15625, 46656]``

## Swift's pow() function won't accept Doubles as arguments

Because pow returns `Double`. And `Double` is not identical to `T`. The error message is misleading, but it means "Cannot find `pow` that accepts `(Double, Double)` and returns `T` type"

I think you are misunderstanding "cast" in Swift. In Swift `as` does not convert numeric types.

``let intVal:Int = 12let doubleVal:Double = intVal as Double//                            ^ [!] error: 'Int' is not convertible to 'Double'``

And If the type of operand is not predictable at compile time, invalid casting causes runtime error:

``func foo<T: IntegerLiteralConvertible>(x: T)  {    x as Double // <-- Execution was interrupted}foo(12 as Int)``

Instead, we must explicitly "convert" them. see the document: Numeric Type Conversion

``let intVal:Int = 12let doubleVal:Double = Double(intVal)``

This works only because `Double` has `init(_ v: Int)` initializer. The following code does not compile:

``func foo<T: IntegerLiteralConvertible>(x: T)  {    Double(x)//  ^~~~~~~~~ [!] error: cannot invoke 'init' with an argument of type 'T'}``

Because `Double` does not have `init<T:IntegerLiteralConvertible>(_ val:T)` initializer.

So, if you want to use `pow()`, you must convert `T` to `Double` for arguments, and convert `Double` to `T` for returning value. And there is no simple solution for that.

Submit