Created
September 30, 2015 18:54
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (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. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Aahh, I just realized that the float literal problem was very easy to solve:
: )