question

DikongPrigm-9942 avatar image
0 Votes"
DikongPrigm-9942 asked DikongPrigm-9942 commented

Using BitWise Operator

I've come across a code where it uses bitwise operator. I dont understand it well enough. What im trying to do is to save a truck size id but when reading the values, the ID im getting is different.

CODE FOR SAVING

         public int getmergedfields()
         {
             int merged = (int)PriorityLevel;
             merged |= ((int)PriceSource << 4);
             merged |= (((int)BinWeight) << 8);
             // merged |= (((int)WhenToInvoice) << 10);
    
             // these two flags store whether this job has extended comments for
             // either the comments or the officenotes field
             if (comments.Length > 200)
                 merged += 1024; // set the 11th bit
             if (officenotes.Length > 200)
                 merged += 2048; // set the 12th bit 
             if (TLPricedPerCube)
                 merged += 4096;
             if (SentToMobileDevice)
                 merged += 8192;
             // before this property was here things were always saved as ExGST so make that the default
             if (TLPricedIncGST)
                 merged += 16384;
             if (DespatchDocketSent)
                 merged += 32768;
             if (IsCurrentJob)
                 merged += 65536;
             merged += ((int)TruckSize) << 17;    
             return merged;
         }


CODE FOR READING


                 int unmerge = JobReader.GetInt32(startat);
                 PriorityLevel = (ePriorityLevel) (unmerge & 15); // 0x1111); // priority stored in 4 low bits
                 PriceSource = (ePriceSource)((unmerge >> 4) & 15);
                 BinWeight = (eBinWeight) ((unmerge >> 8) & 3);
                 // whentoinvoice = (eWhenToInvoice)((unmerge >> 10) & 3);
                 if ((unmerge & 1024) > 0)
                     extendedcomments = true;
                 if ((unmerge & 2048) > 0)
                     extendedofficenotes = true;
                 if ((unmerge & 4096) > 0)
                     TLPricedPerCube = true;
                 if ((unmerge & 8192) > 0)
                     senttomobiledevice = true;
                 if ((unmerge & 16384) > 0)
                     TLPricedIncGST = true;
                 if ((unmerge & 32768) > 0)
                     DespatchDocketSent = true;
                 if ((unmerge & 65536) > 0)
                     IsCurrentJob = true;
                 TruckSize = ((unmerge & ((1 << 17) | (1 << 18))) >> 17);



If the truck size Id is less than or equal to three, it works just fine but when the ID is greater than three, the result im expecting is different.

Honestly, I dont know what this code means.

 TruckSize = ((unmerge & ((1 << 17) | (1 << 18))) >> 17);


 merged += ((int)TruckSize) << 17;    



I don't know where does the 17 and 18 come from.


dotnet-csharp
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Paul-5034 avatar image
0 Votes"
Paul-5034 answered DikongPrigm-9942 edited

1 << 17 means take one bit and move it 17 places to the left, so this:

000000000000000001

Is coverted into this:

100000000000000000 (131072 in decimal)

(1 << 17) | (1 << 18) takes the value above and "bitwise or"'s it with:

1000000000000000000 (contains extra zero than the number above)

And that gives us:

1100000000000000000

You could also do (3 << 17) here instead of (1 << 17) | (1 << 18) and it'll give you the same result.

Next the result above is "bitwise and"'ed to unmerge, which will effectively get it's 17th and 18th bits.

Lastly, the result of that are then shifted right 17 places which will give you the answer in the range of 0 to 3.

For the purpose of your question my question is: how many bits are reserved in your merged variable for the ID? Currently it only uses 2 bits, so if you wanted to represent higher numbers you'll need to consider that when shifting your bits.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Yes, you are right. The code is supposedly gives a number in the range of 0 to 3, and maybe that is the result why when i store a value which is greater than 3, it gives me 0. What change should I do to atleast store a value from the range 0 to 20 without affecting the values which are already stored in the database.

0 Votes 0 ·
Paul-5034 avatar image
0 Votes"
Paul-5034 answered DikongPrigm-9942 commented

Well to represent the number 20 you'd need to use a minimum of 5 bits (giving you an ID range of 0 to 31.)

So you'd need to make sure that you have 5 (ideally consecutive) bits available to store the value. Do you have any bits that aren't already in use by other data?

If you only have 2 bits free and they're the 2 that you're currently using you might want to consider changing the data type of that column to support more bits, although this will be wasteful so it's worth trying to free up any unused bits that you currently have first.

· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Im not sure how to freeup any unused bits, it would be easier just to extend the values from 0-3 to atleast 15 maybe but still not sure how do i do that.

0 Votes 0 ·
Paul-5034 avatar image Paul-5034 DikongPrigm-9942 ·

What's confusing me is that this code appears to be doing bitmasking, but it's also combined with arithmetic, which I'm not sure is valid in this scenario.

For example, this code looks fine, if we assume that PriorityLevel, PriceSource & BinWeight only contain values between 0 and 15:

int merged = (int)PriorityLevel;
 merged |= ((int)PriceSource << 4);
 merged |= (((int)BinWeight) << 8);


However this line suggests it's setting the 11th bit, but it's just adding 11 bits worth of data onto merged:

if (comments.Length > 200)
    merged += 1024; // set the 11th bit


To

if (comments.Length > 200)
    merged |= 1024; // set the 11th bit


If the intention of this line is to check whether a particular bit is set, it may also be incorrect:

if ((unmerge & 1024) > 0)
    extendedcomments = true;


Here you're just checking if any bits between 0 and 11 bits are set, rather than just checking if the 11th bit in particular is set. You'd do this by:

if ((unmerge & 1024) == 1024)
    extendedcomments = true;


The issue with your current approach is that if any bits between 0 and 11 are set then all of your if statements will return true here, which I'm guessing wasn't your intention:

if ((unmerge & 1024) > 0)
    extendedcomments = true;
if ((unmerge & 2048) > 0)
    extendedofficenotes = true;
if ((unmerge & 4096) > 0)
    TLPricedPerCube = true;
if ((unmerge & 8192) > 0)
    senttomobiledevice = true;
...
0 Votes 0 ·
Paul-5034 avatar image Paul-5034 DikongPrigm-9942 ·

Ran out of characters sorry. I think if you address the issues above then you should be able to just provide a large integer value and it should be able to handle it.

If you're happy to just support values from 0 to 31 then you should be able to change your code from this:

TruckSize = ((unmerge & ((1 << 17) | (1 << 18))) >> 17);


To this:

TruckSize = ((unmerge & (31 << 17)) >> 17);


What this does is take 31 (11111 in binary) and shift it left by 17 digits, and that with unmerge to get those bits from it, then shift the values 17 places to the right to give you your truck size in the range 0 to 31.

0 Votes 0 ·

Yes, I really don't understand much of the code but what I can tell is the code is trying to merge all the fields into a single value and store it inside the database. If someone is going to retrieve the data, the code will need to unmerge. Btw, thanks for helping me, I'm not sure if im going to touch the code, it is more complicated than I think.

0 Votes 0 ·