I need to round a 64-bit double value to the nearest uint64_t in my code with the standard "math.h" midpoint rounding behaviour. Some of these numbers have the property:
I noticed there is no 'unsigned' version of the standard library rounding functions. Also, I suspect some of the tricks people use to do this no longer work when an intermediate double value is too large to fit into the mantissa.
What is the best way to do this conversion?
I would use std::round
and then clamp to uint64 range. Also you need to decide what to do with NaN.
std::round
does not convert to integer. Note that the built-in floating to integer conversion in C & C++ is truncating and undefined for out of range values.
std::round
implements the standard "school" type rounding to the nearest integer with the midpoint cases being rounded outwards (e.g. round(1.5) == 2; round(-1.5) = -2
).
The current rounding mode is ignored, also this is not the IEEE754 rounding to nearest. The latter would use round half to even
and round the tie breaking cases up and down to reduce statistical bias.
For long long
one would do something like this.
double iv = std::round(val);
if (std::isnan(iv)) {
return 0LL;
} else if (iv > LLONG_MAX)
return LLONG_MAX;
} else if (iv < LLONG_MIN) {
return LLONG_MIN;
} else {
return (long long)iv;
}
The unsigned long long
case is done correspondingly.
double iv = std::round(val);
if (std::isnan(iv)) {
return 0ULL;
} else if (iv > ULLONG_MAX) // ok, if you know your values are less this can be spared of course
return ULLONG_MAX;
} else if (iv < 0) {
return 0ULL;
} else {
return (unsigned long long)iv;
}
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