efficiency concern: when to really use unsigned ints and when not to

N

Neil Zanella

Hello,

Often I happen to be dealing with nonnegative integers and since I know I won't
need negative numbers here I declare them as unsigned simply to make the program
somewhat clearer. Effectively, though, signed integers would often work too since
unless I am doing some modular arithmetic modulo the word length then I almost
never need to use the high bit since the integers I deal with are usually not
that large, and I would assume this is true of most programs in general.

So, the question is, when you know an integer is not going to be negative, is that
good enough reason to declare it as unsigned, or does doing so somewhat slow down
the computer (e.g. are signed addition, subtraction, etc... somewhat faster and
why would that be so?)?

Thanks,

Neil
 
R

Richard Heathfield

Neil said:
Hello,

Often I happen to be dealing with nonnegative integers and since I know I
won't need negative numbers here I declare them as unsigned simply to make
the program somewhat clearer.

So do I.
Effectively, though, signed integers would
often work too since unless I am doing some modular arithmetic modulo the
word length then I almost never need to use the high bit since the
integers I deal with are usually not that large, and I would assume this
is true of most programs in general.

Well, if your modulus happens to be 2 to the N, where N is the number of
value bits in the unsigned integer type, you're in luck. :)

But I presume you're talking about, say, day of week (modulo 7), month of
year (modulo 12), or perhaps (integral) angle in degrees (modulo 360). That
/sort/ of thing.
So, the question is, when you know an integer is not going to be negative,
is that good enough reason to declare it as unsigned,

IMHO, yes.
or does doing so
somewhat slow down the computer (e.g. are signed addition, subtraction,
etc... somewhat faster and why would that be so?)?

The Standard doesn't require unsigned integer types to go slower than signed
integer types.

If you are sure you'll never overflow the maximum value for the type, feel
free to use signed if you wish. I prefer to use unsigneds.
 
M

Mark A. Odell

(e-mail address removed) (Neil Zanella) wrote in

Often I happen to be dealing with nonnegative integers and since I know
I won't need negative numbers here I declare them as unsigned simply to
make the program somewhat clearer. Effectively, though, signed integers
would often work too since unless I am doing some modular arithmetic
modulo the word length then I almost never need to use the high bit
since the integers I deal with are usually not that large, and I would
assume this is true of most programs in general.

So, the question is, when you know an integer is not going to be
negative, is that good enough reason to declare it as unsigned, or does
doing so somewhat slow down the computer (e.g. are signed addition,
subtraction, etc... somewhat faster and why would that be so?)?

On small micros without sign-support hardware signed maybe slower, e.g.
the venerable 8051. However, unless you need instruction level determinism
I wouldn't worry about it. Make the vars. unsigned when the value is not
negative. For example, why would you ever need to express someone's age in
years as a signed value? Since we know better than to mix control with
data we wouldn't use a negative value for an error so I'd certainly expect
to see age declared as:

unsigned int ageInYears;

or

unsigned char ageInYears;
 
C

Christian Bau

Hello,

Often I happen to be dealing with nonnegative integers and since I know I
won't
need negative numbers here I declare them as unsigned simply to make the
program
somewhat clearer. Effectively, though, signed integers would often work too
since
unless I am doing some modular arithmetic modulo the word length then I
almost
never need to use the high bit since the integers I deal with are usually not
that large, and I would assume this is true of most programs in general.

So, the question is, when you know an integer is not going to be negative, is
that
good enough reason to declare it as unsigned, or does doing so somewhat slow
down
the computer (e.g. are signed addition, subtraction, etc... somewhat faster
and
why would that be so?)?

For signed integers, the C operators +, -, * produce exactly the same
results as the mathematical operators (as long as the results are not
too large). For unsigned integers, the C operators do some pretty weird
things. A trivial example: For which numbers is

x >= y - 1

true if x and y are both signed, both unsigned, one signed and the other
unsigned? For signed numbers, you are quite safe. Both unsigned, and
there is a strange special case for y = 0. One signed and the other
unsigned, and you have to study the C Standard.

It seems what you have are "positive" numbers. "unsigned" is something
completely different; unsigned numbers can behave in completely
unexpected ways. x - 1 is not one less than x in very common cases.

(And some people will be in for some nasty surprises if they switch to a
compiler where unsigned int and unsigned long have different sizes. )
 
K

Keith Thompson

Often I happen to be dealing with nonnegative integers and since I
know I won't need negative numbers here I declare them as unsigned
simply to make the program somewhat clearer. Effectively, though,
signed integers would often work too since unless I am doing some
modular arithmetic modulo the word length then I almost never need
to use the high bit since the integers I deal with are usually not
that large, and I would assume this is true of most programs in
general.

So, the question is, when you know an integer is not going to be
negative, is that good enough reason to declare it as unsigned, or
does doing so somewhat slow down the computer (e.g. are signed
addition, subtraction, etc... somewhat faster and why would that be
so?)?

There are some risks in using unsigned types. Consider:

