why unsigned int?

N

none

I often come across functions that takes an unsigned int as argument:

void somefunction(unsigned int i) {



}


I have also seen it used as template parameter for template classes:

template<typename T, unsigned int D=3>
class SomeClass {

};

Why use unsigned int in this context and not just int?
 
D

D. Stussy

none said:
I often come across functions that takes an unsigned int as argument:

void somefunction(unsigned int i) {
}

I have also seen it used as template parameter for template classes:

template<typename T, unsigned int D=3>
class SomeClass {

};

Why use unsigned int in this context and not just int?

Because negative values have no meaning in the context....
 
K

Kai-Uwe Bux

none said:
I often come across functions that takes an unsigned int as argument:

void somefunction(unsigned int i) { [...]
}


I have also seen it used as template parameter for template classes:

template<typename T, unsigned int D=3>
class SomeClass {

};

Why use unsigned int in this context and not just int?

You have actually not provided context. Sometimes, but not always, unsigned
int is better, sometimes but not always int is better, and there might even
be cases where one could go one way or the other without significant
difference. But, "SomeClass" is just not enough context to say _why_
unsigned would be better.

E.g.:

unsigned int number_of_bits_set ( unsigned int n ) {
...
}

could take an unsigned argument to ensure platform independence and to allow
for an easier portable implementation (signed integers can be represented in
two different ways on the bit-level).


Best

Kai-Uwe Bux
 
Ö

Öö Tiib

I often come across functions that takes an unsigned int as argument:

void somefunction(unsigned int i) {

}

I have also seen it used as template parameter for template classes:

template<typename T, unsigned int D=3>
class SomeClass {

};

Why use unsigned int in this context and not just int?

But you did not post context. Context is how variable is used. Like
for example as right operand of bitwise shift operation. It does
*never* make sense to have negative value there.
 
M

Marcel Müller

Öö Tiib said:
But you did not post context. Context is how variable is used. Like
for example as right operand of bitwise shift operation. It does
*never* make sense to have negative value there.

Well, an extended definition of shift operators may change the direction
in this case. Of, course the standard C++ operators do not.

However, there are many situations where a value must be a natural
number. Think about the length of a string or the number of elements in
an array or container or any other countable object.
One advantage of using unsigned integers in this cases is that you
usually need only one comparison to verify the validity of a value. E.g.:

unsigned index;
std::string str;
....
if (index >= str.length())
// Error
...

If you use singed int you have to check against zero too in general, to
avoid undefined behavior.

Of course, there are platforms where unsigned integers are slow, because
they are not supported by the hardware natively.


Marcel
 
Ö

Öö Tiib

Well, an extended definition of shift operators may change the direction
in this case. Of, course the standard C++ operators do not.

Yes. Especially because of that. Otherwise some inexperienced
maintainer might imagine it as extended.
However, there are many situations where a value must be a natural
number. Think about the length of a string or the number of elements in
an array or container or any other countable object.
One advantage of using unsigned integers in this cases is that you
usually need only one comparison to verify the validity of a value. E.g.:

unsigned index;
std::string str;
...
if (index >= str.length())
   // Error
   ...

If you use singed int you have to check against zero too in general, to
avoid undefined behavior.

That is the only significant advantage of using unsigned there but
that has been discussed to death. Lot of people for some reason prefer
-1 instead of 4294967295 there ... and since both are wrong values i
am indifferent. I am sure that reverse cycles using unsigned that way
may confuse the crap out of beginners however:

std::string str("Noob trap");
for ( unsigned i = str.size()-1; i < str.size(); --i )
{
str += 13;
}
Of course, there are platforms where unsigned integers are slow, because
they are not supported by the hardware natively.

Yes, but on typical PC the division with constant is quicker for
unsigned (and so %). Conversion to float is quicker with signed. Rest
of the things are more or less at same speed. Also that speed is
*fast* in general so that is bad idea to adjust your type usage before
you have reasons to improve performance. Competitors throw something
together in python at same time and get the order while you ponder
about things that do not matter.
 
