Bit Operations
The library provides extension methods for common bit-level operations on primitive integer types. These cover individual bit access, bit ranges, nibble manipulation, parity, overflow detection, and binary string formatting.
Supported Types
Bit operations are available on the following types:
| Type | Bit Width | API Reference |
|---|---|---|
byte | 8 | ByteExtensions |
ushort | 16 | UInt16Extensions |
int | 32 | Int32Extensions |
uint | 32 | UInt32Extensions |
long | 64 | Int64Extensions |
ulong | 64 | UInt64Extensions |
Individual Bit Access
GetBit(index) returns true if the bit at the given zero-based index is set. SetBit(index) returns a new value with that bit set. ResetBit(index) returns a new value with that bit cleared.
Bits are numbered from 0 (least significant) to N-1 (most significant).
byte b = 0b00001010; // bits 1 and 3 are set
bool bit1 = b.GetBit(1); // true
bool bit0 = b.GetBit(0); // false
byte set = b.SetBit(0); // 0b00001011
byte reset = b.ResetBit(1); // 0b00001000Bit Ranges
GetBits(startInclusive, endInclusive) extracts a contiguous range of bits, shifting the result right so that the start bit is at position 0. SetBits(value, startInclusive, endInclusive) replaces a range of bits with the low bits of the supplied value.
Both methods validate that the range indices are within bounds and that endInclusive is not less than startInclusive.
byte b = 0b01101100;
byte nibble = b.GetBits(2, 5); // bits 2..5 = 0b1011, shifted to 0b1011 (11)
byte updated = b.SetBits(0b1111, 2, 5); // sets bits 2..5 to 1111 -> 0b01111100Convenience Bit Properties
Three convenience methods provide named access to commonly used bit positions:
LeftMostBit()returns the value of the most significant bit.RightMostBit()returns the value of the least significant bit (bit 0).SignBit()returns the value of the sign bit (same asLeftMostBit()).
byte b = 0b10000001;
bool left = b.LeftMostBit(); // true (bit 7)
bool right = b.RightMostBit(); // true (bit 0)
bool sign = b.SignBit(); // true (bit 7)Nibble Operations (byte only)
HighNibble() returns bits 4-7 of a byte shifted down to bits 0-3. LowNibble() returns bits 0-3 of a byte. SetHighNibble(nibble) returns a new byte with the upper four bits replaced. SetLowNibble(nibble) returns a new byte with the lower four bits replaced.
byte b = 0xAB;
byte high = b.HighNibble(); // 0x0A
byte low = b.LowNibble(); // 0x0B
byte updated = b.SetHighNibble(0x05); // 0x5BCopying Bits with a Mask (byte only)
CopyBitsFrom(toCopyFrom, mask) copies bits from one byte to another selectively. Bits where the mask is set are taken from toCopyFrom; bits where the mask is clear are taken from the receiver.
byte target = 0b11110000;
byte source = 0b10101010;
byte mask = 0b00001111;
byte result = target.CopyBitsFrom(source, mask); // 0b11101010Parity (byte only)
Parity() returns true if the number of set bits in the byte is even (even parity).
byte b = 0b00001111; // 4 set bits
bool even = b.Parity(); // true
byte c = 0b00000111; // 3 set bits
bool odd = c.Parity(); // falseByte Decomposition (ushort only)
MostSignificantByte() returns the high byte, and LeastSignificantByte() returns the low byte. ToBytes() returns both as a (byte Msb, byte Lsb) tuple.
ushort value = 0x1234;
byte msb = value.MostSignificantByte(); // 0x12
byte lsb = value.LeastSignificantByte(); // 0x34
(byte m, byte l) = value.ToBytes(); // m = 0x12, l = 0x34Binary String Representation
ToBinaryString() converts any supported integer value to a human-readable binary string prefixed with "0b".
| Type | Output length | Example |
|---|---|---|
byte | 10 chars | "0b01011010" |
ushort | 18 chars | "0b0001001000110100" |
int | 34 chars | "0b00000000000000000000000001011010" |
uint | 34 chars | "0b00000000000000000000000001011010" |
long | 66 chars | (64 digits prefixed with "0b") |
ulong | 66 chars | (64 digits prefixed with "0b") |
byte b = 0x5A;
string s = b.ToBinaryString(); // "0b01011010"
int i = 90;
string t = i.ToBinaryString(); // "0b00000000000000000000000001011010"BoolExtensions.ToBitChar() converts a boolean to the character '1' for true or '0' for false. This is useful when building binary string representations character by character.
char c = true.ToBitChar(); // '1'
char d = false.ToBitChar(); // '0'Arithmetic Overflow Detection
These methods detect whether an arithmetic operation on two values produced an overflow or a half-carry/half-borrow. They are primarily useful when emulating processors that expose status flags, such as Z80 or 6502 CPUs.
Addition
DidAdditionHalfCarry(left, right) is called on the sum and returns true if the addition of the low nibble (for byte) or low byte (for ushort) produced a carry into the next nibble or byte. On byte, this is a carry from bit 3 to bit 4. On ushort, it is a carry from bit 11 to bit 12.
DidAdditionOverflow(left, right) is called on the sum and returns true if a signed addition overflowed, meaning the result has the wrong sign relative to both operands.
byte left = 120;
byte right = 20;
byte sum = (byte)(left + right); // 140, wraps in signed interpretation
bool overflow = sum.DidAdditionOverflow(left, right); // true (sign changed)
bool halfCarry = sum.DidAdditionHalfCarry(left, right); // depends on nibblesSubtraction
DidSubtractionHalfBorrow(left, right) is called on the difference and returns true if a borrow occurred from the upper nibble into the lower nibble (for byte), or from the upper byte into the lower byte (for ushort).
DidSubtractionOverflow(left, right) is called on the difference and returns true if a signed subtraction overflowed.
byte left = 10;
byte right = 20;
byte difference = (byte)(left - right); // 246 (wraps)
bool overflow = difference.DidSubtractionOverflow(left, right); // true
bool halfBorrow = difference.DidSubtractionHalfBorrow(left, right); // depends on nibbles