The question is
Are there any other (and/or faster) implementations of a basic 2log?
Applications
The log2(int) and
Took the binary solution already mentioned and removed the branching. Did some testing and it turned out to be 1.3 times faster than DeBruijn.
public static int Log2(int v)
{
int r = 0xFFFF - v >> 31 & 0x10;
v >>= r;
int shift = 0xFF - v >> 31 & 0x8;
v >>= shift;
r |= shift;
shift = 0xF - v >> 31 & 0x4;
v >>= shift;
r |= shift;
shift = 0x3 - v >> 31 & 0x2;
v >>= shift;
r |= shift;
r |= (v >> 1);
return r;
}
Here is the fastest implementation of log2(int) for C#:
[StructLayout(LayoutKind.Explicit)]
private struct ConverterStruct
{
[FieldOffset(0)] public int asInt;
[FieldOffset(0)] public float asFloat;
}
public static int Log2(uint val)
{
ConverterStruct a; a.asInt = 0; a.asFloat = val;
return ((a.asInt >> 23 )+ 1) & 0x1F;
}
Notes: The inspiration for using the exponent in a float is from SPWorley 3/22/2009. Use with caution on production code since this would fail on architectures that are not little-endianness.
If you want something "endianness" safe then check out spender 5/3/2012. It also has Zero support.
Here are some benchmarks: (code here: https://github.com/SunsetQuest/Fast-Integer-Log2)
Function Time1 Time2 Errors Full-32-Bit Zero_Support
Log2_SunsetQuest3: 18 18 0 (Y) (N)
Log2_SunsetQuest4: 18 18 0 (Y) (N)
Log2_SPWorley: 18 18 0 (Y) (N)
MostSigBit_spender: 20 19 0 (Y) (Y)
Log2_HarrySvensson: 26 29 0 (Y) (N)
Log2_WiegleyJ: 27 23 0 (Y) (N)
Log2_DanielSig: 28 24 3125 (N) (N)
FloorLog2_Matthew_Watson: 29 25 0 (Y) (Y)
Log2_SunsetQuest1: 31 28 0 (Y) (Y)
HighestBitUnrolled_Kaz: 33 33 3125 (Y) (Y)
Log2_Flynn1179: 58 52 0 (Y) (N)
GetMsb_user3177100: 58 53 0 (Y) (N)
Log2floor_greggo: 89 101 0 (Y) (Y)
SomeOtherMethod0: 102 43 0 (Y) (N)
Log2_SunsetQuest2: 118 140 0 (Y) (Y)
SomeOtherMethod1: 125 60 0 (Y) (N)
SomeOtherMethod2: 136 118 0 (Y) (N)
Log2_SunsetQuest0: 206 202 0 (Y) (Y)
SomeOtherMethod3: 228 240 3125 (N) (Y)
SomeOtherMethod4: 2346 1494 0 (Y) (N)
Zero_Support = Supports Neg Return on Zero
Full-32-Bit = Supports full 32-bit (some just support 31 bits)
Time1 = benchmark for sizes up to 32-bit (same number tried for each size)
Time2 = benchmark for sizes up to 16-bit (for measuring perf with small numbers)
SomeOtherMethods = name of function/person left out on purpose
Benchmark notes: AMD Ryzen CPU, Release mode, no-debugger attached, .net core 2.1
clean reliable and fast!
(requires .net core 3 or later)
int val = BitOperations.Log2(x);