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

I created this infix operator ^^ as a substitute to using the pow function:
infix operator ^^ { associativity left precedence 155 }
func ^^ <T: IntegerLiteralConvertible>(left: T, right: T) -> T {
return pow(left as Double, right as Double)
}
I used the IntegerLiteralConvertible protocol as a type constraint for the generics left and right, because from my understanding this diagramm shows, that it basically includes all number types.
In order to use the pow function I have to downcast left and right to Double though, which I did using the as operator. It's not the safest approach, but that's besides the point.
When implementing the function this way swift tells me:
<stdin>:4:12: error: cannot invoke 'pow' with an argument list of type '(Double, Double)'
return pow(left as Double, right as Double)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now as far as I know pow takes two Doubles as parameters, so why is it complaining about this?

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.

Thanks #Martin R. This comes from the only question I have posted so far at S.O.
import Cocoa
Protocols
protocol Fraction { init(_ value:Double) ; var asDouble : Double { get } }
protocol Text { init(_ value:String) ; var asString : String { get } }
Extensions
extension String : Text { var asString : String { return self } }
extension Double : Fraction { var asDouble : Double { return self } }
extension Float : Fraction { var asDouble : Double { return Double(self) } }
extension CGFloat : Fraction { var asDouble : Double { return Double(self) } }
infix operator ^^
infix operator ^^ { associativity left precedence 170 }
func ^^<T:IntegerType, U:IntegerType> (var base:T, var power:U) -> T {
if power < 0 { return 0 }
var result: T = 1
if power > 0 {
if power % 2 == 1 { result *= base }
power /= 2
}
while power > 0 {
base *= base
if power % 2 == 1 { result *= base }
power /= 2
}
return result
}
func ^^<T:Fraction, U:Fraction> (base: T, power: U) -> T {
return T(pow(base.asDouble, power.asDouble))
}
func ^^<T:Text, U:IntegerType> (base:T, var power:U) -> T {
if power <= 0 { return "" as T }
if power == 1 { return base as T }
return power > 1 ? {var result = ""; for x in 1...power { result+=base.asString };return result as T}() : "" as T
}
func ^^<T:Text, U:Text> (base:T, var power:U) -> T {
return "" as T
}
testing
println(1 ^^ -1) // "0" Int
println(1 ^^ 0) // "1" Int
println(1 ^^ 1) // "1" Int
println(1 ^^ 2) // "1" Int
println(2 ^^ -1) // "0" Int
println(2 ^^ 0) // "1" Int
println(2 ^^ 1) // "2" Int
println(2 ^^ 2) // "4" Int
println(2 ^^ 8) // "256" Int
println(2 ^^ 16) // "65536" Int
println(2 ^^ 32) // "4294967296" Int
println(2 ^^ 62) // "4611686018427387904"
println(UInt(2) ^^ 8) // "256" UInt
println(UInt64(2) ^^ 8) // "256" UInt64

Related

Can we overload = (assignment operator) in swift? [duplicate]

I would like to override the '=' operator for a CGFloat like the follow try :
func = (inout left: CGFloat, right: Float) {
left=CGFloat(right)
}
So I could do the following:
var A:CGFloat=1
var B:Float=2
A=B
Can this be done ? I get the error Explicitly discard the result of the closure by assigning to '_'
That's not possible - as outlined in the documentation:
It is not possible to overload the default assignment operator (=). Only the compound assignment operators can be overloaded. Similarly, the ternary conditional operator (a ? b : c) cannot be overloaded.
If that doesn't convince you, just change the operator to +=:
func +=(left: inout CGFloat, right: Float) {
left += CGFloat(right)
}
and you'll notice that you will no longer get a compilation error.
The reason for the misleading error message is probably because the compiler is interpreting your attempt to overload as an assignment
You can not override assignment but you can use different operators in your case. For example &= operator.
func &= (inout left: CGFloat, right: Float) {
left = CGFloat(right)
}
So you could do the following:
var A: CGFLoat = 1
var B: Float = 2
A &= B
By the way operators &+, &-, &* exist in swift. They represent C-style operation without overflow. More
This is not operator overload approach. But the result may be what you are expecting
// Conform to `ExpressibleByIntegerLiteral` and implement it
extension String: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) {
// String has an initializer that takes an Int, we can use that to
// create a string
self = String(value)
}
}
extension Int: ExpressibleByStringLiteral {
public init(stringLiteral value: String) {
self = Int(value) ?? 0
}
}
// No error, s2 is the string "4"
let s1: Int = "1"
let s2: String = 2
print(s1)
print(s2)
print(s1 + 2)

