-1

I'm trying to make a function that enables me to print floats. Right now, I'm encountering two strange behaviors : Sometimes, values like 1.3 come out as 1.2999999 instead of 1.3000000,and sometimes values like 1.234567 come out as 1.2345672 instead of 1.2345670.

Here's the source code :

int     ft_putflt(float f)
{
    int     ret;
    int     intpart;
    int     i;

    ret = 0;
    i = 0;
    intpart = (int)f;
    ft_putnbr(intpart);
    ret = ft_nbrlen(intpart) + 8;
    write(1, ".", 1);
    while (i++ < 7)
    {
        f *= 10;
        ft_putchar(48 + ((int)f % 10));
    }
    return (ret);
}

ft_putnbr is OK AFAIK. ft_putchar is a simple call to "write(1, &c, 1)".

test values (value : output)

1.234567  : 1.2345672 (!)

1.2345670 : 1.2345672 (!)

1.0000001 : 1.0000001 OK

0.1234567 : 0.1234567 OK

0.67      : 0.6700000 OK

1.3       : 1.3000000 OK (fixed it)

1.321012  : 1.3210119 (!)

1.3210121 : 1.3210122 (!)

This all seems a bit mystic to me... Loss of precision when casting to int maybe ?

Mr. Llama
  • 20,202
  • 2
  • 62
  • 115
SwiX
  • 111
  • 2
  • 8
  • 2
    Not so much loss of precision, as lacking precision to start with. `float` can only represent about 7 decimal places accurately. Try `double` if you want more. – Mike Seymour Nov 04 '14 at 22:43
  • 3
    Welcome to floating point math. Neither of the "symptoms" you note are unexpected or abnormal. – Lee Daniel Crocker Nov 04 '14 at 22:45
  • Hum... Is there a way to work around these "symptoms" ? – SwiX Nov 04 '14 at 22:48
  • 2
    @SwiX yes. Use fixed point numbers instead of floating point. – eerorika Nov 04 '14 at 22:49
  • Okay, thanks. I don't understand the mechanism behind that as deeply as I wish, but that'll have to do - the function is still accurate enough for the purpose it has ;) – SwiX Nov 05 '14 at 00:01

2 Answers2

1

Yes, you lose precision when messing with floats and ints.

If both floats have differing magnitude and both are using the complete precision range (of about 7 decimal digits) then yes, you will see some loss in the last places, because floats are stored in the form of (sign) (mantissa) × 2(exponent). If two values have differing exponents and you add them, then the smaller value will get reduced to less digits in the mantissa (because it has to adapt to the larger exponent):

PS> [float]([float]0.0000001 + [float]1)
1

In relation to integers, a normal 32-bit integer is capable of representing values exactly which do not fit exactly into a float. A float can still store approximately the same number, but no longer exactly. Of course, this only applies to numbers that are large enough, i. e. longer than 24 bits.Because a float has 24 bits of precision and (32-bit) integers have 32, float will still be able to retain the magnitude and most of the significant digits, but the last places may likely differ:

PS> [float]2100000050 + [float]100
2100000100
Lawrence Aiello
  • 4,560
  • 5
  • 21
  • 35
1

This is inherent in the use of finite-precision numerical representation schemes. Given any number that can be represented, A, there is some number that is the smallest number greater than A that can be represented, call that B. Numbers between A and B cannot be represented exactly and must be approximated.

For example, let's consider using six decimal digits because that's an easier system to understand as a starting point. If A is .333333, then B is .333334. Numbers between A and B, such 1/3, cannot be exactly represented. So if you take 1/3 and add it to itself twice (or multiply it by 3), you will get .999999, not 1. You should expect to see imprecision at the limits of the representation.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278