Skip to content

Instantly share code, notes, and snippets.

@jepers
Created September 30, 2015 18:54
Show Gist options
  • Save jepers/bb199222352726796312 to your computer and use it in GitHub Desktop.
Save jepers/bb199222352726796312 to your computer and use it in GitHub Desktop.
An example of creating a generic function/method working for Float and Double
// (Xcode 7.1 beta 2)
// Background:
// I wanted to replace these two overloads with a generic function/method (working for Float and Double):
// func oldRemoveSrgbGamma(v: Float) -> Float {
// return (v <= 0.04045) ? v * (1.0 / 12.92) : pow((v + 0.055) * (1.0 / (1.0 + 0.055)), 2.4)
// }
// func oldRemoveSrgbGamma(v: Double) -> Double {
// return (v <= 0.04045) ? v * (1.0 / 12.92) : pow((v + 0.055) * (1.0 / (1.0 + 0.055)), 2.4)
// }
//
// I would be happy if someone could show me wrong, but this is the amount of code that seems to be necessary:
import Darwin
protocol FloatingPointArithmeticType : FloatLiteralConvertible, Comparable {
@warn_unused_result func +(lhs: Self, rhs: Self) -> Self
@warn_unused_result func -(lhs: Self, rhs: Self) -> Self
@warn_unused_result func *(lhs: Self, rhs: Self) -> Self
@warn_unused_result func /(lhs: Self, rhs: Self) -> Self
@warn_unused_result func %(lhs: Self, rhs: Self) -> Self
@warn_unused_result func toThePowerOf(e: Self) -> Self
}
extension Float : FloatingPointArithmeticType {}
extension Double : FloatingPointArithmeticType {}
extension Float { func toThePowerOf(e: Float) -> Float { return Darwin.pow(self, e) } }
extension Double { func toThePowerOf(e: Double) -> Double { return Darwin.pow(self, e) } }
@warn_unused_result
func pow<T: FloatingPointArithmeticType>(v: T, e: T) -> T { return v.toThePowerOf(e) }
// Here is the generic replacement function (in the form of computed property for FloatingPointArithmetic types),
// I've tested it and verified that it is as fast as the old overloaded version:
extension FloatingPointArithmeticType {
var srgbGammaRemoved : Self {
return self <= 0.04045 ? self * (1.0 / 12.92) : ((self + 0.055) * (1.0 / 1.055)).toThePowerOf(2.4)
// It turns out that this (above) is about 1.3 times faster then the simplified:
// return self <= 0.04045 ? self / 12.92 : ((self + 0.055) / 1.055).toThePowerOf(2.4)
// Because the latter has a division instead of the former's multiplication with a constant.
// So, for the sake of the argument, let's say I wanted to break out those constants like this:
// let c1 = Self(1.0 / 12.92)
// let c2 = Self(1.0 / 1.055)
// That will not work, and I will get "Error: Missing argument label 'floatLiteral' in call".
// I've tried various ways of resolving that but couldn't. So I'm not able to assign literals. : (
}
}
// So, I'm kind of willing to accept the amount of code needed to do this since adding other functions besides
// srgbGammaRemoved will not require additional boilerplate. But note that I had to deal specifically with pow
// for each conforming type (Float and Double), as I couldn't find a way similar to how i did the + - * / % operators.
// This is just pow, so I'll have to perform the same special dance for sin, cos, tan, round, floor, etc.
//
// Also, I think this has a somewhat hackish feel to it, I mean for example:
// Presumably, there are good reasons for not having something like FloatingPointArithmeticType in the std lib, no?
//
// And I guess there must be some way to handle the float literal problem mentioned in the comments of srgbGammeRemoved.
//
// Any improvements and/or feedback on this would be much appreciated.
@jepers
Copy link
Author

jepers commented Sep 30, 2015

Aahh, I just realized that the float literal problem was very easy to solve:

extension FloatingPointArithmeticType {
    var srgbGammaRemoved : Self {
        let c1: Self = 1.0 / 12.92
        let c2: Self = 1.0 / 1.055
        return self <= 0.04045 ? self * c1 : ((self + 0.055) * c2).toThePowerOf(2.4)
        //return self <= 0.04045 ? self * (1.0 / 12.92) : ((self + 0.055) * (1.0 / 1.055)).toThePowerOf(2.4)
    }
}

: )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment