0
void    putfnbr(float number)
{
    int a = (int) number;
    putnbr(a);
    write(1, ".", 1);
    int i = 6;
    while (i > 0)
    {

        number = (number - a) * (10);
        a = (int) number;
        putnbr(a);
        i--;
    }
}
putfnbr(123.456555);// output 123.456558 
printf("\n%f", 123.456555); // output 123.456555

this function works well however the last number it's converting to another number in this example: 5 becomes 8, I want it to print the whole number as it's as the printf() dose

  • 1
    Note that `%f` in `printf` works with `double` arguments,not `float`. The `f` refers to fixed digit printing, not `float`. Note that if you cast a floating-point operand to integer type, the behavior is undefined if the value is out or range of the integer type. – Kaz Sep 21 '21 at 00:26
  • 1
    @Kaz A `float` passed as a _variadic_ parameter gets promoted to `double` by the caller. With: `float x = 123.456; void foo(float y) { ... } foo(x); printf("%f\n",x);` then `x` gets passed to `foo` as a `float` but as a `double` to `printf`. And, _The `f` refers to fixed digit printing, not `float`_? Do you mean `d`? For `%f`, this is `float/double` and _not_ "fixed" (i.e. integer) – Craig Estey Sep 21 '21 at 01:25
  • 1
    See also [how to convert a float number to string to print it using write() function in C](https://stackoverflow.com/q/69248148/2410359). – chux - Reinstate Monica Sep 21 '21 at 02:15
  • 1
    @HssainAitkadir Accurately converting a floating-point number to a properly-rounded string of decimal digits turns out to be a fantastically hard problem. If you can come close, you should consider that a success. Trying to get exactly the same result that `printf` does, in every case, is probably not achievable without a truly unreasonable amount of time and effort. – Steve Summit Sep 21 '21 at 02:26
  • @CraigEstey `%f` prints in a fixed decimal format like 123.456, with a fixed number of places past the decimal, given by the precision. `printf` also supports `%e` (exponent notation) and `%g` (general: it chooses the representation). – Kaz Sep 21 '21 at 02:26
  • @SteveSummit I think it's a fantastically hard problem to try to do in portable C code, that is agnostic of the floating-point format. If you assume concretes like "IEEE 64 bit double with a 52 bit mantissa with an implicit leading 1, 11 bit binary exponent with such and such bias and one bit sign", that will tend to simplify things. – Kaz Sep 21 '21 at 02:30
  • Works OK for many values. Failed cases: Improper rounding, e.g.: `putfnbr(0.999999f)` prints `"0.999999"` rather than 7 digit `"0.9999999"` or best 6-digit `"1.000000"`. Fails for large value, NaN, -0.0. – chux - Reinstate Monica Sep 21 '21 at 02:33
  • @Kaz I'd say a definitive answer to handle all `float` without library support is very challenging. For a learners, this task encourages short cuts, UB and not full range correctness. – chux - Reinstate Monica Sep 21 '21 at 02:36
  • Thank you guys for your time and useful information I really appreciate – Hssain Aitkadir Sep 21 '21 at 16:18
  • Hssain Aitkadir, `putfnbr(float number)` --> `putfnbr(double number)`. – chux - Reinstate Monica Sep 27 '21 at 14:03

1 Answers1

4

The problem is that the closest float value to the number 123.456555 is actually 123.4565582275390625 (0x1.edd384p+6), so that is what you get when you print it.

The printf format %f prints a double, for which the closest value is 123.4565549999999944930095807649195194244384765625 (0x1.edd38327674d1p+6) so when you print rounded to 6 decimal places (the default with %f) you get what you see.

If you change your putfnbr routine to use a double instead of a float, you'll print the value 123.456554, because you are always rounding towards zero -- you really should be rounding the last digit to the nearest integer. Unfortunately that turns out to be very hard to do while still getting all the corner cases right.

One other note -- your code will misbehave for negative numbers as written.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226