Cast Cgfloat to Int in Extension Binaryfloatingpoint

Swift: Casting a FloatingPoint conforming value to Double

The problem there is that you need to extend BinaryFloatingPoint instead of FloatingPoint protocol:

extension BinaryFloatingPoint {
// Creates a new instance from the given value if possible otherwise returns nil
var double: Double? { Double(exactly: self) }
// Creates a new instance from the given value, rounded to the closest possible representation.
var doubleValue: Double { .init(self) }
}

Playground testing

let cgFloat: CGFloat = .pi                    // 3.141592653589793

let exactlyDouble = cgFloat.double // 3.141592653589793
let closestDoubleValue = cgFloat.doubleValue // 3.141592653589793

You can also create generic methods to return any floating point type that conforms to the BinaryFloatingPoint protocol:

extension BinaryFloatingPoint {
func floatingPoint<F: BinaryFloatingPoint>() -> F? { F(exactly: self) }
func floatingPointValue<F: BinaryFloatingPoint>() -> F { .init(self) }
}

Playground testing

let float80pi: Float80 = .pi   // 3.1415926535897932385

let closestCGFloatPiValue: CGFloat = float80pi.floatingPointValue() // 3.141592653589793
let closestDoublePiValue: Double = float80pi.floatingPointValue() // 3.141592653589793
let closestFloatPiValue: Float = float80pi.floatingPointValue() // 3.141593

let exactlyCGFloat: CGFloat? = float80pi.floatingPoint() // nil
let exactlyDouble: Double? = float80pi.floatingPoint() // nil
let exactlyFloat: Float? = float80pi.floatingPoint() // nil

Initialising String from a BinaryFloatingPoint protocol

The String init method expects a concrete type.

Use String Interpolation instead

extension Numeric where Self: BinaryFloatingPoint {

var toString: String {
return "\(self)"
}
}

Swift random float between 0 and 1

Try initializing the divisor as a float as well, a la:

CGFloat(Float(arc4random()) / Float(UINT32_MAX))

What is the best way of converting NON-String type to String type in Swift, using initializer vs \()?

No it is not the only way of converting it. You can add another constrain to your generic type requiring it to conform to LosslessStringConvertible as well. Note that all BinaryFloatingPoint types conforms to CustomStringConvertible but not all of them conforms to LosslessStringConvertible (i.e CGFloat).

If you don't care about your method supporting CGFloat you can constrain it LosslessStringConvertible otherwise you need to use CustomStringConvertible's String(describing:) initializer.


This will not support CGFloat

func test<T: BinaryFloatingPoint & LosslessStringConvertible>(value: T) {        
let stringValue = String(value)
print(stringValue)

}

This will support all BinaryFloatingPoint floating point types. Note that you don't need to constrain to CustomStringConvertible. It is only for demonstration purposes.

func test<T: BinaryFloatingPoint & CustomStringConvertible>(value: T) {
let stringValue = String(describing: value)
print(stringValue)
}

You can also make CGFloat conform to LosslessStringConvertible as well:

extension CGFloat: LosslessStringConvertible {
private static let formatter = NumberFormatter()
public init?(_ description: String) {
guard let number = CGFloat.formatter.number(from: description) as? CGFloat else { return nil }
self = number
}
}

This will allow you to support all floating point types with your generic method and use the String initializer as well.

Generic half func in Swift

You write "all numeric types", but based on the 0.5 multiplication this answer is based on the assumption that you refer to the commonly use floating point types (Double, Float, CGFloat).

You could create a custom protocol that blueprints the * function (for multiplying to values of Self) as well as an initializer by FloatLiteralType, and conform Double, Float and CGFloat to this protocol. The * function as well as the initializer are already implemented for these three types, so the conformance is simply explicitly telling the compiler that these types indeed conform to your custom protocol.

E.g.

protocol MyFloatingPointTypes {
func *(lhs: Self, rhs: Self) -> Self
init(_: FloatLiteralType)
}

extension Double : MyFloatingPointTypes {}
extension Float : MyFloatingPointTypes {}
extension CGFloat : MyFloatingPointTypes {}

func half<T: MyFloatingPointTypes>(value: T) -> T {
return value * T(0.5)
}

/* example usage */
var dVal: Double = 10.5
var fVal: Float = 10.5
var cfVal: CGFloat = 10.5

dVal = half(dVal)
fVal = half(fVal)
cfVal = half(cfVal)

print(dVal, fVal, cfVal) // 5.25 5.25 5.25

Alternative: compound protocol constraint, using FloatLiteralConvertible

As @Hamish writes in his comments below, rather than blueprinting the initializer by Double (init(_: FloatLiteralType) in MyFloatingPointTypes, a better approach is to instead add an additional type constraint to the generic half(...) function, constraining the generic (in addition to MyFloatingPointTypes) to FloatLiteralConvertible:

// lets rename this protocol here, since it no longer has any direct association with floats
protocol Multiplicable {
func *(lhs: Self, rhs: Self) -> Self
}

extension Double : Multiplicable {}
extension Float : Multiplicable {}
extension CGFloat : Multiplicable {}

func half<T: protocol<Multiplicable, FloatLiteralConvertible>>(value: T) -> T {
return value * 0.5
}

/* example usage */
// ... same as above

Another (more general) alternative: compound protocol constraint, using IntegerLiteralConvertible

Or, if you want you half function to extend its generic "coverage" also to integer types (as also pointed out by @Hamish, thanks!) you could use the same compound protocol constraint method as above, but against IntegerLiteralConvertible:

protocol Divisable {
func /(lhs: Self, rhs: Self) -> Self
}

extension Double : Divisable {}
extension Float : Divisable {}
extension CGFloat : Divisable {}
extension Int: Divisable {}

func half<T: protocol<Divisable, IntegerLiteralConvertible>>(value: T) -> T {
return value / 2
}

/* example usage */
var dVal: Double = 10.5
var fVal: Float = 10.5
var cfVal: CGFloat = 10.5
var iVal: Int = 11

dVal = half(dVal)
fVal = half(fVal)
cfVal = half(cfVal)
iVal = half(iVal) // truncates decimal part

print(dVal, fVal, cfVal, iVal) // 5.25 5.25 5.25 5

How to use FloatingPoint generic type for Float/Double

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


Related Topics



Leave a reply



Submit