Integer subtraction problem, help!

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • bruce.james.lee@gmail.com

    Integer subtraction problem, help!

    hi
    i have a problem with integer subtraction in C.

    printf("%d", c < (a - b));

    a is got from a #define and is 0x80000000 and b is got from input and
    is also 0x80000000.
    c is ffffffff (-1).
    Now, this should print 1 (true) but it prints 0!

    If I modify this to
    d = a - b;
    printf("%d", c < d);
    it prints 1 correctly.

    I am stumped, please help! i guess something wrong happens during the
    comparison, i dont know what.
    If i just retain my second method which works, is everything ok? or is
    there some risk?

    thanks a lot
    bruce

  • Christian Bau

    #2
    Re: Integer subtraction problem, help!

    In article <1112560953.632 571.65940@l41g2 000cwc.googlegr oups.com>,
    bruce.james.lee @gmail.com wrote:
    [color=blue]
    > hi
    > i have a problem with integer subtraction in C.
    >
    > printf("%d", c < (a - b));
    >
    > a is got from a #define and is 0x80000000 and b is got from input and
    > is also 0x80000000.
    > c is ffffffff (-1).[/color]

    If you mean 0xffffffff, that is definitely not the same as -1.

    Take a good book about C and check out _exactly_ what types the various
    operands have.

    Comment

    • Chris Torek

      #3
      Re: Integer subtraction problem, help!

      From: bruce.james.lee @gmail.com

      In two different articles,
      <1112560762.360 771.275210@f14g 2000cwb.googleg roups.com>
      and
      <1112560953.632 571.65940@l41g2 000cwc.googlegr oups.com>
      <bruce.james.le e@gmail.com> wrote:
      [color=blue]
      >i have a problem with integer subtraction in C.
      > printf("%d", c < (a - b));
      >a is got from a #define and is 0x80000000 and b is got from input and
      >is also 0x80000000.
      >c is ffffffff (-1).
      >Now, this should print 1 (true) but it prints 0!
      >
      >If I modify this to[/color]

      [here is where the two articles differ]
      [color=blue]
      > d = c < (a - b);
      > printf("%d", d);
      >it prints 1 correctly.[/color]

      This would imply a compiler bug.
      [color=blue]
      > d = a - b;
      > printf("%d", c < d);
      >it prints 1 correctly.[/color]

      This would imply something else entirely.
      [color=blue]
      >I am stumped, please help! i guess something wrong happens during the
      >comparison, i dont know what.[/color]

      The situation here is a bit like a guy who drives into an auto shop
      with a problem. The mechanic looks at the car: "I don't see anything
      wrong here." "Oh, *this* isn't the car with the problem. I drove
      this one in because the other one won't start!"

      Presumably something *is* wrong, but you have not brought in the
      actual code, just some little snippet from it. (In the analogy
      above, the guy might have brought in the cigarette lighter from
      the faulty car. :-) ) Still, one can make a guess at your complete
      program:

      % cat t.c
      #include <stdio.h>

      #define a 0x80000000

      int main(void) {
      int b = 0x80000000, c = 0xffffffff, d;

      printf("c < (a - b): %d\n", c < (a - b)); /* line 8 */
      d = a - b;
      printf("c < d: %d\n", c < d);
      return 0;
      }
      % cc -ansi -pedantic -o t t.c
      % ./t
      c < (a - b): 0
      c < d: 1
      %

      This has the same symptoms you describe in
      <news:111256095 3.632571.65940@ l41g2000cwc.goo glegroups.com>.
      Note what happens if we ask the compiler (GNU's GCC, in this case)
      for "maximal warnings":

      % cc -O -Wall -W -ansi -pedantic -o t t.c
      t.c: In function `main':
      t.c:8: warning: comparison between signed and unsigned
      %

      (line 8 is the commented printf() call). This is your clue as to
      what is wrong.

      On a 32-bit-"int" system like the one I used here, the constant
      0x80000000 has type "unsigned int". The expression:

      c < (0x80000000 - b)

      has three operands: one "int" (c), one "unsigned int" (0x80000000),
      and one more "int" (b). The parenthesized sub-expression is grouped
      first, and a C compiler must find the type to use for the result of
      the subtraction based on nothing but the types of the two operands.
      Since one is "unsigned int" and the other is plain (signed) "int",
      the computation will be done with unsigned arithmetic, producing an
      unsigned int result. The value in b is first converted to unsigned
      int, giving 0x80000000U again, and the result is the unsigned int 0,
      so this means:

      c < 0U

      The variable c is of course -1, but this expression does the
      comparison by converting c to unsigned int, producing UINT_MAX or
      (on this implementation) 4294967295, so this means:

      4294967295U < 0U

      and of course it is not.

      By assigning the result of the subtraction to "d" -- an ordinary
      signed int -- we get the second comparison to compare -1 and 0 (two
      ordinary signed "int"s), and of course -1 is less than 0.

      Note that a more fundamental problem here is that you have defined
      "a" as 0x80000000, which is numerically 2147483648, but on your
      machine (and the one I used to compile the test case above), INT_MAX
      is 2147483647. What happens when you put 2147483648 into a variable
      that cannot hold a number bigger than 2147483647? Pretty much the
      same thing as when you put ten gallons of water into a five-gallon
      bucket: it overflows. To extend this analogy a bit, C does not
      specify whether the floor is wood (which warps) or tile (which is
      waterproof and does not warp) -- you are on your own at this point.
      If you want the language itself to specify the result, avoid this
      kind of overflow. If you feel safe in depending on "always having
      tile floors" as it were -- that is, if you are sure you will always
      use the machine you are using right now -- you can depend on any
      additional guarantees it makes. Here in the comp.lang.c newsgroup,
      thuogh, we generally try to discourage this kind of "depending on
      the machine", at least whenever possible; and we try not to talk
      too much about the specifics of any one machine, since C runs on
      so many different machines with different behaviors.
      --
      In-Real-Life: Chris Torek, Wind River Systems
      Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
      email: forget about it http://web.torek.net/torek/index.html
      Reading email is like searching for food in the garbage, thanks to spammers.

      Comment

      • Old Wolf

        #4
        Re: Integer subtraction problem, help!

        bruce.james.lee @gmail.com wrote:[color=blue]
        > i have a problem with integer subtraction in C.
        >
        > printf("%d", c < (a - b));
        >
        > a is got from a #define and is 0x80000000
        > and b is got from input and is also 0x80000000.
        > c is ffffffff (-1).
        > Now, this should print 1 (true) but it prints 0!
        >
        > If I modify this to
        > d = a - b;
        > printf("%d", c < d);
        > it prints 1 correctly.[/color]

        You didn't post exact code, so I'm going to make some assumptions:
        - You're on a machine with 32-bit ints
        - 'b' is an unsigned int (A signed int can't hold 0x80000000)
        - 'c' is a signed int which holds -1 (not ffffffff)
        - 'd' is a signed int;

        Now, 0x80000000 (in decimal, 2147483648) is too big to fit
        in a signed int, so the compiler treats it as an unsigned int.
        So (a - b) has type "unsigned int" and value 0.

        So we have reduced the problem to the old C 'flaw' of signed-
        unsigned comparisons. You would get the same result if
        you wrote:
        printf("%d", -1 < 0u);

        In C, binary operators (that is, operators that take 2 operands)
        must have both operands the same type. You gave it different
        types (one is signed int, the other unsigned int). The compiler
        'solves' this problem by converting the signed int to unsigned,
        so it ends up doing the comparison 4294967295 < 0 , which
        turns out to be false as you have seen.

        In your case with 'd', you are comparing two ints, so
        no conversions occur, and -1 < 0 is of course true.

        In your specific example you can fix the problem like this:
        printf("%d\n", c < (int)(a - b));

        But if (a - b) did not hold a valid int value (eg. if a is
        0x80000000 and b is 0), then you have undefined behaviour.
        So in general, if you need to compare the full range of
        signed ints with the full range of unsigned ints, you would
        need a function like this:

        int less_than(int a, unsigned int b)
        {
        if (b > INT_MAX) return 0;
        return a < (int)b;
        }

        Comment

        • Thomas Cameron

          #5
          Re: Integer subtraction problem, help!

          <posted & mailed>

          bruce.james.lee @gmail.com wrote:
          [color=blue]
          > hi
          > i have a problem with integer subtraction in C.
          >
          > printf("%d", c < (a - b));
          >
          > a is got from a #define and is 0x80000000 and b is got from input and
          > is also 0x80000000.
          > c is ffffffff (-1).
          > Now, this should print 1 (true) but it prints 0!
          >
          > If I modify this to
          > d = a - b;
          > printf("%d", c < d);
          > it prints 1 correctly.
          >
          > I am stumped, please help! i guess something wrong happens during the
          > comparison, i dont know what.
          > If i just retain my second method which works, is everything ok? or is
          > there some risk?
          >
          > thanks a lot
          > bruce[/color]

          I'll assume that all of the other issues are taken care of and simply point
          out math issues here.

          a) 0x80000000 - (-1) = 0x80000001 --> Double negative is positive, so (--1)
          is equivalent to (+1). Watch this carefully.

          b) 0x80000000 < 0x80000001 is true, yes, but the integer value of "true" is
          implementation specific...so tread lightly here. :-)

          Just words of caution.

          --
          Tom Cameron
          tom<at>drdabble s<dot>us

          Comment

          • Old Wolf

            #6
            Re: Integer subtraction problem, help!

            Thomas Cameron wrote:[color=blue]
            > bruce.james.lee @gmail.com wrote:[color=green]
            > >
            > > printf("%d", c < (a - b));
            > >
            > > a is got from a #define and is 0x80000000 and
            > > b is got from input and is also 0x80000000.
            > > c is ffffffff (-1).[/color]
            >
            > a) 0x80000000 - (-1) = 0x80000001 --> Double negative is
            > positive, so (--1) is equivalent to (+1). Watch this carefully.[/color]

            That issue never came up in the OP example. 0x80000000 was being
            subtracted from 0x80000000. (allegedly).
            [color=blue]
            > b) 0x80000000 < 0x80000001 is true, yes, but the integer value
            > of "true" is implementation specific...so tread lightly here. :-)[/color]

            The integer value of a '<' operation must be either 0 or 1.

            Comment

            Working...