0

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 from above would evaluate to 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.

rtpax
  • 1,687
  • 1
  • 18
  • 32
  • I don't think I did that? – rtpax Aug 04 '16 at 22:18
  • You didn't, but you did break the double underscore part of the same rule. More here: [What are the rules about using an underscore in a C++ identifier?](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – user4581301 Aug 04 '16 at 22:20
  • Thanks for pointing that out. Just to verify, that couldn't be affecting this could it? – rtpax Aug 04 '16 at 22:22
  • There is a `std::rint` that may have some fatal `__rint` hidden away somewhere deep in the library implementation, but I don't know for sure. That's why the whole `__` world is declared off limits: so you don't have to know. Personally, it's unlikely, but why risk it? – user4581301 Aug 04 '16 at 22:24
  • off topic: `byte = byte;` doesn't look very useful. – user4581301 Aug 04 '16 at 22:27
  • not sure how that sneaked in there – rtpax Aug 04 '16 at 22:27
  • Also, I compiled without double underscore and behavior remained the same – rtpax Aug 04 '16 at 22:28
  • the smaller-than-byte bit shifting is done in the third for-loop. That was supposed to be returned by reference, I missed that particular method – rtpax Aug 04 '16 at 22:42

1 Answers1

0

& 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.

kfsone
  • 23,617
  • 2
  • 42
  • 74