I frequently work with float
or double
types which are in a range of [0, 1]. I am aware that floating point operations are imprecise, so I typically clamp my values so that they are guaranteed to be in this range before/after operations.
In some cases I rely on floats being not even slightly negative and being exactly <= 1
, making this necessary.
For example is it necessary in any of these functions:
// x and y are guaranteed to be in [0, 1]
float avg(float x, float y) {
// the average of [0, 1] values should always be in [0, 1]
return std::clamp<float>((x + y) / 2, 0, 1);
}
float mul(float x, float y) {
// the product of [0, 1] values should always be in [0, 1]
return std::clamp<float>(x * y, 0, 1);
}
float pow(float x, unsigned y) {
// raising an [0, 1] value to any unsigned power should also result in an [0, 1] value
return std::clamp<float>(std::pow(x, y), 0, 1);
}
Are there any consistent rules for when arithmetic operations can make floats leave the [0, 1] range?
Restricting this answer to IEEE754 if I may.
0
, 1
, and 2
can all be represented exactly as a float
. The arithmetic operators are required to return the best floating point value possible. Since x
and y
are neither greater than 1, their sum cannot be greater than 2 since then otherwise there would exist a better float
for the sum. Put another way, the sum of two float
s a little less than 1
cannot be greater than 2
.
The same applies to the product.
The third one requires a clamp since there are no guarantees that std::pow(x, y)
returns the best possible float
.
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