Topic: comparing signed and unsigned integral values


Author: allan_w@my-dejanews.com (Allan W)
Date: Mon, 30 Dec 2002 20:59:48 +0000 (UTC)
Raw View
georg@nospam.ucar.edu ("Georg D.") wrote
> The Standard says there are integral conversions (4.7) and what shall
> happen if the destination is signed or unsigned, but I could not find
> specification for the destination type of parameters of global comparison
> operators, e.g. "bool operator < (???, ???)".
>
> e.g. "-1 < 2294967295"   -> false (32-bit int)
> with warning: comparing signed and unsigned values.

This is correct, but probably not what you intended (thus the warning).

-1 is a signed int. Presumably on a 32-bit computer, 2294967295 is an
unsigned long.

> Q1: I'd like to understand which conversions are "performed" prior to
> comparison.

See 5/9 (NOT 5.9):
    ... if either operand is unsigned long, the other shall be
        converted to unsigned long.

> I'd like to read your comments on this and/or get links to existing
> comments or discussions.

I've heard C++'s rules described as "preserved unsignedness." In other
words, if one of your variables is unsigned, your comparisons will be
unsigned.

Frankly, even in most assembly languages, I doubt you could do the
comparison you want without making two tests; one to compare the
signed quantity to zero, and the other to compare it as if it was
unsigned. So if you overload global or namespace functions to do the
comparison you want, you won't be losing anything...

   namespace georg {
      // It's sufficient to define these in terms of
      // signed and unsigned long, since all other
      // integral types can convert to one of these with no loss.
      // Otherwise we'd need 81 of these functions (for every
      // combination of signed/unsigned char/short/int/long,
      // plus "plain char").
      bool lessthan(  signed long lhs,   signed long rhs)
         { return          lhs<rhs; }
      bool lessthan(unsigned long lhs, unsigned long rhs)
         { return          lhs<rhs; }
      bool lessthan(unsigned long lhs,   signed long rhs)
         { return rhs>0 && lhs<rhs; }
      bool lessthan(  signed long lhs, unsigned long rhs)
         { return lhs<0 || lhs<rhs; }
   }

   int main() { std::cout << georg::lessthan(-1, 2294967295); } // True

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: nobody@localhost.ucar.edu (nobody)
Date: Tue, 31 Dec 2002 05:42:10 +0000 (UTC)
Raw View
Allan W wrote:
> I've heard C++'s rules described as "preserved unsignedness." In other
> words, if one of your variables is unsigned, your comparisons will be
> unsigned.

That's not quite true.  C++ (and also ANSI C, from which the C++ rules
were inherited) requires that conversions be value-preserving whenever
possible.  For example, in a mixed expression containing int and
unsigned short everything will be promoted to int if possible, i.e.,
if sizeof(int) > sizeof(short);  but it sizeof(short) = sizeof(int)
everything gets promoted to unsigned int.  K&R C's rules, which were
unsigned-preserving, would have everything promoted to unsigned int
no matter what.

I know why the language is the way it is, but I often find myself
wishing that the rules were different and that all the integral
types had to be subranges of a signed type of maximum size so
that all conversions would be value-preserving.

