Subtracting unsigned entities

  • Thread starter fred.l.kleinschmidt
  • Start date
F

fred.l.kleinschmidt

If one knows that x and y are unsigned integers (of unknown size -
they may be short, int, long, long long), what is the most portable
way to determine their difference?

If x is smaller than y, then x-y is negative.

A naive approach is
if ( x > y ) {
...
}

but a compiler may code (x>y) as (x-y > 0).
 
B

Ben Pfaff

If one knows that x and y are unsigned integers (of unknown size -
they may be short, int, long, long long), what is the most portable
way to determine their difference?

If x is smaller than y, then x-y is negative.

Mathematically, yes. But in C, the difference of two values of
type unsigned int is always nonnegative.
A naive approach is
if ( x > y ) {
...
}

but a compiler may code (x>y) as (x-y > 0).

No, the compiler is obliged to produce the correct result.
 
T

Tomás Ó hÉilidhe

If one knows that x and y are unsigned integers (of unknown size -
they may be short, int, long, long long), what is the most portable
way to determine their difference?


Let's take an example:

unsigned x, y;

x = 65530u;
y = 655u;

The difference between these two is 64875.

If you do (x-y), you'll get 64875u. However if you do (y-x), you'll
get an implementation-defined value which depends on the value of
UINT_MAX (because when you go past zero you'll start counting backward
from UINT_MAX).

If x is smaller than y, then x-y is negative.

A naive approach is
   if ( x > y ) {
      ...
   }

but a compiler may code (x>y) as  (x-y > 0)


The if method is the only one that comes to mind.
 
B

Bart

If one knows that x and y are unsigned integers (of unknown size -
they may be short, int, long, long long), what is the most portable
way to determine their difference?

If x is smaller than y, then x-y is negative.

A naive approach is
   if ( x > y ) {
      ...
   }

but a compiler may code (x>y) as  (x-y > 0).

What do you mean by difference?

If you mean x-y, then this will give strange results when x<y (it
can't be negative).

If you mean max(x,y)-min(x,y) then your 'naive' approach will likely
work well.
 
P

Peter Nilsson

Subtraction. Though that need not be the minimum 'distance'
metric.
What do you mean by difference?

If you mean x-y, then this will give strange results when x<y (it
can't be negative).

It can in some circumstances, e.g. USHRT_MAX < INT_MAX.
 
C

Chris Dollin

If one knows that x and y are unsigned integers (of unknown size -
they may be short, int, long, long long), what is the most portable
way to determine their difference?

If x is smaller than y, then x-y is negative.

A naive approach is
if ( x > y ) {
...
}

but a compiler may code (x>y) as (x-y > 0).

It might code it as `x + 17`, too, but if it wants to be correct
both decisions would be suspect.
 
F

fred.l.kleinschmidt

What do you mean by difference?

If you mean x-y, then this will give strange results when x<y (it
can't be negative).

If you mean max(x,y)-min(x,y) then your 'naive' approach will likely
work well.

The problem came up on a Unix platform, where some code was trying
to check for a double-click. Each time button1 is clicked, it checks
the time with the previous time it was clicked; if the difference is
small enough, a double-click is assumed.

The times are stored in a variable of type Time, defined as
an unsigned int on some platforms, unsigned long on others, storing
clock time in milliseconds.

For an unsigned int, the value will wrap every 47 days. The original
code was

if ( (newtime - oldtime) < doubleclicktime ) {
/* perform double-click action */
}

That code is unsafe: as oldtime approaches UINT_MAX, the risk
is that newtime might occur after time wraps, thus might be
a small integer, and (newtime - oldtime) is mathematically
negative.

Since others have said that the compiler is obliged to
perform the if-test properly, my solution is

if ( t2 > t1 ) {
delta = t2 - t1;
}
else {
delta = (UINT_MAX - t1) + t2 + 1;
}
 
C

Chris Dollin

Since others have said that the compiler is obliged to
perform the if-test properly, my solution is

if ( t2 > t1 ) {
delta = t2 - t1;
}
else {
delta = (UINT_MAX - t1) + t2 + 1;
}

Not
if (t2 > t1) delta = t2 - t1;
else delta = t1 - t2;

? Because that seems simpler and at least as correct.

(Of course I'd write it as

delta = t2 > t1 ? t2 - t1 : t1 - t2;

)
 
Ø

Øyvind Røtvold

For an unsigned int, the value will wrap every 47 days. The original
code was

if ( (newtime - oldtime) < doubleclicktime ) {
/* perform double-click action */
}

That code is unsafe:
No.

as oldtime approaches UINT_MAX, the risk
is that newtime might occur after time wraps, thus might be
a small integer,
Yes.

and (newtime - oldtime) is mathematically negative.

If newtime and oldtime are of the same unsigned type, the result will
never be negative, and (newtime - oldtime) will be the correct time
difference even when there's a wrap. Assuming ofcourse that the timer
wraps correctly, this will work in any kind of modulo arithmetic.
Whoever made this code originally probably knew what he was doing.

[ snip ]
 
H

Harald van Dijk

If newtime and oldtime are of the same unsigned type, the result will
never be negative, and (newtime - oldtime) will be the correct time
difference even when there's a wrap.

If newtime and oldtime are of the same unsigned type, *and that unsigned
type is unsigned int or wider*, then yes. It is unsigned int here,
apparently, so then it is safe, but it's not safe with smaller unsigned
types. If they were of type unsigned short, for example, it's very well
possible for newtime - oldtime to produce a negative result, because
newtime and oldtime will be promoted, typically to signed int, before any
subtraction takes place.
 

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,781
Messages
2,569,616
Members
45,306
Latest member
TeddyWeath

Latest Threads

Top