- The De Bruijn lookup table needs to be pre-calculated.
===== Using Logs =====
int lsb = (int)(Math.Log(v,2));
===== Using a Loop =====
int getLSB(ulong v) { int lsb = 0; while ((v >>= 1) != 0) { lsb++; } return lsb; }
===== Using MS C++ Compiler Built-in =====
#include <intrin.h> unsigned char _BitScanForward( unsigned long * Index, unsigned long Mask ); unsigned char _BitScanForward64( unsigned long * Index, unsigned __int64 Mask );
===== Using .NET Core 3.0 ===== .NET Core 3.0 introduced hardware intrinsics:
ulong value = 18; ulong result = System.Runtime.Intrinsics.X86.Bmi1.X64.TrailingZeroCount(value);Alternatively, the new System.Numerics.Bitoperations methods also use hardware intrinsics:
int result2 = System.Numerics.BitOperations.TrailingZeroCount(value);
===== Using the integer log base 2 of an integer with an 64-bit IEEE float ===== TODO
int v; // 32-bit integer to find the log base 2 of int r; // result of log_2(v) goes here union { unsigned int u[2]; double d; } t; // temp t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] = 0x43300000; t.u[__FLOAT_WORD_ORDER!=LITTLE_ENDIAN] = v; t.d -= 4503599627370496.0; r = (t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] >> 20) - 0x3FF;
- From this newly minted double, 2^52 (expressed as a double) is subtracted, which sets the resulting exponent to the log base 2 of the input value, v.
- All that is left is shifting the exponent bits into position (20 bits right) and subtracting the bias, 0x3FF (which is 1023 decimal).
- This technique only takes 5 operations, but many CPUs are slow at manipulating doubles, and the endianess of the architecture must be accommodated.
===== References ===== https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanforward-bitscanforward64?redirectedfrom=MSDN&view=msvc-160 http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn https://www.chessprogramming.org/De_Bruijn_Sequence_Generator https://en.wikipedia.org/wiki/Bit_numbering