Question

Is there a clever expression trick to test if a float vec3 is axial (i.e. two zero components) without using multiple equality tests?

At first I thought of if(abs(x)+abs(y)==0.0) (pseudocode)... but of course each abs call probably does a branch/equality test.

I thought of masking each float's bytes together and testing the result, but IEEE FP has both positive and negative 0.

Was it helpful?

Solution

No, there is not a clever way to test whether two of three IEEE-754 binary floating-point values are zero without multiple comparisons to zero.

The desired result is true iff at least two of the following are true:

  • All bits of x except the sign bit are zero.
  • All bits of y except the sign bit are zero.
  • All bits of z except the sign bit are zero.

Before the “All bits” criteria are evaluated, no bitwise operations can assist evaluation of this. Any bitwise operation that loses the relationships between bits in the same value is useless. Essentially, you need to know each of the above items separately. But each of the above items is equivalent to a floating-point comparison to zero.

You could consider a mathematical approach instead of bitwise: (|x|+|y|)•(|y|+|z|)•(|z|+|x|) is, mathematically, zero iff at least two of x, y and z are zero. Taking the absolute value does not require a comparison; it can be achieved by clearing the sign bit. So the above can be implemented as three bit-clear operations (and, on some machines, transfers from floating-point registers to general registers and back), three floating-point additions, two multiplications, and one comparison. However, the multiplications may underflow (producing zero even though the exact mathematical result is not zero) or overflow (which is a problem when the first multiplication produces infinity and causes the second multiplication to produce NaN when zero is needed).

Comparisons are not expensive on common modern processors, and you generally should not worry about avoiding them. Branches can be expensive, although you might not notice this is routine code. If a branch is proving to be troublesome in your application, there may be processor-specific ways to mitigate the issue. There may be machine instructions that allow you to obtain the results of comparisons as values you can perform logical operations on, and then you would need only one branch instruction. This is not an optimization you should perform unless you have specifically determined that the branches are a significant problem in your application.

OTHER TIPS

Eric Postpischil rightly shot a hole in the code I posted; it checked whether each bit appears in at most one of the three arguments. Unfortunately, I can't think of a nice way to solve your problem.

Floating-point absolute value can (ignoring NaNs) be implemented by masking off the sign bit, though, so you might be able to work with that. Also, comparisons like == can compile to a conditional move rather than something branchy.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top