Semantics of unary minus

Discussion in 'C Programming' started by Marc, Feb 12, 2006.

  1. Marc

    Marc Guest

    Hi,

    I've been lurking on clc for a few months now, and want to start by
    thanking the regulars here for opening my eyes to a whole new dimension
    of "knowing c". Considering I had never even touched the standards a
    year ago, though I graduated in embedded SW development...

    Anyway, to the problem at hand: I've stumbled upon the following
    construct at work recently, and cannot really make up my mind about the
    standard's take on the matter.

    int a;
    unsigned int b;

    if(a < 0) {
    b = -a;
    }

    I just can't decide if this is valid when a's value is -32768 (admitting
    16 bit ints). I can't see how the standard's wording on unary minus
    semantics allows for 2's complement asymmetry. C99 says:

    "The result of the unary - operator is the negative of its (promoted)
    operand. The integer promotions are performed on the operand, and the
    result has the promoted type." (I'm also slightly suspicious about the
    disappearance of "value" as compared to the semantics of unary plus...)

    Unless I'm mistaken, a won't be promoted (being an int), so there might
    be no such thing as "the negative of its (promoted) operand"? I feel
    like the standard tells me I might end up with an int worth 32768...
    (still assuming 16 bit ints)? Or should I consider there is an implied
    "if-it-fits-otherwise-overflow"?

    I couldn't find any help through google or in the FAQ, so I'd really
    appreciate any clarification.

    Marc
    Marc, Feb 12, 2006
    #1
    1. Advertising

  2. Marc

    P.J. Plauger Guest

    "Marc" <> wrote in message
    news:dsnip5$47a$02$-online.com...

    > int a;
    > unsigned int b;
    >
    > if(a < 0) {
    > b = -a;
    > }
    >
    > I just can't decide if this is valid when a's value is -32768 (admitting
    > 16 bit ints). I can't see how the standard's wording on unary minus
    > semantics allows for 2's complement asymmetry. C99 says:


    -a overflows and typically yields -32768 without a trap
    (though an implementation doesn't have to). The conversion
    is 2^16 - 32768, which is 32768. So you luck out.

    Converting to unsigned long doesn't work quite as well.
    It is much safer to write "b = 0U - a" instead.

    P.J. Plauger
    Dinkumware, Ltd.
    http://www.dinkumware.com
    P.J. Plauger, Feb 12, 2006
    #2
    1. Advertising

  3. Marc

    Eric Sosman Guest

    Marc wrote:
    > Hi,
    >
    > I've been lurking on clc for a few months now, and want to start by
    > thanking the regulars here for opening my eyes to a whole new dimension
    > of "knowing c". Considering I had never even touched the standards a
    > year ago, though I graduated in embedded SW development...
    >
    > Anyway, to the problem at hand: I've stumbled upon the following
    > construct at work recently, and cannot really make up my mind about the
    > standard's take on the matter.
    >
    > int a;
    > unsigned int b;
    >
    > if(a < 0) {
    > b = -a;
    > }
    >
    > I just can't decide if this is valid when a's value is -32768 (admitting
    > 16 bit ints). I can't see how the standard's wording on unary minus
    > semantics allows for 2's complement asymmetry. C99 says:
    >
    > "The result of the unary - operator is the negative of its (promoted)
    > operand. The integer promotions are performed on the operand, and the
    > result has the promoted type." (I'm also slightly suspicious about the
    > disappearance of "value" as compared to the semantics of unary plus...)
    >
    > Unless I'm mistaken, a won't be promoted (being an int), so there might
    > be no such thing as "the negative of its (promoted) operand"? I feel
    > like the standard tells me I might end up with an int worth 32768...
    > (still assuming 16 bit ints)? Or should I consider there is an implied
    > "if-it-fits-otherwise-overflow"?
    >
    > I couldn't find any help through google or in the FAQ, so I'd really
    > appreciate any clarification.


    Yes, two's complement is asymmetric about zero: there
    is a negative number whose absolute value is not representable.
    (The Standard actually permits an implementation to dodge this
    asymmetry by defining "all ones" to be a trap representation;
    I've never heard of an implementation that does so.)

    However, that doesn't mean unary minus is undefined: it's
    only undefined if its operand has an inappropriate value. This
    is really no different from the situation with binary minus:

    "The result of the binary - operator is the difference
    resulting from the subtraction of the second operand
    from the first." (6.5.6/6)

    This is not to be taken as implying that all subtractions must
    produce mathematically correct results: `INT_MIN - 42', for
    example, is clearly not going to produce a value less than
    INT_MIN.

    When this sort of thing happens, another provision of the
    Standard takes over:

    "If an _exceptional condition_ occurs during the
    evaluation of an expression (that is, if the result
    is not mathematically defined or not in the range of
    representable values for its type), the behavior is
    undefined." (6.5/5)

    So: If you try to negate (or take the absolute value of)
    INT_MIN on a system where `INT_MIN + INT_MAX' is not zero, the
    C language does not specify the outcome -- anything can happen,
    at least in principle. The commonest behavior is that the
    overflow is ignored, and the resulting representation (all ones)
    is equal to INT_MIN again: INT_MIN is its own negation on most
    two's-complement systems. However, this should be thought of
    as a quirk of those systems, not as part of the C language.

    --
    Eric Sosman
    lid
    Eric Sosman, Feb 12, 2006
    #3
  4. Marc

    pete Guest

    Marc wrote:

    > int a;


    > -a;


    > "if-it-fits-otherwise-overflow"?


    Yes.
    "overflow" as in "undefined behavior".

    It's a point of trivia which also comes up when writing itoa,
    that there is no integer type which is guaranteed
    to be able to represent the magnitude of INT_MIN.

    --
    pete
    pete, Feb 12, 2006
    #4
  5. "Marc" <> wrote in message
    news:dsnip5$47a$02$-online.com...
    > Hi,
    >
    > I've been lurking on clc for a few months now, and want to start by
    > thanking the regulars here for opening my eyes to a whole new dimension
    > of "knowing c". Considering I had never even touched the standards a
    > year ago, though I graduated in embedded SW development...
    >
    > Anyway, to the problem at hand: I've stumbled upon the following
    > construct at work recently, and cannot really make up my mind about the
    > standard's take on the matter.
    >
    > int a;
    > unsigned int b;
    >
    > if(a < 0) {
    > b = -a;
    > }
    >
    > I just can't decide if this is valid when a's value is -32768 (admitting
    > 16 bit ints). I can't see how the standard's wording on unary minus
    > semantics allows for 2's complement asymmetry. C99 says:
    >
    > "The result of the unary - operator is the negative of its (promoted)
    > operand. The integer promotions are performed on the operand, and the
    > result has the promoted type." (I'm also slightly suspicious about the
    > disappearance of "value" as compared to the semantics of unary plus...)
    >
    > Unless I'm mistaken, a won't be promoted (being an int), so there might
    > be no such thing as "the negative of its (promoted) operand"? I feel
    > like the standard tells me I might end up with an int worth 32768...
    > (still assuming 16 bit ints)? Or should I consider there is an implied
    > "if-it-fits-otherwise-overflow"?
    >
    > I couldn't find any help through google or in the FAQ, so I'd really
    > appreciate any clarification.


    I'm not going to help you comprehend the spec. There are a few other people
    here better at that than me. But, I can tell how the 16-bit and 32-bit
    compilers that I use work in this area. The 16-bit compilers will not
    convert -32768. It remains negative. But, they will convert -32767 (to -1)
    to +32767 (to +1). The 32-bit compilers convert -32768 to +32768.
    Basically, if it won't fit into the converted type, it doesn't get
    converted.


    Rod Pemberton
    Rod Pemberton, Feb 12, 2006
    #5
  6. Marc

    pete Guest

    pete wrote:
    >
    > Marc wrote:
    >
    > > int a;

    >
    > > -a;

    >
    > > "if-it-fits-otherwise-overflow"?

    >
    > Yes.
    > "overflow" as in "undefined behavior".
    >
    > It's a point of trivia which also comes up when writing itoa,
    > that there is no integer type which is guaranteed
    > to be able to represent the magnitude of INT_MIN.


    You can see what INT_MIN expands to on your implementation.
    It might be something like (-32767 - 1),
    if you have two's complement representation of negative integers.

    /* BEGIN new.c */

    #include <stdio.h>
    #include <limits.h>

    #define str(s) # s
    #define xstr(s) str(s)

    int main(void)
    {
    puts("INT_MIN is " xstr(INT_MIN));
    return 0;
    }

    /* END new.c */

    --
    pete
    pete, Feb 12, 2006
    #6
  7. Marc

    Marc Guest

    Eric Sosman wrote:
    [...]
    > When this sort of thing happens, another provision of the
    > Standard takes over:
    >
    > "If an _exceptional condition_ occurs during the
    > evaluation of an expression (that is, if the result
    > is not mathematically defined or not in the range of
    > representable values for its type), the behavior is
    > undefined." (6.5/5)
    >
    > So: If you try to negate (or take the absolute value of)
    > INT_MIN on a system where `INT_MIN + INT_MAX' is not zero, the
    > C language does not specify the outcome -- anything can happen,
    > at least in principle. The commonest behavior is that the
    > overflow is ignored, and the resulting representation (all ones)
    > is equal to INT_MIN again: INT_MIN is its own negation on most
    > two's-complement systems. However, this should be thought of
    > as a quirk of those systems, not as part of the C language.


    Ah yes ... 6.5/5 states exactly what I was looking for. Thanks a lot for
    the pointer - guess I still have a cover-to-cover reading to do ...

    As you and others suggested, the negation did work on our system, now I
    know for sure it was just "lucking-out" from a standard's point of view.

    Thanks all for the answers,

    Marc
    Marc, Feb 12, 2006
    #7
  8. Eric Sosman wrote:

    <snip: question about unary minus overflowing for INT_MIN>

    > Yes, two's complement is asymmetric about zero: there
    > is a negative number whose absolute value is not representable.
    > (The Standard actually permits an implementation to dodge this
    > asymmetry by defining "all ones" to be a trap representation;
    > I've never heard of an implementation that does so.)


    ITYM a 1 followed by all 0s. All ones is -1 in two's complement.
    Antonio Contreras, Feb 13, 2006
    #8
  9. Marc

    pete Guest

    Antonio Contreras wrote:
    >
    > Eric Sosman wrote:
    >
    > <snip: question about unary minus overflowing for INT_MIN>
    >
    > > Yes, two's complement is asymmetric about zero: there
    > > is a negative number whose absolute value is not representable.
    > > (The Standard actually permits an implementation to dodge this
    > > asymmetry by defining "all ones" to be a trap representation;
    > > I've never heard of an implementation that does so.)

    >
    > ITYM a 1 followed by all 0s. All ones is -1 in two's complement.


    He's talking about negative zero.
    A one followed by all zeros, is negative zero
    in sign and magnitude representation.
    All ones is negative zero in one's complement representation.
    There's different ways for an implementation
    to deal with negative zero, trapping is one of them.

    --
    pete
    pete, Feb 13, 2006
    #9
  10. pete wrote:
    > Antonio Contreras wrote:
    > >
    > > Eric Sosman wrote:
    > >
    > > <snip: question about unary minus overflowing for INT_MIN>
    > >
    > > > Yes, two's complement is asymmetric about zero: there
    > > > is a negative number whose absolute value is not representable.
    > > > (The Standard actually permits an implementation to dodge this
    > > > asymmetry by defining "all ones" to be a trap representation;
    > > > I've never heard of an implementation that does so.)

    > >
    > > ITYM a 1 followed by all 0s. All ones is -1 in two's complement.

    >
    > He's talking about negative zero.
    > A one followed by all zeros, is negative zero
    > in sign and magnitude representation.
    > All ones is negative zero in one's complement representation.
    > There's different ways for an implementation
    > to deal with negative zero, trapping is one of them.


    But he was talking about two's complement. And AFAIK the standard
    allows a two's complement representation with trap representations. In
    this case the obvious pattern for a trap representation is a 1 followed
    by all 0s, which implies that INT_MIN = - INT_MAX
    Antonio Contreras, Feb 13, 2006
    #10
  11. Marc

    pete Guest

    Antonio Contreras wrote:
    >
    > pete wrote:
    > > Antonio Contreras wrote:
    > > >
    > > > Eric Sosman wrote:
    > > >
    > > > <snip: question about unary minus overflowing for INT_MIN>
    > > >
    > > > > Yes, two's complement is asymmetric about zero: there
    > > > > is a negative number whose absolute value is not representable.
    > > > > (The Standard actually permits an implementation to dodge this
    > > > > asymmetry by defining "all ones" to be a trap representation;
    > > > > I've never heard of an implementation that does so.)
    > > >
    > > > ITYM a 1 followed by all 0s. All ones is -1 in two's complement.

    > >
    > > He's talking about negative zero.
    > > A one followed by all zeros, is negative zero
    > > in sign and magnitude representation.
    > > All ones is negative zero in one's complement representation.
    > > There's different ways for an implementation
    > > to deal with negative zero, trapping is one of them.

    >
    > But he was talking about two's complement. And AFAIK the standard
    > allows a two's complement representation with trap representations. In
    > this case the obvious pattern
    > for a trap representation is a 1 followed
    > by all 0s, which implies that INT_MIN = - INT_MAX


    Yes, I had missed the point.

    --
    pete
    pete, Feb 13, 2006
    #11
  12. Marc

    Jordan Abel Guest

    On 2006-02-12, pete <> wrote:
    > Marc wrote:
    >
    >> int a;

    >
    >> -a;

    >
    >> "if-it-fits-otherwise-overflow"?

    >
    > Yes.
    > "overflow" as in "undefined behavior".
    >
    > It's a point of trivia which also comes up when writing itoa,
    > that there is no integer type which is guaranteed
    > to be able to represent the magnitude of INT_MIN.


    Not unsigned int?
    Jordan Abel, Feb 13, 2006
    #12
  13. Marc

    Eric Sosman Guest

    Antonio Contreras wrote:
    > Eric Sosman wrote:
    >
    > <snip: question about unary minus overflowing for INT_MIN>
    >
    >> Yes, two's complement is asymmetric about zero: there
    >>is a negative number whose absolute value is not representable.
    >>(The Standard actually permits an implementation to dodge this
    >>asymmetry by defining "all ones" to be a trap representation;
    >>I've never heard of an implementation that does so.)

    >
    >
    > ITYM a 1 followed by all 0s. All ones is -1 in two's complement.


    Right you are. Sorry for the blunder.

    --
    Eric Sosman
    lid
    Eric Sosman, Feb 13, 2006
    #13
  14. Marc

    pete Guest

    Jordan Abel wrote:
    >
    > On 2006-02-12, pete <> wrote:
    > > Marc wrote:
    > >
    > >> int a;

    > >
    > >> -a;

    > >
    > >> "if-it-fits-otherwise-overflow"?

    > >
    > > Yes.
    > > "overflow" as in "undefined behavior".
    > >
    > > It's a point of trivia which also comes up when writing itoa,
    > > that there is no integer type which is guaranteed
    > > to be able to represent the magnitude of INT_MIN.

    >
    > Not unsigned int?


    No.
    The requirement is for the unsigned type to have
    at least as many value bits as the signed type.
    You can have:
    CHAR_BIT == 16
    sizeof(int) == 2
    UINT_MAX == 65535
    INT_MIN == -65536


    --
    pete
    pete, Feb 13, 2006
    #14
    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. Andrew Ward
    Replies:
    6
    Views:
    680
    Ron Natalie
    Sep 26, 2003
  2. Matthew  Cook
    Replies:
    6
    Views:
    500
  3. Sam Stephenson
    Replies:
    9
    Views:
    227
    Caleb Clausen
    Nov 7, 2005
  4. Todd Burch
    Replies:
    3
    Views:
    151
    Jonas Roberto de Goes Filho (sysdebug)
    Aug 27, 2007
  5. sreservoir

    unary minus strangeness

    sreservoir, Mar 28, 2010, in forum: Perl Misc
    Replies:
    7
    Views:
    116
    Ilya Zakharevich
    Apr 1, 2010
Loading...

Share This Page