In both OS X and iOS, Apple is using the CGFloat typedef to automatically get a float on 32-bit systems and a double on 64-bit systems. But when using the normal Unix math functions you need to make that decision on a case by case basis.
For example the floor() function is defined as:
double floor(double x);
and the floorf() function is defines as:
float floorf(float x);
I know all iOS devices are 32-bit today, but the reason to use CGFloat is to automatically get improved precision when the first 64-bit iOS devices are introduced (iPad 5?) and not having to change any code. But to make that possible we need CGFloat-based math functions:
CGFloat Floor(CGFloat x);
Are there any functions like that in iOS or any third-party libraries? Or how do other developers handle this? I suspect most are either using CGFloat together with the float-versions on iOS but then you would "need" to change every line with a math function if compiling for a 64-bit iOS device (and handle two different versions of of your code base).
Or you could just use float instead of CGFloat everywhere and not worrying about 64-bit iOS. But then you would get inconsistency with Apple's libraries and IMHO uglier code.
Or you could maybe use CGFloat together with the double-versions and just take the space and performance hit of letting the compiler convert between double and float all the time. And not caring about possible "Implicit conversion to 32 Bit Type" warnings.
Or maybe the best strategy, bet on no 64-bit version of iOS will ever arrive (or at least in a near enough future) and use CGFloat together with float-versions of the Unix math functions and not worrying about the future.
What strategy are you using?
Edit: So this question is no longer theoretical now that we have 64-bit iOS!
I think the easiest way to deal with this is to use tgmath.h, instead of math.h (math.h gets imported by Cocoa automatically, tgmath doesn't so you'll need to declare it somewhere).
There are a number of potential solutions discussed at the Cocoa mailing list thread:
http://www.cocoabuilder.com/archive/cocoa/291802-math-functions-with-cgfloat.html
I would agree with the majority of people on that list that tgmath is probably the way to go. I believe it was originally intended to allow easy porting of Fortran code, but it also works in this scenario. TGMath will let you do:
double floor(double x);
float floor(float x);
long double floor(long double x);
Related
Which type of float am I supposed to use for vertex data? There are a bunch to choose from. Glfloat, float, float32, etc.
iOS GPU hardware works best with single-precision floating point data. Moreover, many of the higher level libraries (e.g. GLKit, SceneKit) use data structures containing 32-bit floats for vectors, matrices, and the like.
As for which type name to use, remember that Swift doesn't do automatic type conversion. So where in C you could get away with using float values in your code and passing them to OpenGL APIs, in Swift you'd have to implicitly convert them to the type(s) used by the API (with GLfloat(value)). It's probably best to just use GLfloat for your own data so you don't have to insert that conversion.
Even if you're developing only for Apple platforms (since you're using Swift), using GLfloat also ensures that you're using whatever data type is required by the OpenGL specification — if you use another type name that happens to specify the same data size/format today, you're relying on that name happening to mean the same thing in the future. (Granted, these particular Swift data types don't seem all that likely to change, but in general it's best to rely on an explicit API contract rather than an implicit match.)
For OpenGL, you should use the OpenGL data types - GLfloat in this case, as they are guaranteed to be the correct types used by the the GL implementation on every platform. In practice, a GLfloat will be a 32 bit single precision floating point format in virtually all cases.
Question
Consider layout code like this:
CGFloat descriptionHeight = // height of a paragraph of text with zero or more words;
CGFloat imageHeight = // height of an image;
CGFloat yCoordinateOfSomeOtherView = fmax(descriptionHeight, imageHeight) + 5.0f;
How should the third line be rewritten with support for 64-bit iOS devices?
(The current code doesn't take into account whether yCoordinateOfSomeOtherView is a float or a double.)
Options
A few options (I'm not sure which is best):
1. Define my own macro
#if defined(__LP64__) && __LP64__
#define cgfmax(x,y) fmaxf(x,y)
#else
#define cgfmax(x,y) fmax(x,y)
#endif
I could then replace fmax with cgfmax.
2. Use tgmath.h
This Stack Overflow answer from 2011 suggests replacing math.h with tgmath.h. This replaces the implementation of fmax with one that calls __typeof__ on each argument and returns either fmax or fmaxf depending on the argument types.
3. Ignore this issue
Since CGFloats relate to layout, the data loss potentially incurred storing a float into a double will usually be insignificant. That is, they'll represent tiny fractions of pixels.
Summary
I'm looking for any other options or helpful advice from someone who's done a 32-bit to 64-bit transition before.
There is never any "data loss" incurred when converting a float into a double. That conversion is always exact.
Your solutions 1 & 2 are entirely equivalent semantically, though (2) is more stylistically correct.
Your solution 3 is formally not equivalent; it may incur extra conversions between float and double, which may make it slightly less efficient (but the actual result is identical).
Basically, it doesn't matter, but use tgmath.
I need to vectorize with SSE a some huge loops in a program. In order to save time I decided to let ICC deal with it. For that purpose, I prepare properly the data, taking into account the alignment and I make use of the compiler directives #pragma simd, #pragma aligned, #pragma ivdep. When compiling with the several -vec-report options, compiler tells me that loops were vectorized. A quick look to the assembly generated by the compiler seems to confirm that, since you can find there plenty of vectorial instructions that works with packed single precision operands (all operations in the serial code handler float operands).
The problem is that when I take hardware counters with PAPI the number of FP operations I get (PAPI_FP_INS and PAPI_FP_OPS) is pretty the same in the auto-vectorized code and the original one, when one would expect to be significantly less in the auto-vectorized code. What's more, a vectorized by-hand a simplified problem of the one that concerns and in this case I do get something like 3 times less of FP operations.
Has anyone experienced something similar with this?
Spills may destroy the advantage of vectorization, thus 64-bit mode may gain significantly over 32-bit mode. Also, icc may version a loop and you may be hitting a scalar version even though there is a vector version present. icc versions issued in the last year or 2 have fixed some problems in this area.
Apple CoreGraphics.framework, CGGeometry.h:
CG_INLINE bool __CGSizeEqualToSize(CGSize size1, CGSize size2)
{
return size1.width == size2.width && size1.height == size2.height;
}
#define CGSizeEqualToSize __CGSizeEqualToSize
Why do they (Apple) compare floats with ==? I can't believe this is a mistake. So can you explain me?
(I've expected something like fabs(size1.width - size2.width) < 0.001).
Floating point comparisons are native width on all OSX and iOS architectures.
For float, that comes to:
i386, x86_64:
32 bit XMM register (or memory for second operand)
using an instructions in the family of ucomiss
ARM:
32 bit register
using instructions in the same family as vcmp
Some of the floating point comparison issues have been removed by restricting storage to 32/64 for these types. Other platforms may use the native 80 bit FPU often (example). On OS X, SSE instructions are favored, and they use natural widths. So, that reduces many of the floating point comparison issues.
But there is still room for error, or times when you will favor approximation. One hidden detail about CGGeometry types' values is that they may be rounded to a nearby integer (you may want to do this yourself in some cases).
Given the range of CGFloat (float or double-x86_64) and typical values, it's reasonable to assume the rounded values generally be represented accurately enough, such that the results will be suitably comparable in the majority of cases. Therefore, it's "pretty safe", "pretty accurate", and "pretty fast" within those confines.
There are still times when you may prefer approximated comparisons in geometry calculations, but apple's implementation is what I'd consider the closest to a reference implementation for the general purpose solution in this context.
The TMS320C55x has a 17-bit MAC unit and a 40-bit accumulator. Why the non-power-of-2-width units?
The 40-bit accumulator is common in a few TI DSPs. The idea is basically that you can accumulate up to 256 arbitrary 32-bit products without overflow. (vs. in C where if you take a 32-bit product, you can overflow fairly quickly unless you resort to using 64-bit integers.)
The only way you access these features is by assembly code or special compiler intrinsics. If you use regular C/C++ code, the accumulator is invisible. You can't get a pointer to it.
So there's not any real need to adhere to a power-of-2 scheme. DSP cores have been fairly optimized for power/performance tradeoffs.
I may be talking through my hat here, but I'd expect to see the 17-bit stuff used to avoid the need for a separate carry bit when adding/subtracting 16-bit samples.