-1

I need to redo printf for a projet, so I actually have a problem with the conversion of float. I managed to convert almost everything but for the number 1254451555.6
I got an issue: I got 1254451555.59999.

I think it's the calculation to keep the part after the . that doesnt work.

nbr = ((n - nbr) * 100000000);

I tried different things but I haven't managed to fix it yet.

Do you have any idea?

  int               getlenghtitoa(long long n, int nbase)
  {
         int i;

         i = 0;
         while (n >= 0)
        {
          n /= nbase;
          i++;
          if (n == 0)
               break ;
        }
        return (i);
 }  

 float             ft_nbconv(float n, int i)
{
        while (i-- > 0)
        n = n *10;
        return (n);
 }

int                ft_power(long long nbr)
{
        int i;

        i = 1;
        while(nbr > 10)
        {
            i *= 10;
            nbr = nbr / 10;
         }
        return (i);
 }

char            *ft_conver_f(long double  n)
{
     char               *dest;
     int                    i;
     int                a;
     long long int          nbr;
     int                power;

     nbr = (long long) n;
     i  = getlenghtitoa((long long )n, 10);
     if (!(dest = malloc(sizeof(char) * (i + 8))))
       return (0);
     a = i;
     i = 0;
     power = ft_power(nbr);
     while (a--)
    {
        dest[i++] = ((nbr / power) % 10) + '0';
        if (power != 1)
            power /= 10;
    }
    dest[i++] = '.';
    nbr = ((n - nbr) * 100000000);
    power = 10000000;
    while (a++ < 5)
    {
        if (a == 5)
            if ((((nbr / power)) % 10) >= 5)
           {
               dest[i++] = ((nbr / power) % 10 + 1) + '0';
               break;
           }
        dest[i++] = ((nbr / power) % 10) + '0';
        power /= 10;
    }
    dest[i] = '\0';
    return (dest);
  }
pikl
  • 33
  • 2
  • 7
  • 6
    Please take care to properly format your code before presenting it to the world. As it stands it's a mess. – alk Nov 03 '19 at 11:34
  • @alk it would be great if u share the link for formating in stackoverflow for new-bie :) – Mike Nov 03 '19 at 11:38
  • @pmg prbly he need to do it for school project so, he can't use already made functions – Maqcel Nov 03 '19 at 11:40
  • Just use any indention style/schema you prefer and stick to it. Some are listed here: https://en.wikipedia.org/wiki/Indentation_style (SO does not like TABs, BTW) – alk Nov 03 '19 at 11:41
  • 2
    If you got 1254451555.59999 for "1254451555.6" you're doing pretty good. That's kind of the correct answer. See [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Steve Summit Nov 03 '19 at 12:23
  • @SteveSummit yeah, but i need to make the same result that printf does T_T, thanks for the website and the answer – pikl Nov 03 '19 at 13:02
  • @alk thanks you for the reply , i did improve the presentation :> – pikl Nov 03 '19 at 13:07
  • i manage to fixe it , i change my way of doing it and multiply the number giving to me by 1000000 and look if the last number is > 5 if yeah , i add +1 to the total number and it do the trick , thanks you all for support – pikl Nov 03 '19 at 14:34

1 Answers1

0

Most decimal fractions cannot be represented exactly as binary fractions. A consequence is that, in general, the decimal floating-point numbers you enter are only approximated by the binary floating-point numbers actually stored in the machine.

That's why when implementing a printf, the only way to really be able to convert a floating number to a 2-seperated-by-point integers, is by using the precision factor and rounding manually. If you are not required to implement the precision, the default is 6. (Precision is the number of places to print after the dot (and it's rounded)). And that's what's missing in your implementation. Let's call the digits before the dot the ipart and the digits after the fpart .

nbr = ((n - nbr) * 100000000);

This should be

nbr = ((n - nbr) * 10000000); // 7 zeros
// nbr is now equal to 5999999
if (nbr % 10 >= 5)
{
    nbr = nbr / 10 + 1;
}
else
    nbr = nbr / 10;

This way, you get 7 digits after the dot, see if the last one is higher than 5, if it is, you add +1 to nbr (after dividing by 10 to make sure nbr has 6 digits), if it's not, you just divide by 10.

One more note about this rounding method, It will not be able to carry the rounding from the fpart to the ipart . what if you want to print 3.9999999 ? It should print 4.000000. That means that can't just convert the ipart to a string from the beginning, because sometimes rounding the fpart will add +1 to your ipart

So think about creating a function ltoa for example that takes a long long int and converts it to a string, complete the piece of code about rounding i just gave you to make sure rounding can be carried to the ipart , then convert the whole thing to string using something like

dest = join(ltoa(ipart), ".", ltoa(fpart)).

A couple more notes, your function does not handle negative numbers. And your int ft_pow can be easily flooded, so consider changing to long long ft_pow

mdaoud
  • 111
  • 4