views:

194

answers:

5

If I want to check that positive float A is less than the inverse square of another positive float B (in C99), could something go wrong if B is very small?

I could imagine checking it like

if(A<1/(B*B))

but if B is small enough, would this possibly result in infinity? If that were to happen, would the code still work correctly in all situations?

in a similar vein, I might do

if(1/A>B*B)

Which might be slightly better because B*B might be zero if B is small (is this true?)

Finally, a solution that I can't imagine being wrong is

if(sqrt(1/A)>B)

Which I don't think would ever result in zero division, but still might be problematic if A is close to zero.

So basically, my questions are

Can 1/X ever be infinity if X is greater than zero (but small)?
Can X*X ever be zero if X is greater than zero?
Will comparisons with infinity work the way I would expect them to?

EDIT: for those of you who are wondering, I ended up doing

if(B*A*B<1)

I did it in that order, because it is visually unambiguous which multiplication occurs first.

+3  A: 

You want to avoid divisions so the trick is to modify the equation. You can multiply both sides of your first equation by (b*b) to get:

b*b*a < 1.0

This won't have any divisions so should be ok.

Ben Robbins
Nice! Measure twice, cut once. To asker: if this code is not self-explanatory, then add necessary comments to make this clear.
Hamish Grubijan
Division is somewhat slow, but not toxic. The problem here is that b*b can easily overflow. a*b where a>1 and b<1 is a far better place to start.
Potatoswatter
@Potatoswatter: Assuming IEEE-754 floating point, the overflow is harmless, and this will give the correct answer anyway. Ditto for underflow.
Stephen Canon
@stephen: Not quite… if `a` is denormal then `b*b` may overflow to infinity and throw off the result.
Potatoswatter
@Potatoswatter: ah, didn't catch that this one was `b*b*a` instead of the correct `a*b*b` (which *does* work properly, because multiplication associates left-to-right in C).
Stephen Canon
+4  A: 

OK, reposting as an answer.

Try using arithmetically equivalent comparison like if ( A*B*B < 1. ). You might get in trouble with really big numbers though.

Take a careful look at the IEEE 745 for your corner cases.

Nikolai N Fetissov
This should probably have been accepted as the best answer.
Cam
Actually, as long as he doesn't need to support zero or infinity as values for `a` or `b` (it sounds like he doesn't), then there are no corner case issues; they all fall out correctly.
Stephen Canon
+2  A: 

Granted, this does not exactly answer the question directly, but anybody doing floating point math should read this:
What Every Computer Scientist Should Know About Floating-Point Arithmetic, by David Goldberg, published in the March, 1991 issue of Computing Surveys. Copyright 1991, Association for Computing Machinery, Inc.

Romain Hippeau
This is no more helpful of an answer than the standard links to Wikipedia that people put up. At least give him a pointer to the relevant section.
Stephen Canon
@Stephen arguably this should have been posted as a comment. However it _is_ useful, because the OP demonstrated some lack of knowledge in this area, and the article was linked to because it provides insightful knowledge of which the OP demonstrated some lack.
Cam
@Incrediman: It's unquestionably a *useful* document (a great one, even), but if I responded with a link to the C standard when someone asked a question about operator precedence, would you say the same thing?
Stephen Canon
@Stephen: Let's say they asked a question like 'Why does 3*3+1 evaulate to 10 and not 12?' - then I would, yes. If they asked 'Does the + operator have greater precedence than *?', then I'd downvote you for being obnoxious. The difference is that in the first case, the answer is insightful because it links to a type of documentation the user probably wouldn't know how to find, since they seemed unaware of operator precedence. In the second example the user obviously knows about operator precedence and could have found such documentation if they wanted. Romain's answer is like my first example.
Cam
@Stephen: Ohhh... my bad. I know the article, so I didn't click on the link. I did just now and realized that much of the intro and other sections of the article do not relate directly to the question - so the plain link isn't as helpful as I presumed. The relevant section should either have been linked to/referenced, or a snippet should have been pasted in along with the link. Gave you a +1.
Cam
@incrediman: thanks; it really is a great document, it's just way too encyclopedic to constitute an answer to such a specific question on its own.
Stephen Canon
+4  A: 

If you want to handle the entire range of possible values of A and B, then you need to be a little bit careful, but this really isn't too complicated.

The suggestion of using a*b*b < 1. is a good one; if b is so tiny that a*b*b underflows to zero, then a is necessarily smaller than 1./(b*b). Conversely, if b is so large that a*b*b overflows to infinity, then the condition will (correctly) not be satisfied. (Potatoswatter correctly points out in a comment on another post that this does not work properly if you write it b*b*a, because b*b might overflow to infinity even when the condition should be true, if a happens to be denormal. However, in C, multiplication associates left-to-right, so that is not an issue if you write it a*b*b and your platform adheres to a reasonable numerics model.)

Because you know a priori that a and b are both positive numbers, there is no way for a*b*b to generate a NaN, so you needn't worry about that condition. Overflow and underflow are the only possible misbehaviors, and we have accounted for them already. If you needed to support the case where a or b might be zero or infinity, then you would need to be somewhat more careful.

To answer your direct questions: (answers assume IEEE-754 arithmetic)

Can 1/X ever be infinity if X is greater than zero (but small)?

Yes! If x is a small positive denormal value, then 1/x can overflow and produce infinity. For example, in double precision in the default rounding mode, 1 / 0x1.0p-1024 will overflow.

Can X*X ever be zero if X is greater than zero?

Yes! In double precision in the default rounding mode, all values of x smaller than 0x1.0p-538 (thats 2**-578 in the C99 hex format) or so have this property.

Will comparisons with infinity work the way I would expect them to?

Yes! This is one of the best features of IEEE-754.

Stephen Canon
Thanks! I'll look more into denormal values (not because I'm worried, just interested)
Jeremybub
+1  A: 
Potatoswatter