K

Kai-Uwe Bux

Öö Tiib wrote:

[...]
I am sure that reverse cycles using unsigned that way
may confuse the crap out of beginners however:

std::string str("Noob trap");
for ( unsigned i = str.size()-1; i < str.size(); --i )
{
str += 13;
}

[...]

That reminds me: when I first had to iterate backwards using unsigned int,
the above was the first idea that popped into my mind. When I posted it
here, somebody called it "evil" (I think) and taught me a more friendly
idiom:

for ( size_type i = str.size(); i-- > 0; ) {
...
}

At least, that does not rely on wrapping.


Best

Kai-Uwe Bux
 
Ö

Öö Tiib

Öö Tiib wrote:

[...]> I am sure that reverse cycles using unsigned that way
may confuse the crap out of beginners however:
    std::string str("Noob trap");
    for ( unsigned i = str.size()-1; i < str.size(); --i )
    {
        str += 13;
    }


[...]

That reminds me: when I first had to iterate backwards using unsigned int,
the above was the first idea that popped into my mind. When I posted it
here, somebody called it "evil" (I think) and taught me a more friendly
idiom:

  for ( size_type i = str.size(); i-- > 0; ) {
    ...
  }

At least, that does not rely on wrapping.


Sure it is certainly less evil because smarter beginners can read it
out. Unless someone applies geek-beautifying like:

for ( size_type i = str.size(); i --> 0; ) {
...
}

Then explain what does operator-->(). Other thing is that it uses
operands with side-effects for comparison operator. That is something
that some policies forbid.
 
A

Alf P. Steinbach

* Öö Tiib, on 21.05.2010 00:10:
Well, an extended definition of shift operators may change the direction
in this case. Of, course the standard C++ operators do not.

Yes. Especially because of that. Otherwise some inexperienced
maintainer might imagine it as extended.
However, there are many situations where a value must be a natural
number. Think about the length of a string or the number of elements in
an array or container or any other countable object.
One advantage of using unsigned integers in this cases is that you
usually need only one comparison to verify the validity of a value. E.g.:

unsigned index;
std::string str;
...
if (index>= str.length())
// Error
...

If you use singed int you have to check against zero too in general, to
avoid undefined behavior.

That is the only significant advantage of using unsigned there but
that has been discussed to death. Lot of people for some reason prefer
-1 instead of 4294967295 there ... and since both are wrong values i
am indifferent. I am sure that reverse cycles using unsigned that way
may confuse the crap out of beginners however:

std::string str("Noob trap");
for ( unsigned i = str.size()-1; i< str.size(); --i )
{
str += 13;
}
Of course, there are platforms where unsigned integers are slow, because
they are not supported by the hardware natively.


I think one can safely ignore the ENIACs...

But without proper support in place (a suitable general signed type, wrapper
functions for obtaining sizes, start-pointers and end-pointers of collections
and arrays) using signed integers can be a little laborious.

Proper support constitutes very little code, though. I wrote up about it here:
<url:
http://alfps.wordpress.com/2010/05/10/how-to-avoid-disastrous-integer-wrap-around/>



Cheers, & enjoy,

- Alf
 
Ö

Öö Tiib

But without proper support in place (a suitable general signed type, wrapper
functions for obtaining sizes, start-pointers and end-pointers of collections
and arrays) using signed integers can be a little laborious.

Proper support constitutes very little code, though. I wrote up about it here:
<url: http://alfps.wordpress.com/2010/05/10/how-to-avoid-disastrous-integer-wrap-around/>

Yes, wrappers like that are probably needed to use signed values as
indexes.

It is maybe good to add that static_cast between signed and unsigned
integral types of same size takes 0 clock cycles on most popular
platforms (so that your progrock::cppx::size() has likely excellent
performance). ;)
 
V

Vladimir Jovic

Kai-Uwe Bux said:
[...]

That reminds me: when I first had to iterate backwards using unsigned int,
the above was the first idea that popped into my mind. When I posted it
here, somebody called it "evil" (I think) and taught me a more friendly
idiom:

