rtpax - 7 months ago 22

C++ Question

I wrote some code as an exercise that essentially performs mathematical operations on any size piece of data using only (except for looping) bit-wise operations. It's mostly functional but there is one problem which I cannot understand and I can't recreate it out of context and there is a bit of code that goes along with it, but here's the snippet that's giving me trouble

`const __rint<size> _leftshiftto(__rint<size>arg)`

{

if (arg.val[0] & 0x80)//negative arg

{

return _rightshiftto(arg._negto());

}

uint32_t byte = (arg._int32() / 8);

uint32_t carbyte = size - byte;

byte = byte;

uint8_t bit = (arg._int8() % 8);

uint8_t carbit = 8 - bit;

for (uint32_t n = 0; n<carbyte; ++n)

{

puts("iter");

printf("%02hhx <- %02hhx\n",val[n],val[n+byte]);

val[n] = val[n + byte];

}

for (uint32_t n = carbyte; n < size; ++n)

{

puts("iter2");

val[n] = 0x00;

}

for (uint32_t n = 0; n<size-1; ++n)

{

val[n] <<= bit;

val[n] &= val[n + 1] >> carbit;

}

val[size - 1] <<= bit;

return *this;

}

The full code is at https://github.com/rtpax/rmath/blob/master/rint.h

What's happening is that it works for small enough values, but evaluates to zero for input 8 or above (so if it shifts a whole byte).

`__rint<4> a(5);`

//evaluates to 0x00000005

a._leftshiftto(4);

//evaluates to 0x00000050

__rint<4> b(5);

//evaluates to 0x00000005

b._leftshiftto(8);

//evaluates to 0x00000000

What's stranger is that if you change the line

`val[n] = 0x00;`

to

`val[n] = 0xff;//or anything 0x80 and above`

It does work except that the rightmost bytes will be filled with whatever number you put there (so

`b`

`0x000005ff`

I'm at a loss on this one, if anyone could offer an explanation I appreciate it.

some other notes:

I'm compiling using g++ on Windows 10

Something that seems related is that when I print out my hexes they display as 4 digits rather than two if they are at least 0x80 (which would print as 0xff80)

Bitshifts from 1 to 7 also don't work for larger numbers, but I assume that those failures are for the same reason as the whole byte shift failures.

Answer

`&`

is the logical and operator: it requires a 1 in both sources to yield a 1 in the destination. `0101 & 0011`

yields `0001`

.

```
val[n] &= val[n + 1] >> carbit;
```

This will set `val[n]`

to zero, since we know the low bits of `val[n]`

are zero, and we shift the `val[n + 1]`

bits so the corresponding high bits will be zero:

```
11111000 &
00000111 =
00000000
```

You want the `|`

operator:

```
11011000 |
00000010 =
11011010
```

Also, note that your code modifies the this object, but you return by value, making a copy.

Your return type probably should be

```
const __rint<size>&
```

Return by const *value* makes very little sense here.