Grimxn
Grimxn

Reputation: 22497

Literal numbers in FloatingPoint protocol

Having not much to do over the holidays, I finally got round to updating my maths library to use the FloatingPoint protocol, and get rid of all the duplicate code. To my surprise, I got bitten pretty much straight away by literal numbers:

func uprightAngle1<T: FloatingPoint>(_ x: T) -> T {
    if (x > 0.5 * T.pi) && (x < 1.5 * T.pi) { // *** ERROR HERE
        // binary operator '*' cannot be applied to operands of type 'Double' and 'T'
        return x - T.pi
    } else {
        return x
    }
}

however, this works fine:

func uprightAngle2<T: FloatingPoint>(_ x: T) -> T {
    if (x > T.pi / 2) && (x < 3 * T.pi / 2) { // All fine here
        return x - T.pi
    } else {
        return x
    }
}

Can anyone

A) explain why the compiler is inferring the type correctly with the integer literals, but not with the floating point literal,

B) show me the idiom to use when I can't use rationals as neither let half: T = 0.5 nor T(0.5) compile...

Upvotes: 2

Views: 147

Answers (1)

Martin R
Martin R

Reputation: 539825

The FloatingPoint protocol inherits from ExpressibleByIntegerLiteral via the inheritance chain

FloatingPoint - SignedNumeric - Numeric - ExpressibleByIntegerLiteral

and that is why the second function uprightAngle2 compiles: Values of the type T are created from the integer literals 2 and 3.

The first function uprightAngle1 does not compile because the FloatingPoint protocol does not inherit from ExpressibleByFloatLiteral, i.e. values of type T can not be created from a floating point literal like 1.5.

Possible solutions:

  • Create rational values as let half: T = 1/2. (Not let half = T(1/2), that would truncate the division result before creating the T value.)

  • Replace FloatingPoint by BinaryFloatingPoint (which inherits from ExpressibleByFloatLiteral).

For more information about the design of the floating point protocols see SE-0067 Enhanced Floating Point Protocols.

The floating point types in the Swift Standard Library (Double, Float, CGFloat, Float80) as well as CGFloat from the Core Graphics framework all conform to the BinaryFloatingPoint protocol, so this protocol is "sufficiently generic" for many applications.

Upvotes: 3

Related Questions