2

I was trying to satisfy this question: Write a function print_dig_float(float f) which prints the value of each digit of a floating point number f. For example, if f is 2345.1234 the print_dig_float(f) will print integer values of digits 2, 3, 4, 5, 1, 2, 3, and 4 in succession.

What I did is: given a number with some decimals, I try to move the digits to the left (Ex: 3.45 -> 345) by multiplying it with 10. After that, I store each digit in an array by taking the remainder and put it in an element. Then, I print them out.

So my program looks like this:

#include <stdio.h>

void print_dig_float(float f);

int main(int argc, char const *argv[]) {

    print_dig_float(23432.214122);

    return 0;
}

void print_dig_float(float f) {

    printf("%f\n", f);

    int i = 0, arr[50], conv;

    //move digits to the left

    do {

        f = f * 10;
        conv = f;
        printf("%i\n", conv);

    } while (conv % 10 != 0);

    conv = f / 10;

    //store digits in an array

    while (conv > 1) {
        arr[i] = conv % 10;
        conv = conv / 10;
        i++;
    }

    for (int j = i - 1; j >= 0; j--) {
        printf("%i ", arr[j]);
    }

    printf("\n");

}

When I tested it with the number: 23432.214122, this is what I get (according to Linux terminal):

23432.214844

234322

2343221

23432216

234322160

2 3 4 3 2 2 1 6

The problem is that, as you can see above, the computer arbitrarily changes the decimal digits at the end of the number even before I do anything with it. I don't know if this is my fault or the computer's fault for this problem.

ks1322
  • 33,961
  • 14
  • 109
  • 164
Xet46
  • 39
  • 3
  • 3
    Does this answer your question? [Why are floating point numbers inaccurate?](https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate) – Irelia Dec 06 '19 at 12:10
  • 1
    Similar question: https://stackoverflow.com/questions/9577179/c-floating-point-precision – user253751 Dec 06 '19 at 12:10
  • 2
    Your first mistake is that no floating point number can equal 2345.1234 or 23432.214122 exactly (assuming the almost universal IEEE 754 binary floating point format is used). – President James K. Polk Dec 06 '19 at 12:19
  • 1
    Or, in other words: it is not arbitrary. – glglgl Dec 06 '19 at 12:34
  • Note that `23432.214122` is type `double` so it *has* to be changed to be assigned to `float`. However, `float` can represent only 6-7 decimal digits of significance. Note the term "represent". Floating point variables trade off range against accuracy. Only about 2^32 distinct values can be *exactly* represented by `float`. – Weather Vane Dec 06 '19 at 13:19

1 Answers1

6

Per C 2018 5.2.4.2.2, a floating-point number is represented with a sign, a fixed base to some exponent, and a numeral formed of digits in that base. Most commonly, two is used as the base.

When the base is two, 23432.214122 cannot be represented in floating-point, because every representable number is necessarily some integer multiple of a power of the base (possible a negative power). 23432.214122 is not a multiple of ½, ¼, ⅛, 1/24, 1/25, or any other power of two.

When 23432.214122 is used in source code, it is converted to a value that is representable. In good C implementations, the nearest representable value is used, but the C standard permits either the representable value that is the nearest larger or nearest smaller value to be used. Other than this, the digits that appear are not arbitrary; they are a consequence of the mathematics.

When IEEE-754 binary32 is used for float, the representable value nearest to 23432.214122 is exactly 23432.21484375.

Because, when a C implementation uses base two for floating-point numbers, floating-point numbers have binary digits and do not have decimal digits. It is generally not meaningful to attempt to extract decimal digits from a thing that does not have decimal digits. It is possible to determine the decimal digits that were in an original numeral up to some limit affected by the floating-point format. However, “23432.214122” has too many digits to do this with a 32-bit floating-point type. With a 64-bit type, as is commonly used for double, you could recover the original digits providing you knew how many decimal digits there were to start with. It is not generally possible to recover the original numeral without that information—as you have seen the trailing digits will be different, and there is no indication in the floating-point number itself of where the differences start.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312