for ( size_type i = str.size(); i-- > 0; ) {
...
}

Also known as the "goes to" operator :>

But it is like this :
for ( size_type i = str.size(); i --> 0; ) {
...
}
 
J

James Kanze

Öö Tiib wrote:
[...]> I am sure that reverse cycles using unsigned that way
may confuse the crap out of beginners however:
std::string str("Noob trap");
for ( unsigned i = str.size()-1; i < str.size(); --i )
{
str += 13;
}

[...]
That reminds me: when I first had to iterate backwards using
unsigned int, the above was the first idea that popped into
my mind. When I posted it here, somebody called it "evil" (I
think) and taught me a more friendly idiom:
for ( size_type i = str.size(); i-- > 0; ) {
...
}
At least, that does not rely on wrapping.

Sure it is certainly less evil because smarter beginners can
read it out. Unless someone applies geek-beautifying like:
for ( size_type i = str.size(); i --> 0; ) {
...
}
Then explain what does operator-->(). Other thing is that it
uses operands with side-effects for comparison operator. That
is something that some policies forbid.

And of course, there'll always be someone who'll convert it to
prefix decrementation, because somewhere, there's a rule to
prefer prefix to postfix.

In such cases, I'll just use a while:

size_t i = str.size();
while ( i != 0 ) {
-- i;
// ...
}
 
Ö

Öö Tiib

Are you sure.  I think on a typical PC today, division is
a single clock, regardless of the type.

I have to confess i haven't studied the differences between anyway
quick things much recently, usually improving bigger issues (with
threads and algorithms) helps lot more ... but this is like quite
recent Intels optimization manual ... http://www.intel.com/assets/pdf/manual/248966.pdf

It says somewhere things like:
throughput of IDIV with 64-bit operand are significantly slower than
those with 32-bit operand. Latency of DIV is similar to IDIV.
Generally, the latency of DIV may be one cycle less.
 
K

Keith H Duggar

Are you sure. I think on a typical PC today, division is
a single clock, regardless of the type.

No. For example the following

int halfi ( int x ) { return x / 2 ; }
unsigned halfu ( unsigned x ) { return x / 2 ; }

compiled with

g++ --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5493)
Copyright (C) 2005 Free Software Foundation, Inc.

g++ -O3 -S

yields the following (cleaned up)

__Z5halfii:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
leave
movl %edx, %eax
shrl $31, %eax
addl %edx, %eax
sarl %eax
ret

__Z5halfuj:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
leave
shrl %eax
ret

Notice the int divide compiles to 3 Intel arithemtic instructions
and an extra move compared to the single instruction for unsigned.

KHD
 
A

Alf P. Steinbach

* Keith H Duggar, on 21.05.2010 20:54:
No. For example the following

int halfi ( int x ) { return x / 2 ; }
unsigned halfu ( unsigned x ) { return x / 2 ; }

compiled with

g++ --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5493)
Copyright (C) 2005 Free Software Foundation, Inc.

g++ -O3 -S

yields the following (cleaned up)

__Z5halfii:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
leave
movl %edx, %eax
shrl $31, %eax
addl %edx, %eax
sarl %eax
ret

__Z5halfuj:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
leave
shrl %eax
ret

Notice the int divide compiles to 3 Intel arithemtic instructions
and an extra move compared to the single instruction for unsigned.

As I recall there is SAR (Shift Arithmetic Right, signed div by 2) and SHR
(Shift Right, unsigned div by 2).

It seems you haven't turned on optimization, or compiler stupid, or my memory is
faulty (again), or, Intel has somehow turned those two instructions into
multiple clock cycle monstrosities?


Cheers,

- Alf
 
K

Kai-Uwe Bux

Leigh said:
SAR is not sufficient as SAR(-1) == -1 which is obviously wrong, -1/2 = 0
not -1

