contract BitwiseOps {
// x = 1110 = 8 + 4 + 2 + 0 = 14
// y = 1011 = 8 + 0 + 2 + 1 = 11
// x & y = 1010 = 8 + 0 + 2 + 0 = 10
function and(uint x, uint y) external pure returns (uint) {
return x & y;
}
// x = 1100 = 8 + 4 + 0 + 0 = 12
// y = 1001 = 8 + 0 + 0 + 1 = 9
// x | y = 1101 = 8 + 4 + 0 + 1 = 13
function or(uint x, uint y) external pure returns (uint) {
return x | y;
}
// x = 1100 = 8 + 4 + 0 + 0 = 12
// y = 0101 = 0 + 4 + 0 + 1 = 5
// x ^ y = 1001 = 8 + 0 + 0 + 1 = 9
function xor(uint x, uint y) external pure returns (uint) {
return x ^ y;
}
// x = 00001100 = 0 + 0 + 0 + 0 + 8 + 4 + 0 + 0 = 12
// ~x = 11110011 = 128 + 64 + 32 + 16 + 0 + 0 + 2 + 1 = 243
function not(uint8 x) external pure returns (uint8) {
return ~x;
}
// 1 << 0 = 0001 --> 0001 = 1
// 1 << 1 = 0001 --> 0010 = 2
// 1 << 2 = 0001 --> 0100 = 4
// 1 << 3 = 0001 --> 1000 = 8
// 3 << 2 = 0011 --> 1100 = 12
function shiftLeft(uint x, uint bits) external pure returns (uint) {
return x << bits;
}
// 8 >> 0 = 1000 --> 1000 = 8
// 8 >> 1 = 1000 --> 0100 = 4
// 8 >> 2 = 1000 --> 0010 = 2
// 8 >> 3 = 1000 --> 0001 = 1
// 8 >> 4 = 1000 --> 0000 = 0
// 12 >> 1 = 1100 --> 0110 = 6
function shiftRight(uint x, uint bits) external pure returns (uint) {
return x >> bits;
}
// Get last n bits from x
function getLastNBits(uint x, uint n) external pure returns (uint) {
// Example, last 3 bits
// x = 1101 = 13
// mask = 0111 = 7
// x & mask = 0101 = 5
uint mask = (1 << n) - 1;
return x & mask;
}
// Get last n bits from x using mod operator
function getLastNBitsUsingMod(uint x, uint n) external pure returns (uint) {
// 1 << n = 2 ** n
return x % (1 << n);
}
// Get position of most significant bit
// x = 1100 = 10, most significant bit = 1000, so this function will return 3
function mostSignificantBit(uint x) external pure returns (uint) {
uint i = 0;
while ((x >>= 1) > 0) {
++i;
}
return i;
}
// Get first n bits from x
// len = length of bits in x = position of most significant bit of x, + 1
function getFirstNBits(uint x, uint n, uint len) external pure returns (uint) {
// Example
// x = 1110 = 14, n = 2, len = 4
// mask = 1100 = 12
// x & mask = 1100 = 12
uint mask = ((1 << n) - 1) << (len - n);
return x & mask;
}
}
contract MostSignificantBitFunction {
// Find most significant bit using binary search
function mostSignificantBit(uint x) external pure returns (uint msb) {
// x >= 2 ** 128
if (x >= 0x100000000000000000000000000000000) {
x >>= 128;
msb += 128;
}
// x >= 2 ** 64
if (x >= 0x10000000000000000) {
x >>= 64;
msb += 64;
}
// x >= 2 ** 32
if (x >= 0x100000000) {
x >>= 32;
msb += 32;
}
// x >= 2 ** 16
if (x >= 0x10000) {
x >>= 16;
msb += 16;
}
// x >= 2 ** 8
if (x >= 0x100) {
x >>= 8;
msb += 8;
}
// x >= 2 ** 4
if (x >= 0x10) {
x >>= 4;
msb += 4;
}
// x >= 2 ** 2
if (x >= 0x4) {
x >>= 2;
msb += 2;
}
// x >= 2 ** 1
if (x >= 0x2) msb += 1;
}
}
contract MostSignificantBitAssembly {
function mostSignificantBit(uint x) external pure returns (uint msb) {
assembly {
let f := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
x := shr(f, x)
// or can be replaced with add
msb := or(msb, f)
}
assembly {
let f := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
x := shr(f, x)
msb := or(msb, f)
}
assembly {
let f := shl(5, gt(x, 0xFFFFFFFF))
x := shr(f, x)
msb := or(msb, f)
}
assembly {
let f := shl(4, gt(x, 0xFFFF))
x := shr(f, x)
msb := or(msb, f)
}
assembly {
let f := shl(3, gt(x, 0xFF))
x := shr(f, x)
msb := or(msb, f)
}
assembly {
let f := shl(2, gt(x, 0xF))
x := shr(f, x)
msb := or(msb, f)
}
assembly {
let f := shl(1, gt(x, 0x3))
x := shr(f, x)
msb := or(msb, f)
}
assembly {
let f := gt(x, 0x1)
msb := or(msb, f)
}
}
}