Matt Gibson
Matt Gibson

Reputation: 38238

Should conditional compilation be used to cope with difference in CGFloat on different architectures?

In answering this earlier question about getting a use of ceil() on a CGFloat to compile for all architectures, I suggested a solution along these lines:

    var x = CGFloat(0.5)

    var result: CGFloat

    #if arch(x86_64) || arch(arm64)
        result = ceil(x)
    #else
        result = ceilf(x)
    #endif

    // use result

(Background info for those already confused: CGFloat is a "float" type for 32-bit architecture, "double" for 64-bit architecture (i.e. the compilation target), which is why just using either of ceil() or ceilf() on it won't always compile, depending on the target architecture. And note that you don't seem to be able to use CGFLOAT_IS_DOUBLE for conditional compilation, only the architecture flags...)

Now, that's attracted some debate in the comments about fixing things at compile time versus run time, and so forth. My answer was accepted too fast to attract what might be some good debate about this, I think.

So, my new question: is the above a safe, and sensible thing to do, if you want your iOS and OS X code to run on 32- and 64-bit devices? And if it is sane and sensible, is there still a better (at least as efficient, not as "icky") solution?

Upvotes: 6

Views: 1057

Answers (3)

Sulthan
Sulthan

Reputation: 130162

Note that with current version of Swift the solution below is already implemented in the standard library and all mathematical functions are properly overloaded for Double, Float and CGFloat.

Ceil is an arithmetic operation and in the same way as any other arithmetic operation, there should be an overloaded version for both Double and Float.

var f1: Float = 1.0
var f2: Float = 2.0

var d1: Double = 1.0
var d2: Double = 2.0

var f = f1 + f2
var d = d1 + d2

This works because + is overloaded and works for both types.

Unfortunately, by pulling the math functions from the C library which doesn't support function overloading, we are left with two functions instead of one - ceil and ceilf.

I think the best solution is to overload ceil for Float types:

func ceil(f: CFloat) -> CFloat {
    return ceilf(f)
}

Allowing us to do:

var f: Float = 0.5
var d: Double = 0.5

var f: Float = ceil(f)
var d: Double = ceil(d)

Once we have the same operations defined for both Float and Double, even CGFloat handling will be much simpler.

To answer the comment:

Depending on target processor architecture, CGFloat can be defined either as Float or a Double. That means we should use ceil or ceilf depending on target architecture.

var cgFloat: CGFloat = 1.5

//on 64bit it's a Double
var rounded: CGFloat = ceil(cgFloat)

//on 32bit it's a Float
var rounded: CGFloat = ceilf(cgFloat)

However, we would have to use the ugly #if.

Another option is to use clever casts

var cgFloat: CGFloat = 1.5
var rounded: CGFloat = CGFloat(ceil(Double(cgFloat))

(casting first to Double, then casting the result to CGFloat)

However, when we are working with numbers, we want math functions to be transparent.

var cgFloat1: CGFloat = 1.5
var cgFloat2: CGFloat = 2.5

// this works on both 32 and 64bit architectures!
var sum: CGFloat = cgFloat1 + cgFloat 2

If we overload ceil for Float as shown above, we are able to do

var cgFloat: CGFloat = 1.5

// this works on both 32 and 64bit architectures!
var rounded: CGFloat = ceil(cgFloat)

Upvotes: 1

Jean Le Moignan
Jean Le Moignan

Reputation: 22236

Matt,

Building on your solution, and if you use it in several places, then a little extension might make it more palatable:

extension CGFloat {
    var ceil: CGFloat {
        #if arch(x86_64) || arch(arm64)
            return ceil(x)
        #else
            return ceilf(x)
        #endif
    }
}

The rest of the code will be cleaner:

var x = CGFloat(0.5)
x.ceil

Upvotes: 3

matt
matt

Reputation: 535889

    var f : CGFloat = 0.5
    var result : CGFloat
    result = CGFloat(ceil(Double(f)))

Tell me what I'm missing, but that seems pretty simple to me.

Upvotes: 2

Related Questions