int i;
for (i = 9; i >= 0; i --) { printf("%d\n", i); }

vs.

unsigned int u;
for (u = 9; u >= 0; u --) { printf("%u\n", u); }
 
J

Jack Klein

(e-mail address removed) (Neil Zanella) wrote in



On small micros without sign-support hardware signed maybe slower, e.g.
the venerable 8051

[snip]

<somewhat off topic>
I beg your pardon, but an 8051 has a carry flag and can performed
signed arithmetic with the same speed as unsigned arithmetic.

There are a lot of reasons to look down one's nose and the brain-dead
little work-horse, but this is not one of them.
</somewhat off topic>
 
J

Jack Klein

Hello,

Often I happen to be dealing with nonnegative integers and since I know I won't
need negative numbers here I declare them as unsigned simply to make the program
somewhat clearer. Effectively, though, signed integers would often work too since
unless I am doing some modular arithmetic modulo the word length then I almost
never need to use the high bit since the integers I deal with are usually not
that large, and I would assume this is true of most programs in general.

So, the question is, when you know an integer is not going to be negative, is that
good enough reason to declare it as unsigned, or does doing so somewhat slow down
the computer (e.g. are signed addition, subtraction, etc... somewhat faster and
why would that be so?)?

Thanks,

Neil

Speed or efficiency of operation is no different between pure signed
or unsigned types on any architecture developed in the last quarter
century at least.

There are pros and cons to using unsigned types.

One of the biggest pros is simpler range checking in functions.
Suppose for example that you have a function that can be properly
called with a value between 0 and 10, and it is the function's job to
validate the argument and return an error code if it is out of range.
Now look at the two functions below:

int s_func(signed int x)
{
if ((x >= 0) && (x <= 10))
{
/* do stuff */
return OK;
}
else
{
return ERROR;
}
}

Now the unsigned version, the checking is simpler:

int u_func(unsigned int x)
{
if (x <= 10)
--------

The biggest con to using unsigned is that you have to know what can
happen when mixing with signed or you can be unpleasantly surprised.

unsigned int x = 12;

if (x > -1)
{
puts("Yippee!");
}
else
{
puts("Ouch!");
}

The code above will output "Ouch!".
 
M

Martin Dickopp

Christian Bau said:
For signed integers, the C operators +, -, * produce exactly the same
results as the mathematical operators (as long as the results are not
too large).

ITYM as long as the absolute values of the results are not too large.
For unsigned integers, the C operators do some pretty weird
things. A trivial example: For which numbers is

x >= y - 1

true if x and y are both signed, both unsigned, one signed and the other
unsigned? For signed numbers, you are quite safe. Both unsigned, and
there is a strange special case for y = 0.

For signed ints, there is a strange special case for y = INT_MIN. With
unsigned integers, you have well-defined over/underflow semantics at
least, but as long as you stay within the range of the type, you are
safe with both signed and unsigned integers.

Martin
 
M

Martin Dickopp

Keith Thompson said:
There are some risks in using unsigned types. Consider:

int i;
for (i = 9; i >= 0; i --) { printf("%d\n", i); }

vs.

unsigned int u;
for (u = 9; u >= 0; u --) { printf("%u\n", u); }

Some compilers can even warn you of comparisons which are always true.
The latter case can be rewritten as, for example,

unsigned int u;
for (u = 10; u-- > 0;) { printf("%u\n", u); }

which uses unsigned integers and has the intended effect. :)

Martin
 
C

Christian Bau

Martin Dickopp said:
ITYM as long as the absolute values of the results are not too large.


For signed ints, there is a strange special case for y = INT_MIN. With
unsigned integers, you have well-defined over/underflow semantics at
least, but as long as you stay within the range of the type, you are
safe with both signed and unsigned integers.

Which case happens more often, INT_MIN or 0?
 
C

Christian Bau

Martin Dickopp said:
Some compilers can even warn you of comparisons which are always true.
The latter case can be rewritten as, for example,

unsigned int u;
for (u = 10; u-- > 0;) { printf("%u\n", u); }

which uses unsigned integers and has the intended effect. :)

Yes, I have the pleasure to use one f***ing compiler that doesn't let me
write

if (x >= 0 && x <= 10)

if x is an unsigned value without giving a warning.
 
M

Martin Dickopp

Christian Bau said:
Which case happens more often, INT_MIN or 0?

I fully agree with you that if there is a risk of "underflowing" an
unsigned integer (and the wrap-around behavior is not deliberately
wanted), a signed integer type should be used. However, IMHO unsigned
integers should be used when there's no such risk.

Perhaps the programmer has to think more carefully when using unsigned
integers, and yet more carefully when mixing them with signed integers.
I consider this a good thing.

When I was just beginning to learn programming and C, I did in fact
write a `while (n >= 0)' loop, where `n' was an unsigned integer (and
the compiler I used at that time did /not/ warn about it). When I saw
my mistake, I didn't conclude that I should just avoid unsigned integers
(either in this special case or in general), but that I should think
again what I'm doing.

