// value will always be in the range of [0.0 - maximum]
float obtainRatio(float value, float maximum){
if(maximum != 0.f){
return value / maximum;
}else{
return 0.f;
}
}
The range of maximum
can be anything, including negative numbers. The range of value
can also be anything, though the function is only required to make "sense" when the input is in the range of [0.0 - maximum]
. The output should always be in the range of [0.0 - 1.0]
I have two questions that I'm wondering about, with this:
Here is a late answer clarifying some concepts in relation to the question:
In floating-point, division by zero is not a fatal error like integer division by zero is.
Since you know that value
is between 0.0
and maximum
, the only division by zero that can occur is 0.0 / 0.0
, which is defined as producing NaN
. The floating-point value NaN
is a perfectly acceptable value for function obtainRatio
to return, and is in fact a much better exceptional value to return than 0.0
, as your proposed version is returning.
There is nothing approximate about the definition of <=
between floats. a <= b
does not sometimes evaluate to true when a
is just a little above b
. If a
and b
are two finite float
variables, a <= b
evaluate to true exactly when the rational represented by a
is less than or equal to the rational represented by b
. The only little glitch one may perceive is actually not a glitch but a strict interpretation of the rule above: +0.0 <= -0.0
evaluates to true, because “the rational represented by +0.0
” and “the rational represented by -0.0
” are both 0.
Similarly, there is nothing approximate about ==
between floats: two finite float
variables a
and b
make a == b
true if and only if the rational represented by a
and the rational represented by b
are the same.
Within a if (f != 0.0)
condition, the value of f
cannot be a representation of zero, and thus a division by f
cannot be a division by zero. The division can still overflow. In the particular case of value / maximum
, there cannot be an overflow because your function requires 0 ≤ value ≤ maximum
. And we don't need to wonder whether ≤
in the precondition means the relation between rationals or the relation between floats, since the two are essentially the same.
C99 allows extra precision for floating-point expressions, which has been in the past wrongly interpreted by compiler makers as a license to make floating-point behavior erratic (to the point that the program if (m != 0.) { if (m == 0.) printf("oh"); }
could be expected to print “oh” in some circumstances).
In reality, a C99 compiler that offers IEEE 754 floating-point and defines FLT_EVAL_METHOD
to a nonnegative value cannot change the value of m
after it has been tested. The variable m
was set to a value representable as float when it was last assigned, and that value either is a representation of 0 or it isn't. Only operations and constants can have excess precision (See the C99 standard, 5.2.4.2.2:8).
In the case of GCC, recent versions do what is proper with -fexcess-precision=standard
, implied by -std=c99
.
David Monniaux's description of the sad state of floating-point in C a few years ago (first version published in 2007). David's report does not try to interpret the C99 standard but describes the reality of floating-point computation in C as it was then, with real examples. The situation has much improved since, thanks to improved standard-compliance in compilers that care and thanks to the SSE2 instruction set that renders the entire issue moot.
The 2008 mailing list post by Joseph S. Myers describing the then current GCC situation with floats in GCC (bad), how he interpreted the standard (good) and how he was implementing his interpretation in GCC (GOOD).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With