Dealing with wrap-around in unsigned differences

N

Noob

Hello,

I've come across the following macro:

/** Get the absolute difference between 2 u32_t values (correcting overflows)
* 'a' is expected to be 'higher' (without overflow) than 'b'. */
#define FOO_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))

(u32_t is equivalent to uint32_t)

In my opinion, the entire macro reduces to ((a)-(b)) since
((b) ^ 0xFFFFFFFF) + 1 is always equal to -b (since uint32_t
arithmetic is carried out modulo 2^32).

Do you agree that the macro can be simplified, with no loss
in portability whatsoever?

I wrote a small program to try to illustrate my point.

#include <stdio.h>
int main(void)
{
volatile unsigned b = 0;
do
{
unsigned v1 = (b ^ 0xFFFFFFFF) + 1;
unsigned v2 = -b;
if (v1 != v2) printf("b=%u v1=%u v2=%u\n", b, v1, v2);
}
while (++b != 0);
return 0;
}

My compiler generates the same instruction to compute
v1 and v2.

Regards.
 
R

Richard Damon

Hello,

I've come across the following macro:

/** Get the absolute difference between 2 u32_t values (correcting overflows)
* 'a' is expected to be 'higher' (without overflow) than 'b'. */
#define FOO_U32_DIFF(a, b) (((a)>= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))

(u32_t is equivalent to uint32_t)

In my opinion, the entire macro reduces to ((a)-(b)) since
((b) ^ 0xFFFFFFFF) + 1 is always equal to -b (since uint32_t
arithmetic is carried out modulo 2^32).

Do you agree that the macro can be simplified, with no loss
in portability whatsoever?

My guess is that this is code to emulate uint32_t on a machine that
doesn't have a proper uint32_t, or may not be of type uint32_t. (perhaps
u32 is an 36 or 64 bit unsigned, as that is as close as the platform
provides, but they needed exact emulation for this result.
 
P

Peter Nilsson

Noob said:
I've come across the following macro:

/** Get the absolute difference between 2 u32_t values
(correcting overflows) * 'a' is expected to be 'higher'
(without overflow) than 'b'. */

Expected, but not required apparently! Is it really meant
to get the _absolute_ difference?
#define FOO_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b))
: (((a) + ((b) ^ 0xFFFFFFFF) + 1)))

(u32_t is equivalent to uint32_t)

In my opinion, the entire macro reduces to ((a)-(b)) since
((b) ^ 0xFFFFFFFF) + 1 is always equal to -b (since uint32_t
arithmetic is carried out modulo 2^32).

You're assuming uint32_t doesn't promote to int. The macro
can be written as...

#define FOO_U32_DIFF(a, b) ( (u32_t) ((a) - (b)) )

Assuming u32_t is an unsigned type.
Do you agree that the macro can be simplified, with no loss
in portability whatsoever?

It all hinges on what exactly u32_t is, or rather could be.
I'm guessing it's set up with some conditional preprocessing.

Perhaps it's really more like uint_least32_t, in which case
the macro may not work when b == 0 anyway. If it is meant to
mimic uint32_t, but may be wider, then the following may be
better:

#define FOO_U32_DIFF(a, b) \
( (u32_t) ((0ul + (a) - (b)) & 0xFFFFFFFFul) )
 
J

Jorgen Grahn

.
My guess is that this is code to emulate uint32_t on a machine that
doesn't have a proper uint32_t, or may not be of type uint32_t. (perhaps
u32 is an 36 or 64 bit unsigned, as that is as close as the platform
provides, but they needed exact emulation for this result.

What do you mean by "may not be of type uint32_t"?

Surely, uint32_t has to be exactly 32 bits if your environment
provides it? There's uint_least32_t for the other cases.

/Jorgen
 
J

Jorgen Grahn

Hello,

I've come across the following macro:

/** Get the absolute difference between 2 u32_t values (correcting overflows)
* 'a' is expected to be 'higher' (without overflow) than 'b'. */
#define FOO_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))

(u32_t is equivalent to uint32_t)

In my opinion, the entire macro reduces to ((a)-(b)) since
((b) ^ 0xFFFFFFFF) + 1 is always equal to -b (since uint32_t
arithmetic is carried out modulo 2^32).

Do you agree that the macro can be simplified, with no loss
in portability whatsoever?

I don't know, but I'd definitely make it an (inline) function, to avoid
driving people crazy. This isn't the 1980s.

/Jorgen
 
R

Richard Damon

What do you mean by "may not be of type uint32_t"?

Surely, uint32_t has to be exactly 32 bits if your environment
provides it? There's uint_least32_t for the other cases.

/Jorgen

The code calls the type U32, not uint32_t. It also is a macro so we
don't really know what type the parameters are.

If the type IS uint32_t, the extra complication should not be needed, so
my assumption is that the programmer didn't want to assume that this is
what he had, but did want the results as if he had them.
 

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,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top