Martin
 
M

Martin Dickopp

Christian Bau said:
Yes, I have the pleasure to use one f***ing compiler that doesn't let me
write

if (x >= 0 && x <= 10)

if x is an unsigned value without giving a warning.

Well, I have the pleasure to use a fine compiler that has a command line
option to switch the warning on or off. :)

Martin
 
P

pete

Christian said:
Yes, I have the pleasure to use one
f***ing compiler that doesn't let me write

if (x >= 0 && x <= 10)

if x is an unsigned value without giving a warning.

I don't understand the reason for the deletable expletive.
The warning was good and proper and useful and caused you to
change your meaningless code, right ?
 
M

Mark A. Odell

<somewhat off topic>
I beg your pardon, but an 8051 has a carry flag and can performed
signed arithmetic with the same speed as unsigned arithmetic.

There are a lot of reasons to look down one's nose and the brain-dead
little work-horse, but this is not one of them.

True it has a carry flag and that means extra instructions to check it
when using signed integers. When using unsigned integers, no assy. is
produced to check the carry flag.
 
N

nrk

Christian said:
Yes, I have the pleasure to use one f***ing compiler that doesn't let me
write

if (x >= 0 && x <= 10)

if x is an unsigned value without giving a warning.

Ok, you've lost me. If x is unsigned why would you ever want to check a
tautology x >= 0? I think your compiler is doing a fine job, and its you
who's effing up :)

-nrk.
 
D

Dan Pop

In said:
Often I happen to be dealing with nonnegative integers and since I know I won't
need negative numbers here I declare them as unsigned simply to make the program
somewhat clearer. Effectively, though, signed integers would often work too since
unless I am doing some modular arithmetic modulo the word length then I almost
never need to use the high bit since the integers I deal with are usually not
that large, and I would assume this is true of most programs in general.

Signed integers and unsigned integers are fairly different beasts,
intended for different purposes. Avoid unsigned integers unless you need
their special semantics (or the additional range), even if you're only
manipulating positive values. After all, the prototype of main() isn't

int main(unsigned argc, char **argv);

despite the fact that argc is not supposed to have negative values.

If it's intended for usual arithmetic operations, use signed integer.
If it's intended for bit manipulation operations and/or modulo arithmetic,
use unsigned integer.

Avoid as much as possible mixing the two flavours in the same
expression, because very nasty bugs may arise.

The fact that size_t is unsigned is a real pain in the ass, because this
type is seldom used in a genuine unsigned context. It should have been
signed, for the same reason that argc is signed.
So, the question is, when you know an integer is not going to be negative, is that
good enough reason to declare it as unsigned,
Nope.

or does doing so somewhat slow down
the computer (e.g. are signed addition, subtraction, etc... somewhat faster and
why would that be so?)?

Speed is not a concern. On two's complement architectures, the two are
usually handled identically. It's the intended purpose of the variable
that dictates the choice (again, unless you need the extra range provided
by the unsigned flavour, but this doesn't seem to be the case).

Dan
 
D

Dan Pop

In said:
True it has a carry flag and that means extra instructions to check it
when using signed integers.

Why do you need to check it when using signed integers? The carry flag
*must* be taken into account when doing both signed and unsigned
arithmetic on multi-byte operands, but this is usually achieved by using
the "add with carry" instruction, not by checking the carry flag.
When using unsigned integers, no assy. is
produced to check the carry flag.

And what kind of assembly is generated to check the carry flag when using
signed integers? Do the 8051 compilers bother to check for signed
integer overflow? I'd be really surprised...

Dan
 
C

Christian Bau

pete said:
I don't understand the reason for the deletable expletive.
The warning was good and proper and useful and caused you to
change your meaningless code, right ?

Completely brainlessly wrong. The code checked that the value of a
variable was in a certain constant range. If I want to know whether a
value x is in a range from a to b then I write "if (x >= a && x <= b)".
It is absolutely idiotic to have a special case for a = 0.

Changing the code would have created maintenance problems: If a variable
can hold values lets say from 0 to 100, then any integer type whether
signed or unsigned can hold all the values. However, changing the type
from unsigned to signed makes the code incorrect if the test x >= 0 is
missing.
 
C

Christian Bau

nrk said:
Ok, you've lost me. If x is unsigned why would you ever want to check a
tautology x >= 0? I think your compiler is doing a fine job, and its you
who's effing up :)

When checking whether "minimum value" <= x <= "maximum value", why would
I want to make a special case for "minimum value" = 0?

File header.h:
#define MIN_VALUE 0 // Or any other value
#define MAX_VALUE 99 // Or any other value

File mycode.c:
#include "header.h"
int in_range (unsigned int x) {
#if MIN_VALUE <= 0
return x <= MAX_VALUE;
#else
return x >= MIN_VALUE && x <= MAX_VALUE;
#endif
}

Is that how you would want to write code?
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top