dqhendricks
dqhendricks

Reputation: 19251

Using bitwise operators on > 32 bit integers

I am using bitwise operations in order to represent many access control flags within one integer.

ADMIN_ACCESS = 1;
EDIT_ACCOUNT_ACCESS = 2;
EDIT_ORDER_ACCESS = 4;

var myAccess = 3; // ie: ( ADMIN_ACCESS | EDIT_ACCOUNT_ACCESS )

if ( myAccess & EDIT_ACCOUNT_ACCESS ) { // check for correct access
   // allow for editing of account

}

Most of this is occurring on the PHP side of my project. There is one piece however where Javascript is used to join several access flags using | when saving someone's access level. This works fine to a point. I have found that once an integer (flag) gets too large (> 32bit), it no longer works correctly with bitwise operators in Javascript. For instance:

alert( 4294967296 | 1 ); // equals 1, but should equal 4294967297

I am trying to find a workaround for this so that I do not have to limit my number of access control flags to 32. Each access control flag is two times the previous control flag so that each control flag will not interfere with other control flags.

dec(4) = bin(100)
dec(8) = bin(1000)
dec(16) = bin(10000)

I have noticed that when adding two of these flags together with a simple +, it seems to come out with the same answer as a bitwise or operation, but am having trouble wrapping my head around whether this is a simple substitution, or if there might be problems with doing this. Can anyone comment on the validity of this workaround? Example:

(4294967296 | 262144 | 524288) == (4294967296 + 262144 + 524288)

Upvotes: 4

Views: 3589

Answers (3)

Aleko
Aleko

Reputation: 970

It is simple. Just perform bit shift using division:

function getBitAtPos(mask: number, pos: number): number {
  return mask / 2 ** pos & 1;
}

function setBitAtPos(mask: number, pos: number, val: number): number {
  return (Math.trunc(mask / 2 ** (pos + 1) * 2 + (val & 1)) * 2 ** pos + mask % 2 ** pos;
}

// bit position starting from 0 to 52 (up to Number.MAX_SAFE_INTEGER)
getBitAtPos(4503599627370496, 52) // 1
setBitAtPos(0, 52, 1) // 4503599627370496
setBitAtPos(4503599627370496, 52, 0) // 0

Upvotes: 0

Phil H
Phil H

Reputation: 20141

You cannot have more than 32, if you want to have bitwise operations. To perform bitwise operations, javascript converts the number value (which is held as an 8 byte float) to a 32-bit integer and then performs bitwise/bitshift operations on that value. It converts the resulting integer back to floating point before storing in the variable. For more information see this Moz Dev Net article.

You can still perform integer arithmetic on the floats, up to 9007199254740992, which is 2^53. But you cannot use bitwise operators beyond 32 bits for the above reason.

Since PHP uses platform-dependent integers, you cannot guarantee that the PHP can handle more than 32 bits either. So on both sides I would recommend splitting your flags into groups and maintaining them separately. You can wrap them in objects with accessors to make sure they behave like one set of flags rather than several.

Upvotes: 2

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324650

Simply adding the flags will work provided you know for sure that each flag is a power of two, and that you don't go past 52 bits long (due to the amount a Double-precision float can hold, since that's what JS uses for numbers).

If, for whatever reason, you need more than 52 flags, I would suggest grouping the flags into categories.

Upvotes: 2

Related Questions