Just a nit: (-1)/2 == 0 is not guaranteed by the standard: the sign of the
remainder is implementation defined (that the quotient be rounded toward 0
is recommended is a footnote but not required). [5.6/4]

Nonetheless, in the above code, the compiler has to make sure that this use
of shifting implements the division by 2 properly (i.e. in accordance with
the implementation defined rules). As you point out, that explains the need
for the additional instructions.


Best

Kai-Uwe Bux
 
P

Paul Bibbings

Leigh Johnston said:
Kai-Uwe Bux said:
Just a nit: (-1)/2 == 0 is not guaranteed by the standard: the sign of the
remainder is implementation defined (that the quotient be rounded toward 0
is recommended is a footnote but not required). [5.6/4]

"with any fractional part discarded" in the main standard text

You appear to be quoting from the C++0x FCD which is, of course, not The
Standard yet (unless there was a change to this effect between C++98 and
C++03, only the former of which I have access to at the present).

Regards

Paul Bibbings
 
P

Paul Bibbings

Leigh Johnston said:
Paul Bibbings said:
Leigh Johnston said:
Just a nit: (-1)/2 == 0 is not guaranteed by the standard: the
sign of the
remainder is implementation defined (that the quotient be rounded
toward 0
is recommended is a footnote but not required). [5.6/4]


"with any fractional part discarded" in the main standard text

You appear to be quoting from the C++0x FCD which is, of course, not The
Standard yet (unless there was a change to this effect between C++98 and
C++03, only the former of which I have access to at the present).

Regards

Paul Bibbings

Yes I was, the draft C standard has similar wording too which is why I
assumed it was older wording but it looks like C guys and C++ guys are
working in unison on this point (assuming you are correct, could you
cite the current standard which I don't have?). Either way the next
revision of the standard should put any retarded implementations which
evaluate -1/2 as -1 to bed. :)

[expr.mul]/4

"The binary / operator yields the quotient, and the binary % operator
yields the remainder from the division of the first expression by the
second. If the second operand of / or % is zero the behavior is
undefined; otherwise (a/b)*b + a%b is equal to a. If both operands are
nonnegative then the remainder is nonnegative; if not, the sign of the
remainder is implementation-defined 74)."

74) "According to work underway toward the revision of ISO C, the
preferred algorithm for integer division follows the rules defined
in the ISO Fortran standard, ISO/IEC 1539:1991, in which the
quotient is always rounded towards zero."

This is according to C++98. I don't have access immediately to C++03,
and so I don't know what the implications are for the possibility of
this having changed in the 5 intervening years, particularly given the
intention expressed in the footnote.

Regards

Paul Bibbings
 
K

Kai-Uwe Bux

Leigh said:
Paul Bibbings said:
Leigh Johnston said:
Just a nit: (-1)/2 == 0 is not guaranteed by the standard: the sign of
the
remainder is implementation defined (that the quotient be rounded
toward 0
is recommended is a footnote but not required). [5.6/4]


"with any fractional part discarded" in the main standard text

You appear to be quoting from the C++0x FCD which is, of course, not The
Standard yet (unless there was a change to this effect between C++98 and
C++03, only the former of which I have access to at the present).

Regards

Paul Bibbings

Yes I was, the draft C standard has similar wording too which is why I
assumed it was older wording but it looks like C guys and C++ guys are
working in unison on this point (assuming you are correct, could you cite
the current standard which I don't have?).

Current [5.6/4] in C++03:

The binary / operator yields the quotient, and the binary % operator yields
the remainder from the division of the first expression by the second. If
the second operand of / or % is zero the behavior is undefined; otherwise
(a/b)*b + a%b is equal to a. If both operands are nonnegative then the
remainder is nonnegative; if not, the sign of the remainder is
implementation-defined.
Either way the next revision of the standard should put any retarded
implementations which evaluate -1/2 as -1 to bed. :)

It's not retarded, it makes it so that a % 2 is always 0 or 1.


Best

Kai-Uwe Bux
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,262
Messages
2,571,049
Members
48,769
Latest member
Clifft

Latest Threads

Top