0

For example if I input 123.45678 I get in output 123 and 0.456779 instead of 0.45678, can anyone explain why is that so? I though it might be something with float data type, but I need a comprehensive explanation, thank you:)

the code:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void decompose(float number, float *decimal, int *whole);

int main()
{
    float number, decimal;
    int whole;

    printf("\n=== Float Decomposition ===\n\n");


    printf("Enter the number you would like to decompose: ");
    scanf("%f",&number);

    printf("\n");

    decompose(number, &decimal, &whole);

    printf("The whole part of your number is: \n");

    printf("%d\n",whole);

    printf("fractional part: \n");

    printf("%f\n",decimal);
    return EXIT_SUCCESS;
}

void decompose(float number, float *decimal, int *whole){
    *decimal = number - trunc(number);
    *whole = number - *decimal;

    return;
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    [Is floating point math broken?](https://stackoverflow.com/q/588004) is fairly comprehensive. – 001 Nov 17 '21 at 21:18
  • About 7 significant figures is all you can expect from `float`. – Fred Larson Nov 17 '21 at 21:20
  • The short version of the comprehensive explanation is that internally, everything is binary. The decimal fraction 123.45678 does not exist, not exactly. The closest binary fraction that *does* exist (which is the one you'll get) corresponds to 123.45677947998046875. So when you (correctly) take the fractional part of *that*, you get 0.45677947998046875, or 0.456779 when rounded to 6 places. – Steve Summit Nov 17 '21 at 21:36
  • If you had started with the number 0.45678 (which can't be represented exactly in binary either, but can at least be represented with more precision on the fraction side) you would have gotten a binary fraction corresponding to 0.4567799866199493408203125, which is closer, and would have rounded to 0.456780 in 6 places. – Steve Summit Nov 17 '21 at 21:39
  • In other words, you would find that the code `decompose(123.45678, &decimal, &whole); if(decimal != 0.45678) printf("surprise!\n");` printed "`surprise!`". – Steve Summit Nov 17 '21 at 21:42
  • Precision in almost any floating-point format is finite. At the far right edge of the available precision (which corresponds to roughly 7 decimal digits for type `float`), noise begins to accumulate. If you're careful and/or lucky, you can arrange things so that the noise stays out there on the right-hand edge. What you *don't* want is for the noise to creep leftwards, eating up those precious 7 digits of precision. But when you subtract two numbers of significantly different magnitudes, that's exactly what happens. – Steve Summit Nov 17 '21 at 21:47
  • When you subtract 123 from 123.45678, you're left with only about 4 digits that are any good. That's why 0.4567 was right, but the 8 was wrong. (And bear in mind that counting decimal digits like this is never exact. Type float gives you *approximately* 7 digits of precision, but it can be as little as 6 and as many as 9. What you really have, down inside, is 24 binary *bits* of precision.) – Steve Summit Nov 17 '21 at 21:50
  • The bottom line is that your code is not broken — it is doing the best that it can do, given the limited precision of type `float`. You'd get better results with type `double`, but they still wouldn't be perfect, because the precision of type `double` is limited, too (to the equivalent of about 16 decimal digits). – Steve Summit Nov 17 '21 at 22:02

0 Answers0