How to use FloatingPoint generic type for Float/Double

I'd like to make the function below work both with Float and Double values:
func srgb2linear(_ S: Float) -> Float {
if S <= 0.04045 {
return S / 12.92
} else {
return pow((S + 0.055) / 1.055, 2.4)
}
}
The Swift 4 Documentation says that what I need is a FloatingPoint generic, to represent both Float and Double classes, like:
func srgb2linear<T: FloatingPoint>(_ S: T) -> T
However when I try to do this, it doesn't compile with the following errors:
Error: binary operator '<=' cannot be applied to operands of type 'T' and 'Double'
Error: binary operator '/' cannot be applied to operands of type 'T' and 'Double'
Error: binary operator '+' cannot be applied to operands of type 'T' and 'Double'
How is it possible that for a generic representing floating point numbers such operators are not implemented? And if not like this, how can I write this function in Swift?
One problem is that FloatingPoint is not a subprotocol of ExpressibleByFloatLiteral, so your floating-point literals cannot necessarily be converted to T. You can solve this either by changing FloatingPoint to BinaryFloatingPoint (which is a subprotocol of ExpressibleByFloatLiteral) or by adding ExpressibleByFloatLiteral as a separate requirement.
Then you will run into the problem that there is no pow function that is generic over FloatingPoint, and no member of FloatingPoint or BinaryFloatingPoint that performs exponentiation. You can solve this by creating a new protocol and conforming the existing floating-point types to it:
protocol Exponentiatable {
func toPower(_ power: Self) -> Self
}
extension Float: Exponentiatable {
func toPower(_ power: Float) -> Float { return pow(self, power) }
}
extension Double: Exponentiatable {
func toPower(_ power: Double) -> Double { return pow(self, power) }
}
extension CGFloat: Exponentiatable {
func toPower(_ power: CGFloat) -> CGFloat { return pow(self, power) }
}
Note that there is also a Float80 type, but the standard library doesn't provide a pow function for it.
Now we can write a working generic function:
func srgb2linear<T: FloatingPoint>(_ S: T) -> T
where T: ExpressibleByFloatLiteral, T: Exponentiatable
{
if S <= 0.04045 {
return S / 12.92
} else {
return ((S + 0.055) / 1.055).toPower(2.4)
}
}
You could define a second one with Double arguments:
func srgb2linear(_ S: Double) -> Double {
if S <= 0.04045 {
return S / 12.92
} else {
return pow((S + 0.055) / 1.055, 2.4)
}
}
or, if Float<->Double conversions are not a concern :
func srgb2linear(_ S: Double) -> Double {
return Double(srgb2linear(Float(S)))
}

Swift block syntax failure to infer type

Can anyone explain why this single line block with an implicit return compiles:
let r = withUnsafePointer(&msg) {
dn_expand(UnsafePointer($0), eomorig: UnsafePointer($0).advancedBy(msg.count), comp_dn: UnsafePointer($0).advancedBy(offset), exp_dn: &buf, length: buf.count)
}
but this version refactored where the only difference is to avoid the multiple calls to UnsafePointer($0) doesn't:
let s = withUnsafePointer(&msg) {
let p = UnsafePointer($0)
return dn_expand(p, eomorig: p.advancedBy(msg.count), comp_dn: p.advancedBy(offset), exp_dn: &buf, length: buf.count)
}
with error message:
Cannot convert value of type 'inout [UInt8]' (aka 'inout Array<UInt8>') to expected argument type 'inout _'
The dn_function being called is just a trivial wrapper around dn_expand from libresolv:
public static func dn_expand(msg: UnsafePointer<UInt8>, eomorig: UnsafePointer<UInt8>, comp_dn: UnsafePointer<UInt8>, exp_dn: UnsafeMutablePointer<CChar>, length: Int) -> Int {
return Int(res_9_dn_expand(msg, eomorig, comp_dn, exp_dn, Int32(length)))
}
As already said in the comments, withUnsafePointer() is not the
correct way to get a pointer to the element storage. It compiles, but
gives unexpected results, as the following example demonstrates:
var msg: [UInt8] = [1, 2, 3, 4]
func foo(x: UnsafePointer<UInt8>) {
print(x[0])
}
withUnsafePointer(&msg) {
foo(UnsafePointer($0))
}
This prints "random" numbers, but not the expected 1. The correct
way is to call the withUnsafeBufferPointer() method on the array:
msg.withUnsafeBufferPointer {
foo($0.baseAddress)
}
In your case that would be
let r = msg.withUnsafeBufferPointer {
dn_expand($0.baseAddress, eomorig: $0.baseAddress + $0.count, ...)
}
Here the return type of the closure is inferred automatically because
it is a "single-expression" closure. If the closure contains more
than one expression, you have to specify its type:
let r = msg.withUnsafeBufferPointer { bufPtr -> Int in
let p = bufPtr.baseAddress
return dn_expand(p, eomorig: p + msg.count, ...)
}
or let the compiler infer the return type from the context:
let r: Int = msg.withUnsafeBufferPointer { bufPtr in
let p = bufPtr.baseAddress
return dn_expand(p, eomorig: p + msg.count, ...)
}

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

