Bitwise Operations

From SphereWiki
Revision as of 19:52, 5 November 2015 by RanXerox (talk | contribs) (Flags)
Jump to: navigation, search

Bitwise operations are used to perform an action on the bits (the 1's and 0's) of a number.

In this article a "binary" formatted number (which represents the "bits" of a number) will be written with a 2... and a decimal number with a 10

Limitations

In Sphere, numbers are stored in something called a "DWORD". The largest number a DWORD can store is constrained by the fact that a DWORD is 32 bits wide. That means the largest number it can store is 2^32-1.

  • In Binary that's 11111111111111111111111111111111.
  • In Hex it's FFFFFFFF.
  • In Decimal that's 4294967295.

To store a 'signed' number in a DWORD (in other words, a number that can be positive or negative), the first bit is used to indicate the sign (a 1 is negative). Which means the largest 'signed' positive number is 2^31-1

  • In Binary that's 01111111111111111111111111111111.
  • In Hex it's 7FFFFFFF.
  • In Decimal that's 2147483647.

In sphere script language, the EVAL function outputs a signed DWORD, and the UVAL outputs an unsigned DWORD.

[FUNCTION Mathtest]
LOCAL.Number0=2147483647
LOCAL.Number1=4294967295
LOCAL.Number2=8589934588
SERV.LOG eval0=<EVAL <LOCAL.Number0>> eval1=<EVAL <LOCAL.Number1>> eval2=<EVAL <LOCAL.Number2>>
SERV.LOG uval0=<UVAL <LOCAL.Number0>> uval1=<UVAL <LOCAL.Number1>> uval2=<UVAL <LOCAL.Number2>>

The output of this test is:

13:37:(test.scp,10)eval0=2147483647 eval1=-1 eval2=-4
13:37:(test.scp,11)uval0=2147483647 uval1=4294967295 uval2=4294967292

Notes:

  • The output is limited to align with the limitation of the DWORD itself.
  • Since there are 32 "bits" in a DWORD, there can only be 32 flags in a set.
  • Be careful when manipulating flags using EVAL, because the 32nd flag could get lost.

Flags

In the Sphere server, quite a few concepts are implemented using "flags". You can see examples of flags being defined in the Sphere.ini file, or the sphere_defs.scp files. For example:

[DEFNAME attr_flags]
attr_identified       01
attr_decay            02
attr_newbie           04
attr_move_always      08
attr_move_never      010
attr_magic           020
attr_owned           040
attr_invis           080
attr_cursed         0100
attr_cursed2        0200
attr_blessed        0400
attr_blessed2       0800
attr_forsale       01000
attr_stolen        02000
attr_can_decay     04000
attr_static        08000
attr_exceptional  010000
attr_enchanted    020000
attr_imbued       040000
attr_questitem    080000
attr_insured     0100000
attr_nodrop      0200000
attr_notrade     0400000
attr_lockeddown  0800000
attr_secure     01000000

This technique is a very efficient way to store a number of Boolean values using as little memory as possible. Let's tip that list on it's side and chart the first 8 flags:

Flag Name: attr_invis attr_owned attr_magic attr_move_never attr_move_always attr_newbie attr_decay attr_identified
Flag Position 8th position 7th position 6th position 5th position 4th position 3rd position 2nd position 1st position
Binary Number: 10000000 01000000 00100000 00010000 00001000 00000100 00000010 00000001
Hex Number: 080 040 020 010 08 04 02 01
Decimal Number: 128 64 32 16 8 4 2 1

Now you can probably see the pattern... the numbers 1,2,4,8,16,32,64,128,... are all multiples of 2 and they are special because they all have a single 1 in them when converted to binary. To enable or disable an individual flag on an object is accomplished using the bitwise operators AND, OR, XOR, and NOT.

The OR Operator (inclusive OR)

A bitwise OR takes two bit patterns of equal length and performs the logical inclusive OR operation on each pair of corresponding bits. When you perform this operation, the result in each position is 0 if both bits are 0, and the result is 1 if either (or both) the bits were 1. For example:

   0101 (decimal 5)
OR 0011 (decimal 3)
 = 0111 (decimal 7)

In Sphere, this technique is commonly used to set a flag in a register, where each bit represents an individual Boolean state. Thus, 0010 (decimal 2) can be considered a set of four flags, where the first, third, and fourth flags are clear (0) and the second flag is set (1). The fourth flag may be set by performing a bitwise OR between this value and a bit pattern with only the fourth bit set:

   0010 (decimal 2)
OR 1000 (decimal 8)
 = 1010 (decimal 10)

The AND Operator

The XOR Operator (exclusive OR)

The NOT Operator

Left and right shift