Confused to printf %f

Discussion in 'C Programming' started by timmu, Jul 29, 2006.

  1. timmu

    timmu Guest

    Someone asked me a question about integer division and printf
    yesterday,
    I tell him he should do a casting to float/double before you do any
    interger division.
    But he doesn't think so, so I try to do some example to explain,
    However, after some trying,
    I confused when I try to do some integer constant division,
    I know I should do float division something like 3.0/6.0,
    but I'm still confused where the -0.124709 comes for the following
    example?
    I just add some dummy variables, but the result will show some
    different.
    did I overflow anything?

    The situation is somehow a little different for a different gcc
    compiler, it's really wierd.


    //example 1
    #include <stdio.h>
    int main()
    {
    //double i;
    //long a=1,b=4;
    printf("%f\n",3/7);
    printf("%f\n",5/7);
    printf("%.2f\n",5/7);
    printf("%f\n",5.0/7.0);
    printf("%d\n",4/7);
    return 0;
    }

    -bash-3.00$ gcc z.c
    -bash-3.00$ ./a.out
    -0.124709
    -0.124709
    -0.12
    0.714286
    0

    **********************

    //example 2:
    #include <stdio.h>
    int main()
    {
    double i;
    long a=1,b=4;
    printf("%f\n",3/7);
    printf("%f\n",5/7);
    printf("%.2f\n",5/7);
    printf("%f\n",5.0/7.0);
    printf("%d\n",4/7);
    return 0;
    }
    -bash-3.00$ gcc z.c
    -bash-3.00$ ./a.out
    0.000000
    0.000000
    0.00
    0.714286
    0

    ********
    //example 3:
    #include <stdio.h>
    int main()
    {
    double i;
    //long a=1,b=4;
    printf("%f\n",3/7);
    printf("%f\n",5/7);
    printf("%.2f\n",5/7);
    printf("%f\n",5.0/7.0);
    printf("%d\n",4/7);
    return 0;
    }

    -bash-3.00$ gcc -v
    Using built-in specs.
    Configured with: FreeBSD/i386 system compiler
    Thread model: posix
    gcc version 3.4.2 [FreeBSD] 20040728

    -bash-3.00$ gcc z.c
    -bash-3.00$ ./a.out
    -0.124709
    -0.124709
    -0.12
    0.714286
    0
    -bash-3.00$ gcc41 z.c
    -bash-3.00$ ./a.out
    0.000000
    0.000000
    0.00
    0.714286
    0

    Thanks for any information!
     
    timmu, Jul 29, 2006
    #1
    1. Advertising

  2. timmu said:

    >
    > Someone asked me a question about integer division and printf
    > yesterday,
    > I tell him he should do a casting to float/double before you do any
    > interger division.


    Why?

    > But he doesn't think so, so I try to do some example to explain,
    > However, after some trying,
    > I confused when I try to do some integer constant division,


    If you are confused yourself, why did you "tell him" what he should do?

    > I know I should do float division something like 3.0/6.0,


    That isn't a float division.

    > but I'm still confused where the -0.124709 comes for the following
    > example?


    You lied to the compiler, and it got its revenge.

    <snip>
    >
    > //example 1
    > #include <stdio.h>
    > int main()
    > {
    > //double i;
    > //long a=1,b=4;
    > printf("%f\n",3/7);


    3 is an int, 7 is an int, and so it's not surprising that 3/7 is an int. But
    by using %f, you said to printf: "I'm giving you a double". But you didn't
    give it a double. You gave it an int. If you lie to the compiler, it will
    wreak its revenge.

    Use %d to print ints.

    <snip>

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, Jul 29, 2006
    #2
    1. Advertising

  3. timmu

    timmu Guest

    Richard Heathfield 寫é“:

    > timmu said:
    >
    > >
    > > Someone asked me a question about integer division and printf
    > > yesterday,
    > > I tell him he should do a casting to float/double before you do any
    > > interger division.

    ^^^^^^^^^
    sorry I mean float division.

    >
    > Why?
    >
    > > But he doesn't think so, so I try to do some example to explain,
    > > However, after some trying,
    > > I confused when I try to do some integer constant division,

    >
    > If you are confused yourself, why did you "tell him" what he should do?
    >
    > > I know I should do float division something like 3.0/6.0,

    >


    I really means 3.0/7.0, isn't this double-float division?

    > That isn't a float division.
    >
    > > but I'm still confused where the -0.124709 comes for the following
    > > example?

    >
    > You lied to the compiler, and it got its revenge.
    >
    > <snip>
    > >
    > > //example 1
    > > #include <stdio.h>
    > > int main()
    > > {
    > > //double i;
    > > //long a=1,b=4;
    > > printf("%f\n",3/7);

    >
    > 3 is an int, 7 is an int, and so it's not surprising that 3/7 is an int. But
    > by using %f, you said to printf: "I'm giving you a double". But you didn't
    > give it a double. You gave it an int. If you lie to the compiler, it will
    > wreak its revenge.
    >
    > Use %d to print ints.
    >
    > <snip>


    what I really confused is what compiler doing here.
    anyway thx for your information.

    >
    > --
    > Richard Heathfield
    > "Usenet is a strange place" - dmr 29/7/1999
    > http://www.cpax.org.uk
    > email: rjh at above domain (but drop the www, obviously)
     
    timmu, Jul 29, 2006
    #3
  4. timmu said:

    >
    > Richard Heathfield [said]?
    >
    >> timmu said:
    >>
    >> >
    >> > Someone asked me a question about integer division and printf
    >> > yesterday,
    >> > I tell him he should do a casting to float/double before you do any
    >> > interger division.

    > ^^^^^^^^^
    > sorry I mean float division.


    Same question. Why cast?

    <snip>
    >
    > I really means 3.0/7.0, isn't this double-float division?


    It's a division of a double by a double. The result is a double.

    >> > but I'm still confused where the -0.124709 comes for the following
    >> > example?

    >>
    >> You lied to the compiler, and it got its revenge.
    >>
    >> <snip>
    >> >
    >> > //example 1
    >> > #include <stdio.h>
    >> > int main()
    >> > {
    >> > //double i;
    >> > //long a=1,b=4;
    >> > printf("%f\n",3/7);

    >>
    >> 3 is an int, 7 is an int, and so it's not surprising that 3/7 is an int.
    >> But by using %f, you said to printf: "I'm giving you a double". But you
    >> didn't give it a double. You gave it an int. If you lie to the compiler,
    >> it will wreak its revenge.
    >>
    >> Use %d to print ints.
    >>
    >> <snip>

    >
    > what I really confused is what compiler doing here.


    The compiler merely generates a call to printf. It is printf itself which
    attempts to evaluate the data you pass to it. If you give it the wrong kind
    of data, you shouldn't be surprised if you get the wrong answer.

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, Jul 29, 2006
    #4
  5. "timmu" <> wrote:

    > printf("%f\n",3/7); // ERROR use %d to print ints
    > printf("%f\n",5.0/7.0); // OK (prints "0.714286")
    > printf("%d\n",4/7); // OK (prints "0")


    I hope you are aware that in C, the following fractions are ALL
    equal to zero?

    1/7 2/7 3/7 4/7 5/7 6/7

    That's because with integer division, the fractional part is
    discarded. If you want to keep the fractional part, you need
    to write:

    1.0/7.0 2.0/7.0 3.0/7.0 4.0/7.0 5.0/7.0 6.0/7.0

    and also use %f instead of %d in your printf() call.

    --
    Cheers,
    Robbie Hatley
    East Tustin, CA, USA
    lone wolf intj at pac bell dot net
    (put "[usenet]" in subject to bypass spam filter)
    home dot pac bell dot net slant earnur slant
     
    Robbie Hatley, Jul 29, 2006
    #5
  6. "timmu" <> writes:
    > Someone asked me a question about integer division and printf
    > yesterday,
    > I tell him he should do a casting to float/double before you do any
    > interger division.


    It depends on what you're trying to do.

    The division operator can be applied to either integer or
    floating-point operands. ("Integer" refers any integer type: int,
    short, long, long long, unsigned char, etc.; "floating-point" refers
    to any of float, double, long double.)

    If you want to divide integers, divide integers. If you want to
    divide floating-point values, do so. There's no general rule that
    says you should use one or the other.

    In the usual mathematical sense, 3/5 is 0.6; to do that in C, you need
    to use floating-point division: 3.0/5.0 (or, for variables rather than
    constants, something like (double)x/(double)y). But in C, 3/5 is an
    integer division, yielding the value 0 (use the "%" operation if you
    want the remainder).

    [...]

    > //example 1
    > #include <stdio.h>
    > int main()
    > {
    > //double i;
    > //long a=1,b=4;
    > printf("%f\n",3/7);
    > printf("%f\n",5/7);
    > printf("%.2f\n",5/7);


    3/7 and 5/7 are expressions of type int; you need to use "%d" to print
    them. Don't try to figure out the results of doing it wrong, just do
    it right.

    [snip]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Jul 29, 2006
    #6
  7. timmu

    Michael Mair Guest

    Keith Thompson schrieb:
    > "timmu" <> writes:
    >
    >>Someone asked me a question about integer division and printf
    >>yesterday,
    >>I tell him he should do a casting to float/double before you do any
    >>interger division.

    >
    > It depends on what you're trying to do.
    >
    > The division operator can be applied to either integer or
    > floating-point operands. ("Integer" refers any integer type: int,
    > short, long, long long, unsigned char, etc.; "floating-point" refers
    > to any of float, double, long double.)
    >
    > If you want to divide integers, divide integers. If you want to
    > divide floating-point values, do so. There's no general rule that
    > says you should use one or the other.
    >
    > In the usual mathematical sense, 3/5 is 0.6; to do that in C, you need
    > to use floating-point division: 3.0/5.0 (or, for variables rather than
    > constants, something like (double)x/(double)y). But in C, 3/5 is an
    > integer division, yielding the value 0 (use the "%" operation if you
    > want the remainder).


    As an aside: Some compilers' extensions ignore C semantics in
    the following situation:
    double foo = 3/5;
    then gives you approximately 0.6.
    I do no longer have the data about these things but I remember
    some gcc 3.x having that "feature" when not invoked with -std=c89,
    -ansi, or -std=c99 (more recent gcc versions behave correctly in
    this respect) -- a very nasty surprise for a real programme
    relying on "foo" having value 0.0 in this case (this came in via
    macro) and also little bit embarrassing when trying to teach
    students the difference between
    3/5
    and
    3.0/5, 3/5.0, 3.0/5.0


    <snip>

    Cheers
    Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
     
    Michael Mair, Jul 29, 2006
    #7
  8. Michael Mair <> writes:
    [...]
    > As an aside: Some compilers' extensions ignore C semantics in
    > the following situation:
    > double foo = 3/5;
    > then gives you approximately 0.6.
    > I do no longer have the data about these things but I remember
    > some gcc 3.x having that "feature" when not invoked with -std=c89,
    > -ansi, or -std=c99 (more recent gcc versions behave correctly in
    > this respect) -- a very nasty surprise for a real programme
    > relying on "foo" having value 0.0 in this case (this came in via
    > macro) and also little bit embarrassing when trying to teach
    > students the difference between
    > 3/5
    > and
    > 3.0/5, 3/5.0, 3.0/5.0


    Hmm. I've just tried it with gcc versions 2.7.2.2, 2.8.1, 2.95.2,
    3.0.4, 3.4.4, and 4.1.1; with each of them, it set foo to 0.0.

    Program:

    #include <stdio.h>
    int main(void)
    {
    double foo = 3/5;
    printf("foo = %g\n", foo);
    return 0;
    }

    Command line:

    gcc tmp.c -o tmp && ./tmp

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Jul 29, 2006
    #8
  9. timmu

    Michael Mair Guest

    Keith Thompson schrieb:
    > Michael Mair <> writes:
    > [...]
    >
    >>As an aside: Some compilers' extensions ignore C semantics in
    >>the following situation:
    >> double foo = 3/5;
    >>then gives you approximately 0.6.
    >>I do no longer have the data about these things but I remember
    >>some gcc 3.x having that "feature" when not invoked with -std=c89,
    >>-ansi, or -std=c99 (more recent gcc versions behave correctly in
    >>this respect) -- a very nasty surprise for a real programme
    >>relying on "foo" having value 0.0 in this case (this came in via
    >>macro) and also little bit embarrassing when trying to teach
    >>students the difference between
    >> 3/5
    >>and
    >> 3.0/5, 3/5.0, 3.0/5.0

    >
    > Hmm. I've just tried it with gcc versions 2.7.2.2, 2.8.1, 2.95.2,
    > 3.0.4, 3.4.4, and 4.1.1; with each of them, it set foo to 0.0.
    >
    > Program:
    >
    > #include <stdio.h>
    > int main(void)
    > {
    > double foo = 3/5;
    > printf("foo = %g\n", foo);
    > return 0;
    > }
    >
    > Command line:
    >
    > gcc tmp.c -o tmp && ./tmp


    Maybe it was a "feature" of only one version. I do no longer
    have the programmes the students wrote nor do I know the version
    of gcc this course went by but I remember the integer division
    problem distinctly because I _was_ rather embarrassed at first
    before figuring it out.
    I found the exercise the translation of which essentially is to
    to write a programme reading two ints m and M and do certain things
    based on whether m > M, M - m < 4, M - m < 8, or else.
    Among these things was calculating m/M and (m+M-1)/2.5 for the last
    two cases and outputting them -- and, between the lines, remarking
    on the difference between integer division and floating point
    division... Unfortunately, m/M did not give 0 as expected.

    -Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
     
    Michael Mair, Jul 29, 2006
    #9
  10. timmu

    timmu Guest

    Robbie Hatley 寫é“:

    > "timmu" <> wrote:
    >
    > > printf("%f\n",3/7); // ERROR use %d to print ints
    > > printf("%f\n",5.0/7.0); // OK (prints "0.714286")
    > > printf("%d\n",4/7); // OK (prints "0")

    >
    > I hope you are aware that in C, the following fractions are ALL
    > equal to zero?
    >
    > 1/7 2/7 3/7 4/7 5/7 6/7
    >
    > That's because with integer division, the fractional part is
    > discarded. If you want to keep the fractional part, you need
    > to write:
    >
    > 1.0/7.0 2.0/7.0 3.0/7.0 4.0/7.0 5.0/7.0 6.0/7.0
    >
    > and also use %f instead of %d in your printf() call.
    >


    thx for your information,

    Of course I know interger divide interger will be integer,
    I know double divide double will be double...
    I know I should use %f instead of %d if I want to keep the fractional
    part...
    I knew it when my first year of C programming......

    But my friend don't know, I try to explain it to him.
    That's why I write the example in origin post.
    I wrote the wrong statement because I want to show him "it's wrong!"
    Of course I know I should use %f instead of %d...

    I just don't satisfied the "you cheat compiler, so it revenge" answer,
    I want to know the scene behind these, I want to know why the compiler
    generate a different answer
    for just adding some dummy variables.

    thx informations anyway.

    > --
    > Cheers,
    > Robbie Hatley
    > East Tustin, CA, USA
    > lone wolf intj at pac bell dot net
    > (put "[usenet]" in subject to bypass spam filter)
    > home dot pac bell dot net slant earnur slant
     
    timmu, Aug 2, 2006
    #10
  11. "timmu" <> writes:
    > Robbie Hatley 寫é“:
    >> "timmu" <> wrote:
    >>
    >> > printf("%f\n",3/7); // ERROR use %d to print ints
    >> > printf("%f\n",5.0/7.0); // OK (prints "0.714286")
    >> > printf("%d\n",4/7); // OK (prints "0")

    >>
    >> I hope you are aware that in C, the following fractions are ALL
    >> equal to zero?
    >>
    >> 1/7 2/7 3/7 4/7 5/7 6/7
    >>
    >> That's because with integer division, the fractional part is
    >> discarded. If you want to keep the fractional part, you need
    >> to write:
    >>
    >> 1.0/7.0 2.0/7.0 3.0/7.0 4.0/7.0 5.0/7.0 6.0/7.0
    >>
    >> and also use %f instead of %d in your printf() call.
    >>

    >
    > thx for your information,
    >
    > Of course I know interger divide interger will be integer,
    > I know double divide double will be double...
    > I know I should use %f instead of %d if I want to keep the fractional
    > part...
    > I knew it when my first year of C programming......
    >
    > But my friend don't know, I try to explain it to him.
    > That's why I write the example in origin post.
    > I wrote the wrong statement because I want to show him "it's wrong!"
    > Of course I know I should use %f instead of %d...


    Great, I'm glad you know this. But that wasn't very clear from your
    orginal article. And frankly, it doesn't matter much to us whether
    it's you or your friend who didn't now this; we've never met either of
    you. We can only answer what you ask.

    > I just don't satisfied the "you cheat compiler, so it revenge" answer,
    > I want to know the scene behind these, I want to know why the compiler
    > generate a different answer
    > for just adding some dummy variables.


    The type of any expression in C (that includes subexpressions) is
    almost always determined by the expression itself, not by the context
    in which it appears.

    In your example:

    printf("%f\n", 3/7);

    you use "%f" to promise printf that you're going to pass a double, but
    then you pass an int.

    Why does it print garbage rather than fixing you the error for you?
    Because the standard says it's undefined behavior. C99 7.19.6.1p9 says:

    If a conversion specification is invalid, the behavior is
    undefined. If any argument is not the correct type for the
    corresponding conversion specification, the behavior is undefined.

    The phrase "the behavior is undefined" means that there are absolutely
    no requirements on what the implementation has to do. It can behave
    as you might expect, it can produce garbage, it can crash your
    program, it can crash your computer, it can reformat your hard drive,
    or, as the joke goes, it can make demons fly out of your nose.

    Why does your particular implementation behave in some specific way?
    I don't know, I don't really care, and you shouldn't either.

    The implementation isn't literally getting revenge, it's just behaving
    on the *assumption* that you didn't lie to it. Given a "%f" format,
    printf will most likely try to print a floating-point value that it
    fetches from the location where it would find one if you had passed
    one. Since you didn't, it could use the bitwise representation of
    your integer value and pretend it's of type double, or it could grab
    some piece of garbage from somewhere. If the garbage doesn't
    represent a valid value of type double, Bad Things Can Happen. But
    different implementations of printf will do different things, and the
    details are off-topic here.

    Just don't do that.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Aug 2, 2006
    #11
  12. timmu

    timmu Guest

    Keith Thompson 寫é“:


    > Why does it print garbage rather than fixing you the error for you?
    > Because the standard says it's undefined behavior. C99 7.19.6.1p9 says:
    >
    > If a conversion specification is invalid, the behavior is
    > undefined. If any argument is not the correct type for the
    > corresponding conversion specification, the behavior is undefined.
    >
    > The phrase "the behavior is undefined" means that there are absolutely
    > no requirements on what the implementation has to do. It can behave
    > as you might expect, it can produce garbage, it can crash your
    > program, it can crash your computer, it can reformat your hard drive,
    > or, as the joke goes, it can make demons fly out of your nose.
    >
    > Why does your particular implementation behave in some specific way?
    > I don't know, I don't really care, and you shouldn't either.
    >
    > The implementation isn't literally getting revenge, it's just behaving
    > on the *assumption* that you didn't lie to it. Given a "%f" format,
    > printf will most likely try to print a floating-point value that it
    > fetches from the location where it would find one if you had passed
    > one. Since you didn't, it could use the bitwise representation of
    > your integer value and pretend it's of type double, or it could grab
    > some piece of garbage from somewhere. If the garbage doesn't
    > represent a valid value of type double, Bad Things Can Happen. But
    > different implementations of printf will do different things, and the
    > details are off-topic here.
    >
    > Just don't do that.
    >


    thx, now I know the problem is because of different implementations to
    a undefine behavior,
    really thx for your well explanation.

    > --
    > Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    > San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    > We must do something. This is something. Therefore, we must do this.
     
    timmu, Aug 2, 2006
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. ben
    Replies:
    4
    Views:
    633
    Martin Ambuhl
    Jun 26, 2004
  2. whatluo

    (void) printf vs printf

    whatluo, May 26, 2005, in forum: C Programming
    Replies:
    29
    Views:
    1,272
  3. linq936

    Confused at newline requirement for printf

    linq936, Sep 21, 2007, in forum: C Programming
    Replies:
    1
    Views:
    313
    Eric Sosman
    Sep 21, 2007
  4. azza

    printf affects following printf/s

    azza, Oct 17, 2010, in forum: C Programming
    Replies:
    0
    Views:
    444
  5. guru
    Replies:
    8
    Views:
    288
Loading...

Share This Page