nobody

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: philippe_mori@hotmail.com ("Philippe Mori")
Date: Thu, 26 Dec 2002 21:28:38 +0000 (UTC)
Raw View
In this case (I'm not sure what would be the rule if longs are 64 bit), both
values would be converted to unsigned before the comparison and -1 will
become a really big number and the comparison won't give the expected
result...

In pratice this is often the case when comparing signed and unsigned value,
we do not get the expected result.

For constants, I think that they are signed except when they do not fit the
range of signed value. The constant would be considered unsigned...

I do not think this could be easily changed. The best thing to do is to
properly select the appropraite type for your constants and variables
(either all signed or all unsigned). In some case, unsigned value could be
converted to signed value explicitly because we knows that it is not
probable to have a value bigger than the range of an unsigned. Better yet,
validate it before doing the conversion.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: nagle@animats.com (John Nagle)
Date: Fri, 27 Dec 2002 21:02:30 +0000 (UTC)
Raw View
===================================== MODERATOR'S COMMENT:
 Please try not to quote moderation footers when posting.


===================================== END OF MODERATOR'S COMMENT
   I once wrote a paper titled "Type Integer Considered Harmful".
But it was too radical.  I addressed this issue by viewing
numeric types as ranges, and insisting that the compiler choose
intermediate types in expressions such that overflow in a
compiler-sized temporary was impossible unless an overflow in
the programmer-sized result was inevitable.  This usually
doesn't result in multiple-precision arithmetic, and when
it does, you needed it.  The "size of the machine" would
then no longer be visible to the programmer.

   Too radical, and, once the ones-complement and the
36-bit machines died off, unnecesssary.

     John Nagle
     Animats

Philippe Mori wrote:

> In this case (I'm not sure what would be the rule if longs are 64 bit), both
> values would be converted to unsigned before the comparison and -1 will
> become a really big number and the comparison won't give the expected
> result...
>
> In pratice this is often the case when comparing signed and unsigned value,
> we do not get the expected result.
>
> For constants, I think that they are signed except when they do not fit the
> range of signed value. The constant would be considered unsigned...
>
> I do not think this could be easily changed. The best thing to do is to
> properly select the appropraite type for your constants and variables
> (either all signed or all unsigned). In some case, unsigned value could be
> converted to signed value explicitly because we knows that it is not
> probable to have a value bigger than the range of an unsigned. Better yet,
> validate it before doing the conversion.
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]
>
>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: noway@jose.dude (Electric Ninja)
Date: Thu, 26 Dec 2002 16:39:33 +0000 (UTC)
Raw View
Personally I wouldn't like blanket functions that cover all attempts to
compare signed and unsigned integers.  Sometimes an unsigned value is small
and lends itself to comparison with a signed value.  But sometimes it's huge
and leaves room for debate.

I say just use a (int) typecast where necessary, or *try* to use signed
types across the board... no shame in that.

""Georg D."" <georg@nospam.ucar.edu> wrote in message
news:f6aM9.81569$TA6.1061548@news.chello.at...
> Hi,
>
> The Standard says there are integral conversions (4.7) and what shall
> happen if the destination is signed or unsigned, but I could not find
> specification for the destination type of parameters of global comparison
> operators, e.g. "bool operator < (???, ???)".
>
> e.g. "-1 < 2294967295"   -> false (32-bit int)
> with warning: comparing signed and unsigned values.
>
> Q1: I'd like to understand which conversions are "performed" prior to
> comparison.
>
> Q2: while comparing signed and unsigned values could have a more
> acceptable semantics, a C++ compiler will reject
>
>     bool operator <(int x, unsigned y)
>     {
>         return x < 0 || (unsigned) x < y;
>     }
>
>     bool operator <(unsigned x, int y)
>     {
>         return y > 0 && x < (unsigned) y;
>     }
>
> with " 'operator <(int,unsigned int)' must be a member function or have a
> parameter of class type" (Standard: 13.5/6)
>
> I'd like to read your comments on this and/or get links to existing
> comments or discussions.
>
> TIA,
> Georg
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]
>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: georg@nospam.ucar.edu ("Georg D.")
Date: Thu, 19 Dec 2002 04:08:20 +0000 (UTC)
Raw View
Hi,

The Standard says there are integral conversions (4.7) and what shall
happen if the destination is signed or unsigned, but I could not find
specification for the destination type of parameters of global comparison
operators, e.g. "bool operator < (???, ???)".

e.g. "-1 < 2294967295"   -> false (32-bit int)
with warning: comparing signed and unsigned values.

Q1: I'd like to understand which conversions are "performed" prior to
comparison.

Q2: while comparing signed and unsigned values could have a more
acceptable semantics, a C++ compiler will reject

    bool operator <(int x, unsigned y)
    {
        return x < 0 || (unsigned) x < y;
    }

    bool operator <(unsigned x, int y)
    {
        return y > 0 && x < (unsigned) y;
    }

with " 'operator <(int,unsigned int)' must be a member function or have a
parameter of class type" (Standard: 13.5/6)

I'd like to read your comments on this and/or get links to existing
comments or discussions.

TIA,
Georg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]