0

It seems that I'm missing something fundamental in casting and I don't know what it is!

check this code:

int main(void)
{

    float current_i;
    float floating_part;
    int float_to_int_part;

    current_i=13;

    printf("----------------- current_i = %f ------------------\n",current_i);
    current_i=current_i/10;
    printf("new current_i = %f \n",current_i);

    floating_part = (current_i-(int)current_i);
    printf("floating_part = %f\n",floating_part);

    float_to_int_part= (int)(floating_part * 10.0); //i have a problem unserstanding where i went wrong here
    printf("float_to_int_part = %d\n",float_to_int_part);

    return 0;
}

the output here is

----------------- current_i = 13.000000 ------------------
new current_i = 1.300000 
floating_part = 0.300000
float_to_int_part = 2

I expected float_to_int_part to be 3 but the output is always 2 which is very confusing. the fact that I don't know why means I'm missing something very basic which could mean I'm missing more basic facts. if someone could tell me what is wrong with my code and suggest a book or a link (that you think will help) to fill this gap.

It's more important for me to know what caused the error. if all my variables are float then the output is correct and my module works.

Anas Khedr
  • 41
  • 4

2 Answers2

2

13F / 10 cannot be represented precisely with binary encoded float variables.

If you try and print more decimals, you will see what happens:

#include <stdio.h>

int main(void) {
    float current_i;
    float floating_part;
    int float_to_int_part;

    current_i = 13;

    printf("current_i = %.16f\n", current_i);
    current_i = current_i / 10;
    printf("new current_i = %.16f\n", current_i);

    floating_part = (current_i - (int)current_i);
    printf("floating_part = %.16f\n", floating_part);

    float_to_int_part = (int)(floating_part * 10.0);
    printf("float_to_int_part = %d\n", float_to_int_part);

    return 0;
}

Output:

current_i = 13.0000000000000000
new current_i = 1.2999999523162842
floating_part = 0.2999999523162842
float_to_int_part = 2

Note also that float values are converted to double when passed to printf, and the expression (int)(floating_part * 10.0) is evaluated using double arithmetics because 10.0 is a double constant. These values would not be represented precisely as double either, but converting float to double makes the imprecision much more visible and the approximation for the float representation is smaller than the actual value 1.3 whereas with double type, the representation is slightly larger, so the final conversion produces the expected value:

#include <stdio.h>

int main(void) {
    double current_i;
    double floating_part;
    int float_to_int_part;

    current_i = 13;

    printf("current_i = %.23f\n", current_i);
    current_i = current_i / 10;
    printf("new current_i = %.23f \n", current_i);

    floating_part = (current_i - (int)current_i);
    printf("floating_part = %.23f\n", floating_part);

    float_to_int_part = (int)(floating_part * 10.0);
    printf("float_to_int_part = %d\n", float_to_int_part);

    return 0;
}

Output:

current_i = 13.00000000000000000000000
new current_i = 1.30000000000000004440892
floating_part = 0.30000000000000004440892
float_to_int_part = 3

For these computations to be evaluated reliably, you would need to use a decimal based representation for floating point values. The C Standard does not specify such types by default but as an extension described in a Technical Report . Types _Decimal32, _Decimal64 and _Decimal128 might be available on your system (for example gcc supports them on selected targets).

chqrlie
  • 131,814
  • 10
  • 121
  • 189
-2

This answer is not a proper solution, and I do not know if one exists. As said below, this is a "band-aid" solution, as double precision does not mean it will fix the issue in all cases (it only happened to 'fix' it in this one)

Try with double instead of float. And see this as bolov stated.

It works here

You also do not need the (int) cast as it is implicit when you declare float_to_int_part as int

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Mini
  • 445
  • 5
  • 17
  • I would appreciate any pointers as to where my answer was wrong. I don't want to be giving false information! `double` has "double" the precision and it works for OP's question. – Mini Apr 22 '19 at 00:22
  • Converting to Double increases the precision, making rounding errors less likely, but it isn't a good general solution. Better to round the float rather than truncating. – Duncan C Apr 22 '19 at 00:32