How to rewrite this code using improved numeric protocols of Swift 4


(Jens Persson) #1

I've made an unsuccessful attempt to rewrite the below code in a shorter,
more generic way using the improved numeric protocols in Swift 4
(BinaryFloatingPoint, FixedWidthInteger et al). So now I'm wondering if
anyone would like to give it a try (or declare that it is not possible).

The following is the code I wish to rewrite. It is for initializing Double
and Float to unit range values (0.0 inclusive to 1.0 exclusive) given a
fixed width unsigned integer, ie mapping the full range of the given
integer [.min, .max] to the floating point unit range [0, 1).

It would be nice if the solution also happened to support signed fixed
width integers and CGFloat, Float80, but only if it doesn't make it more
complicated.
The code has to be fast, so any improvement in speed is also appreciated.

extension Double {
    init(unitRange v: UInt64) {
        let shifts: UInt64 = 63 - UInt64(Double.significandBitCount)
        self = Double(v >> shifts) * (.ulpOfOne/2)
    }
    init(unitRange v: UInt32) {
        self = (Double(v) + 0.5) / (Double(UInt32.max) + 1.0)
    }
    init(unitRange v: UInt16) {
        self = (Double(v) + 0.5) / (Double(UInt16.max) + 1.0)
    }
    init(unitRange v: UInt8) {
        self = (Double(v) + 0.5) / (Double(UInt8.max) + 1.0)
    }
}
extension Float {
    init(unitRange v: UInt64) {
        let shifts: UInt64 = 63 - UInt64(Float.significandBitCount)
        self = Float(v >> shifts) * (.ulpOfOne/2)
    }
    init(unitRange v: UInt32) {
        let shifts: UInt32 = 31 - UInt32(Float.significandBitCount)
        self = Float(v >> shifts) * (.ulpOfOne/2)
    }
    init(unitRange v: UInt16) {
        let a = Float(v) + 0.5
        let b = Float(UInt16.max) + 1.0
        self = a / b
    }
    init(unitRange v: UInt8) {
        let a = Float(v) + 0.5
        let b = Float(UInt8.max) + 1.0
        self = a / b
    }
}