1

I am trying to create a method to change a range of bits to all 1 using a high and a low and a source. The code works from 0 to 30, then it outputs incorrect numbers. The correct result for setBits(0, 31, 0) should be ffffffff instead of 0.

What is causing my code to reset to zero?

setBits(0,0,0): 1
setBits(0,1,0): 3
setBits(0,2,0): 7
setBits(0,3,0): f
setBits(0,4,0): 1f
setBits(0,5,0): 3f
setBits(0,6,0): 7f
setBits(0,7,0): ff
setBits(0,8,0): 1ff
setBits(0,9,0): 3ff
setBits(0,10,0): 7ff
setBits(0,11,0): fff
setBits(0,12,0): 1fff
setBits(0,13,0): 3fff
setBits(0,14,0): 7fff
setBits(0,15,0): ffff
setBits(0,16,0): 1ffff
setBits(0,17,0): 3ffff
setBits(0,18,0): 7ffff
setBits(0,19,0): fffff
setBits(0,20,0): 1fffff
setBits(0,21,0): 3fffff
setBits(0,22,0): 7fffff
setBits(0,23,0): ffffff
setBits(0,24,0): 1ffffff
setBits(0,25,0): 3ffffff
setBits(0,26,0): 7ffffff
setBits(0,27,0): fffffff
setBits(0,28,0): 1fffffff
setBits(0,29,0): 3fffffff
setBits(0,30,0): 7fffffff
setBits(0,31,0): 0

uint64_t setBits(unsigned low, unsigned high, uint64_t source)
{
    assert(high < 64 && (low <= high));
    uint64_t mask;
    mask = ((1 << (high-low + 1))-1) << low;
    uint64_t extracted = mask | source;
    return extracted;
}
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
mcockman
  • 19
  • 1

2 Answers2

1

You need to make the initial bit into the type unsigned long long (or uint64_t) so that it doesn't overflow when bitshifted.

mask = ((1ULL << (high - low + 1)) - 1) << low;
          ^^^

For number 1 of int type, it'll overflow when leftshifted for 32 bits:

((1 << (high-low + 1))-1) // Where (high-low + 1) == 31 - 0 + 1 == 32
  ^

    00000000 00000000 00000000 00000001 = 1
 v <-- Left shift for 32 bits --------<
(1) 00000000 00000000 00000000 00000000 = 0

But that would work for a 64-bit integer type. So change it to 1ULL and the problem is gone.

iBug
  • 35,554
  • 7
  • 89
  • 134
  • I applied it to my code, now the only error I get is when i run it as setBits(0, 63, 0), which returns a zero, instead of fffffffffffffff. What could be happening here? – mcockman Jan 25 '18 at 06:23
  • 1
    In that case, what is `high-low + 1`? Can that fit in a 64 bit number? – Retired Ninja Jan 25 '18 at 06:26
  • @mcockman `1 << (63-0 + 1)` is 0 so the next -1 should *also* be `-1ull`. In fact, *all* off your constants should be `ull`. – Matthieu Jan 25 '18 at 06:27
  • 1
    In any case, a shift of 64 bits for a 64-bit quantity is undefined behaviour. Shifts of 0 through N-1 are OK for an N-bit quantity. – Jonathan Leffler Jan 25 '18 at 06:28
  • What can be proposed to offset the bitshifting overflow that occurs when it runs at 0, 63? – mcockman Jan 25 '18 at 06:35
  • @mcockman did you read my answer, and comment? Try changing *all* your `1` to `1ull`. – Matthieu Jan 25 '18 at 06:56
1

unsigned is unsigned int, so a 32 bits value, as well as constant 1 which is a signed int, so when you're shifting 1 << (high-low + 1) you're doing it on 32 bits integers.

Use ull to transform all your constants to unsigned 64 bits int during the shifts.

mask = ((1ull << (high-low + 1ull))-1ull) << low

Matthieu
  • 2,736
  • 4
  • 57
  • 87