0

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.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
ty_1917
  • 151
  • 3
  • 2
    "I tried to all" A good scientist shows *all* of his work. – Jeff Holt Dec 11 '22 at 20:24
  • 1
    Casting floating point to integer rounds down. Use `round` function explicitly. – hyde Dec 11 '22 at 20:25
  • Floating point numbers are stored in a binary format. 1.8 and .3 are both repeating fractions in binary (1.11001100... and .0100110011..., respectively) and so lose precision being stored slightly less than the wanted decimal value. – Mark Tolonen Dec 11 '22 at 20:26
  • 2
    Do the rounding first, then cast to uint16_t – Robert Harvey Dec 11 '22 at 20:32
  • `float x = 1.8;` gave you 1.7999999523162841796875. And then adding 0.3 (which is really 0.300000011920928955078125) gave you 2.099999904632568359375. And then multiplying that by 100, and throwing away the fraction, gave you 209. Try `printf(%.20f\n", x);` – Steve Summit Dec 11 '22 at 20:40

3 Answers3

1

Floating point numbers are not exact, when you add 1.8 + 0.3, the FPU might generate a slightly different result from the expected 2.1 (by margin smaller then float Epsilon) read more about floating-point numbers representation in wiki https://en.wikipedia.org/wiki/Machine_epsilon

what happens to you is:

1.8 + 0.3 = 209.09999999... then you truncate it to int resulting in 209

you might find this question also relevant to you Why float.Epsilon and not zero? might be

Tomer W
  • 3,395
  • 2
  • 29
  • 44
1

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.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
0
#include<stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main() 
{
    float x = 1.8;

    x = x + 0.3;

    uint16_t coefficient = 100;

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

    uint16_t y = round(x * coefficient);

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

    return 0;
}
picchiolu
  • 1,120
  • 5
  • 20