Should conditional compilation be used to deal with the difference in CGFloat across architectures?

Answering this earlier question about how to use ceil() in CGFloat to compile for all architectures, I suggested a solution on 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 

(Initial information for those who are already confused: CGFloat is a type of โ€œfloatโ€ for 32-bit architecture, โ€œdoubleโ€ for 64-bit architecture (that is, the purpose of compilation), so just using either ceil() or ceilf() it will not always compile on it depending on the target architecture. And note that you cannot CGFLOAT_IS_DOUBLE to use CGFLOAT_IS_DOUBLE for conditional compilation, only architecture flags ...)

Now this has caused some controversy in the comments about fixing things at compile time compared to runtime, etc. My answer was adopted too quickly to attract what might be a good thing to do about this, I think.

So my new question is: is this a safe and smart thing if you want your iOS and OS X code to work on 32-bit and 64-bit devices? And if this is reasonable and reasonable, is there an even better (at least as effective, and not as a "bad") solution?

+5
swift
Jun 12
source share
3 answers

Matte

Based on your decision, and if you use it in several places, then a small extension can make it more acceptable:

 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 
+3
Jun 12 '14 at 16:39
source share
  var f : CGFloat = 0.5 var result : CGFloat result = CGFloat(ceil(Double(f))) 

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

+2
Jun 12 '14 at
source share

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

Ceil is an arithmetic operation, and just like any other arithmetic operation, there must be an overloaded version for 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 + overloaded and works for both types.

Unfortunately, pulling the math functions from the C library, which does not support function overloading, we leave two functions instead of one - Ceil and ceilf .

I think the best solution is Ceil overload for Float types:

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

Lets us 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 as for Float and Double , even handling CGFloat will be much easier.

To reply to a comment:

Depending on the architecture of the target processor, CGFloat may be defined as Float or Double . This means that we must use Ceil or ceilf depending on the target architecture.

 var cgFloat: CGFloat = 1.5 //on 64bit it a Double var rounded: CGFloat = ceil(cgFloat) //on 32bit it a Float var rounded: CGFloat = ceilf(cgFloat) 

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

Another option is to use smart tricks.

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

(discarding Double first and then outputting the result to CGFloat )

However, when we work with numbers, we want mathematical 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 reload Ceil for Float as shown above, we can do

 var cgFloat: CGFloat = 1.5 // this works on both 32 and 64bit architectures! var rounded: CGFloat = ceil(cgFloat) 
+1
Jun 12 '14 at 14:23
source share



All Articles