I know UIKit
uses CGFloat
because of the resolution independent coordinate system.
But every time I want to check if for example frame.origin.x
is 0
it makes me feel sick:
if (theView.frame.origin.x == 0) {
// do important operation
}
Isn't CGFloat
vulnerable to false positives when comparing with ==
, <=
, >=
, <
, >
?
It is a floating point and they have unprecision problems: 0.0000000000041
for example.
Is Objective-C
handling this internally when comparing or can it happen that a origin.x
which reads as zero does not compare to 0
as true?
You can use such code for compare float with zero:
This will compare with 0.1 accuracy, that enough for CGFloat in this case.
Since 0 is exactly representable as an IEEE754 floating-point number (or using any other implementation of f-p numbers I've ever worked with) comparison with 0 is probably safe. You might get bitten, however, if your program computes a value (such as
theView.frame.origin.x
) which you have reason to believe ought to be 0 but which your computation cannot guarantee to be 0.To clarify a little, a computation such as :
will (unless your language or system is broken) create a value such that (areal==0.0) returns true but another computation such as
may not.
If you can assure yourself that your computations produce values which are 0 (and not just that they produce values which ought to be 0) then you can go ahead and compare f-p values with 0. If you can't assure yourself to the required degree, best stick to the usual approach of 'toleranced equality'.
In the worst cases the careless comparison of f-p values can be extremely dangerous: think avionics, weapons-guidance, power-plant operations, vehicle navigation, almost any application in which computation meets the real world.
For Angry Birds, not so dangerous.
[The 'right answer' glosses over selecting
K
. SelectingK
ends up being just as ad-hoc as selectingVISIBLE_SHIFT
but selectingK
is less obvious because unlikeVISIBLE_SHIFT
it is not grounded on any display property. Thus pick your poison - selectK
or selectVISIBLE_SHIFT
. This answer advocates selectingVISIBLE_SHIFT
and then demonstrates the difficulty in selectingK
]Precisely because of round errors, you should not use comparison of 'exact' values for logical operations. In your specific case of a position on a visual display, it can't possibly matter if the position is 0.0 or 0.0000000003 - the difference is invisible to the eye. So your logic should be something like:
However, in the end, 'invisible to the eye' will depend on your display properties. If you can upper bound the display (you should be able to); then choose
VISIBLE_SHIFT
to be a fraction of that upper bound.Now, the 'right answer' rests upon
K
so let's explore pickingK
. The 'right answer' above says:So we need
K
. If gettingK
is more difficult, less intuitive than selecting myVISIBLE_SHIFT
then you'll decide what works for you. To findK
we are going to write a test program that looks at a bunch ofK
values so we can see how it behaves. Ought to be obvious how to chooseK
, if the 'right answer' is usable. No?We are going to use, as the 'right answer' details:
Let's just try all values of K:
Ah, so K should be 1e16 or larger if I want 1e-13 to be 'zero'.
So, I'd say you have two options:
K
.