Search code examples
ctypesfloating-pointmultiplication

Problem with float and int multiplication in C


I'm using the online compiler https://www.onlinegdb.com/ and in the following code when I multiply 2.1 with 100 the output becomes 209 instead of 210.

#include<stdio.h>
#include <stdint.h>

int main() 
{
    float x = 1.8;

    x = x + 0.3;

    int coefficient = 100;

    printf("x: %2f\n", x);

    uint16_t y = (uint16_t)(x * coefficient);

    printf("y: %d\n", y);

    return 0;
}

Where am I doing wrong? And what should I do to obtain 210?

I tried to all different type casts still doesn't work.


Solution

  • The following assumes the compiler uses IEEE-754 binary32 and binary64 for float and double, which is overwhelmingly common.

    float x = 1.8;

    Since 1.8 is a double constant, the compiler converts 1.8 to the nearest double value, 1.8000000000000000444089209850062616169452667236328125. Then, to assign it to the float x, it converts that to the nearest float value, 1.7999999523162841796875.

    x = x + 0.3;

    The compiler converts 0.3 to the nearest double value, 0.299999999999999988897769753748434595763683319091796875. Then it adds x and that value using double arithmetic, which produces 2.09999995231628400205181605997495353221893310546875.

    Then, to assign that to x, it converts it to the nearest float value, 2.099999904632568359375.

    uint16_t y = (uint16_t)(x * coefficient);

    Since x is float and coefficient is int, the compiler converts the coefficient to float and performs the multiplication using float arithmetic. This produces 209.9999847412109375.

    Then the conversion to uint16_t truncates the number, producing 209.

    One way to get 210 instead is to use uint16_t y = lroundf(x * coefficient);. (lroundf is declared in <math.h>.) However, to determine what the right way is, you should explain what these numbers are and why you are doing this arithmetic with them.