Karim Manaouil
Karim Manaouil

Reputation: 1249

How to perform signed comparison between unsigned operands?

I have declared 4 unsigned variables:

uint32_t empty_bucket;
uint32_t base_bucket;
uint32_t hop_size;
uint32_t ht_size;

I want to perform a signed conditional check:

if (empty_bucket < base_bucket + (hop_size - 1) - ht_size)

Knowing that base_bucket + (hop_size - 1) - ht_size could be a negative value. What is the right casting for the operands to perform this singed operation?

NB: base_bucket + (hop_size - 1) - ht_size could be something really close to -2^32, so casting to signed 32-bits int32_t could cause an overflow.

Upvotes: 2

Views: 242

Answers (2)

alain
alain

Reputation: 12047

if (base_bucket + hop_size > ht_size + 1
    && empty_bucket < base_bucket + (hop_size - 1) - ht_size)

The first line checks if the right side of the comparison we want to perform is indeed a positive integer. It is done by checking that all the positive values (base_bucket and hop_size) are greater than all the negative values (- 1 and - ht_size). It does this without using subtractions, so it is safe to do with unsigned integers.

@David Bowling suggested

if (empty_bucket + ht_size < base_bucket + (hop_size - 1)) 

the idea is basically the same, to make sure that both sides of the comparison are always positive. This works if base_bucket and hop_size are not both zero at the same time.

With both solutions there can theoretically still be overflow, you have to check that with your actual values. If there is overflow, use a larger type.

Please disregard my earlier mention of short-circuit evaluation, because it is not relevant. If the integer sizes are 'normal', eg. 16, 32, or 64 bits, this should work.

Upvotes: 3

Jean-Fran&#231;ois Fabre
Jean-Fran&#231;ois Fabre

Reputation: 140168

Since you're using stdint include, you could convert the operands to 64 bit signed values, and compare that, no risk that any of the terms to the right become negative, and we have to cast the left operand to signed integer to avoid undefined/implementation behaviour when comparing signed/unsigned:

if ((int64_t)empty_bucket < ((int64_t)base_bucket + ((int64_t)hop_size - 1) - (int64_t)ht_size))

To sum it up:

  • no risk of overflow (I may have cast a little too much on the right side)
  • comparison between signed entities
  • On the downside, 64 bit conversion may have a negative impact on the performance on a 32 bit architecture

Upvotes: 4

Related Questions