1

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;
}
  • *neither work fully* -- And they will never work fully. Floating point numbers are stored as binary. -- *Without std::string* -- So did you get this assignment from a teacher, or did you make this up yourself? – PaulMcKenzie Aug 02 '22 at 01:45
  • Use of epsilon is irrelevant for this. `1234.5678` has an infinite representation in base 2 (same reason that 1/3 cannot be represented in a finite number of decimal places, except that floating point [usually] works in base 2, not 10). So your code is correct in not producing `4`. More usual practice (e.g. to compute the length of a string for output to a user in a textbox) is to impose an upper bound (e.g. if your code produces 13, limit it to 4). Catch is, choice of upper bound depends on needs of your application. (Which is why I/O formatting usually specifies/assumes a number of digits) – Peter Aug 02 '22 at 02:53
  • user34534857, All finite `double` have [exact](https://codereview.stackexchange.com/q/212490/29485) values when written in decimal. `DBL_MIN` is 0.000 _about 300 more zeros_ 000222 _about 790 more digits_ 625. Let us get to the real issue: _Why_ do you want the _exact_ digit count? – chux - Reinstate Monica Aug 02 '22 at 09:19
  • user34534857 Code `1234.5678` as a `double` has the exact value of 1234.5677490234375. Do you want the number of digits of that `double` ("length of the digits after the dot in a double") or the number of digits of code or the number of digits in a numeric _string_ or what? – chux - Reinstate Monica Aug 02 '22 at 09:28
  • *the length after the dot of `1234.5678` is `4`* No. It is not. It is not, because in binary floating point, **there is no such number as `1234.5678`.** This is hard to think about at first, but until you understand it, computer floating point is going to remain frustrating and difficult. You and I use decimal numbers like 1234.5678. But your binary computer does not. – Steve Summit Aug 02 '22 at 19:11
  • As a `float`, 1234.5678 is not 1234.5678, it is `0x4d2.9158`, or `0b10011010010.1001000101011`, which is equivalent to 1234.5677490234375 in decimal. As a `double`, the real value is `0x4d2.915b573eab4`, which is equivalent to 1234.567800000000033833202905952930450439453125 in decimal. But you will never get an actual, internal, binary value exactly equal to 1234.5678. – Steve Summit Aug 02 '22 at 19:16

1 Answers1

3

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.56 in a float, the closest value that can actually be stored is: 234.55999755859375

1234.5678 is 1234.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.

Jeffrey
  • 11,063
  • 1
  • 21
  • 42