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 // Int
let x2 = UInt64(2)^^3 // UInt64
let x3 = 2.0 ^^ 3 // Double
let x4 = Float(2.0) ^^ 3 // Float
let 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 ^^: ExponentiationPrecedence
func ^^<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 // Int
let x2 = UInt64(2)^^3 // UInt64
let x3 = 2.0 ^^ -3 // Double
let 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 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
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 ^^ : 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
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 Foundation
let 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
why is it complaining about this?
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 = 12
let 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 = 12
let 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.
Related Topics
What Does the Dollar Sign Do in Swift/Swiftui
Can Swift Return Value from an Async Void-Returning Block
Tabview Resets Navigation Stack When Switching Tabs
First Item in a List Is Always Selected
What Is Difference Between Optional and Decodeifpresent When Using Decodable For Json Parsing
How Does Collisionbitmask Work? Swift/Spritekit
How to Remove the Left and Right Padding of a List in Swiftui
Swift 4 Decodable - Dictionary With Enum as Key
How to Convert a Decimal Number to Binary in Swift
Nsattributedstring, Change the Font Overall But Keep All Other Attributes
How Flatmap API Contract Transforms Optional Input to Non Optional Result
How to See Which Version of Swift I'M Using
Go to a New View Using Swiftui
Wait Until Swift For Loop With Asynchronous Network Requests Finishes Executing
"Classname Has No Member Functionname" When Adding Uibutton Target