I have created a ^^ operator in Swift. How do I make it work with Integers and Doubles like all other operators?
infix operator ^^ { }
func ^^ (number:Int, power: Int) -> Int {
var result = power > 0 ? number : 0
if power > 1 { for x in 1..<power { result *= number } }
return result
}
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.

Generate an integer binary representation using Swift?

How to create a function accepting any type of Int or Uint in swift
(and calculating number of bits needs regarding param type)
String has constructors
init<T : _SignedIntegerType>(_ v: T, radix: Int, uppercase: Bool = default)
init<T : _UnsignedIntegerType>(_ v: T, radix: Int, uppercase: Bool = default)
which can be used here:
let num = 100
let str = String(num, radix: 2)
print(str)
// Output: 1100100
Here's a little shorter version. It doesn't add extra leading zeroes though:
func bitRep<T: IntegerArithmeticType>(value: T) -> String {
var n: IntMax = value.toIntMax()
var rep = ""
while(n > 0){
rep += "\(n % 2)"
n = n / 2;
}
return rep
}
let binStr:Int->String = {a in return String(a, radix: 2)}
binStr(7) // "111"
Here's a function using Generics in order to accept any type of Int or Uint without param conversion needs.
1- The function needs to constraint a value type conforming to "ToInt" protocol
in order to offer an unique method to convert self type to Int
2- The function calculates length bit needs regarding param type
3- The function insert space every 8 digits to offer legibility
protocol ToInt { func toInt() -> Int }
extension UInt: ToInt { func toInt() -> Int { return Int(self) } }
extension Int8: ToInt { func toInt() -> Int { return Int(self) } }
extension UInt8: ToInt { func toInt() -> Int { return Int(self) } }
extension Int16: ToInt { func toInt() -> Int { return Int(self) } }
extension UInt16: ToInt { func toInt() -> Int { return Int(self) } }
extension Int32: ToInt { func toInt() -> Int { return Int(self) } }
extension UInt32: ToInt { func toInt() -> Int { return Int(self) } }
extension Int64: ToInt { func toInt() -> Int { return Int(self) } }
extension UInt64: ToInt { func toInt() -> Int { return Int(self) } }
func bitRep<T:ToInt>(value: T) -> String {
var size: Int
switch value {
case is Int8, is UInt8: size = 7
case is Int16, is UInt16: size = 15
case is Int32, is UInt32: size = 31
case is Int64, is UInt64: size = 63
default : size = 63
}
var n = value.toInt()
var rep = ""
for (var c = size; c >= 0; c--) {
var k = n >> c
if (k & 1) == 1 { rep += "1" } else { rep += "0" }
if c%8 == 0 && c != 0 { rep += " " }
}
return rep
}
Some examples:
let b1: UInt8 = 0b00000000
bitRep(b1)
// > "00000000"
let c1: UInt16 = 0b00000000_10000101
bitRep(c1)
// > "00000000 10000101"
let e1: UInt64 = 0b00000000_00000000_00000000_00000001
bitRep(e1)
// > "00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001"
and so on!
(algo inspired from this thread: Turning an integer to its binary representation using C?)