How to count the length of the digits after the dot in a double / float?
Without std::string.
So the length after the dot of 1234.5678 is 4.
And how should you correctly use epsilon in such a situation?
I have something like this, one version with epsilon and another without, neither work fully.
// Version 1.
template <typename T> inline constexpr
unsigned int get_length(T x, const bool& include_dot = false) {
unsigned int len = 0;
x = abs(x);
auto c = x - floor(x);
T factor = 10;
T eps = epsilon() * c;
while (c > eps && c < 1 - eps) {
c = x * factor;
c = c - floor(c);
factor *= 10;
eps = epsilon() * x * factor;
++len;
}
if (include_dot && len > 0) { ++len; }
return len;
}
// Version 2.
template <typename T> inline constexpr
unsigned int get_length(const T& x, const bool& include_dot = false, const unsigned int& max_consequtive_zeros = 6) {
unsigned int len = 0;
unsigned int zero_count = 0;
short digit;
auto decimals = get_decimals(x);
while (decimals != 0 && len < 14) {
decimals *= 10;
digit = decimals;
if (digit == 0) {
if (zero_count >= max_consequtive_zeros) { break; }
++zero_count;
}
else { zero_count = 0; }
decimals -= digit;
++len;
// std::cout << len << ": " << decimals << " zeros: " << zero_count << "\n";
}
if (include_dot && len > 0) { ++len; }
return len - zero_count;
}
A floating point number doesn't store a value in decimal format. It stores it in binary.
For example, if you try to store
234.56in a float, the closest value that can actually be stored is:234.559997558593751234.5678is1234.5677490234375(go play with https://www.h-schmidt.net/FloatConverter/IEEE754.html to see for yourself)
As such, the length (in decimal digits) of a number in a float is ill-defined. To keep your sanity, please define an epsilon based on the magnitude, not on the number of digits.