Reputation:
If a float is repeatedly multiplied by a number that is less than one, is it plausible that the the float could become zero?
Here is an example:
float number = 1.0f;
for ( int i = 0; i < ONE_BILLION; ++i )
{
number *= 0.01f;
}
But please don't limit your answer to the example.
Thanks!
Upvotes: 2
Views: 639
Reputation: 3274
I'm surprised that so few pointed out the simple fact that when you go below/above the smallest/largest representable (absolute) non-zero/non-infinite value you will get an underflow/overflow exception which will halt execution. This is because it is mathematically incorrect that a non-zero number (for example) multiplied by a another non-zero number could become zero in the same way that it could become infinity simply by passing a certain point in the scale.
Of course you can mask out the exception(s) in the FP control word and accept that your program behaves mathematically incorrect and eventually deliver a zero which you might plug into a division and get another exception.
In my view it is much better to have control over the FP-processing. I have encountered organizations where they've left integer math for fp to "simplify programming" but have ended up with a processing background which they only vaguely understand and so-called "strange" results and exceptions which they definitely don't.
Upvotes: 1
Reputation: 140786
Yes, when the result of the multiplication would be smaller than the representable number closest to zero, it will become zero. With IEEE floating point, this will happen for any multiplier less than or equal to 0.5f
(but greater than zero); however, if the multiplier is even slightly larger than 0.5f
(for instance, 0.5f + FLT_EPSILON
) the result will converge to the smallest representable positive number and stay there forever. Compare the behavior of this program with and without -DGREATER
:
#include <stdio.h>
#include <float.h>
#ifdef GREATER
#define MULTIPLIER (0.5f + FLT_EPSILON)
#else
#define MULTIPLIER 0.5f
#endif
int
main(void)
{
float x = 1.0f;
unsigned int count = 0;
while (x > 0.0f && count < 200)
{
x *= MULTIPLIER;
printf("%g %a\n", x, x);
count++;
}
return 0;
}
Upvotes: 6
Reputation: 91209
Yes. Eventually you'll reach a number less than the smallest representable positive float, which will underflow to zero.
Upvotes: 2
Reputation: 14890
It depends on the multiplied value and on the current rounding mode. Consider this example:
FLT_MIN * 0.99 == FLT_MIN
EDIT: @Pascal: on my computer, this simple example compiled with GCC:
int main(){
float f = 1.0f;
while (f){
printf("%g\n", f);
f *= 0.99f;
};
return 0;
}
converges to 6.93643e-044
, and not to zero.
My point is that if the intermideate calculations are performed with larger precision than the final result (the most common example is x87 80bit internal FP register), and at the end the result is truncated to float
, then you'll get a zero for sure. But if the calculations are peformed on float, then you have no garanty at all that they will converge to zero. Here is some good reading.
For general case, the best (and much faster) solution would be to transform the loop to a simple expression with logarithms:
#include <math.h>
#define COUNT 1000
#define COEFF 0.9f
int main(){
float f = 1.0f;
float f2 = exp(log(f) + COUNT * log(COEFF));
int i;
for (i = 0; i < COUNT; i++)
f *= COEFF;
printf("results for %d iters with %f: LOOP: %g and LOG: %g\n", COUNT, COEFF, f, f2);
return 0;
};
that will output:
results for 1000 iters with 0.900000: LOOP: 5.04467e-045 and LOG: 0
Upvotes: 2
Reputation: 145419
Depends on the implementation. With typical IEEE 754 implementation you'll first get down into denormals (losing precision) and then snap to 0. But some other implementation may give you a floating point underflow error, bang crash.
Cheers & hth.,
Upvotes: 3