@@ -537,41 +537,45 @@ library Math {
537
537
* @dev Return the log in base 2 of a positive value rounded towards zero.
538
538
* Returns 0 if given 0.
539
539
*/
540
- function log2 (uint256 value ) internal pure returns (uint256 ) {
541
- uint256 result = 0 ;
542
- uint256 exp;
543
- unchecked {
544
- exp = 128 * SafeCast.toUint (value > (1 << 128 ) - 1 );
545
- value >>= exp;
546
- result += exp;
547
-
548
- exp = 64 * SafeCast.toUint (value > (1 << 64 ) - 1 );
549
- value >>= exp;
550
- result += exp;
551
-
552
- exp = 32 * SafeCast.toUint (value > (1 << 32 ) - 1 );
553
- value >>= exp;
554
- result += exp;
555
-
556
- exp = 16 * SafeCast.toUint (value > (1 << 16 ) - 1 );
557
- value >>= exp;
558
- result += exp;
559
-
560
- exp = 8 * SafeCast.toUint (value > (1 << 8 ) - 1 );
561
- value >>= exp;
562
- result += exp;
563
-
564
- exp = 4 * SafeCast.toUint (value > (1 << 4 ) - 1 );
565
- value >>= exp;
566
- result += exp;
567
-
568
- exp = 2 * SafeCast.toUint (value > (1 << 2 ) - 1 );
569
- value >>= exp;
570
- result += exp;
571
-
572
- result += SafeCast.toUint (value > 1 );
540
+ function log2 (uint256 x ) internal pure returns (uint256 r ) {
541
+ // If value has upper 128 bits set, log2 result is at least 128
542
+ r = SafeCast.toUint (x > 0xffffffffffffffffffffffffffffffff ) << 7 ;
543
+ // If upper 64 bits of 128-bit half set, add 64 to result
544
+ r |= SafeCast.toUint ((x >> r) > 0xffffffffffffffff ) << 6 ;
545
+ // If upper 32 bits of 64-bit half set, add 32 to result
546
+ r |= SafeCast.toUint ((x >> r) > 0xffffffff ) << 5 ;
547
+ // If upper 16 bits of 32-bit half set, add 16 to result
548
+ r |= SafeCast.toUint ((x >> r) > 0xffff ) << 4 ;
549
+ // If upper 8 bits of 16-bit half set, add 8 to result
550
+ r |= SafeCast.toUint ((x >> r) > 0xff ) << 3 ;
551
+ // If upper 4 bits of 8-bit half set, add 4 to result
552
+ r |= SafeCast.toUint ((x >> r) > 0xf ) << 2 ;
553
+
554
+ // Shifts value right by the current result and use it as an index into this lookup table:
555
+ //
556
+ // | x (4 bits) | index | table[index] = MSB position |
557
+ // |------------|---------|-----------------------------|
558
+ // | 0000 | 0 | table[0] = 0 |
559
+ // | 0001 | 1 | table[1] = 0 |
560
+ // | 0010 | 2 | table[2] = 1 |
561
+ // | 0011 | 3 | table[3] = 1 |
562
+ // | 0100 | 4 | table[4] = 2 |
563
+ // | 0101 | 5 | table[5] = 2 |
564
+ // | 0110 | 6 | table[6] = 2 |
565
+ // | 0111 | 7 | table[7] = 2 |
566
+ // | 1000 | 8 | table[8] = 3 |
567
+ // | 1001 | 9 | table[9] = 3 |
568
+ // | 1010 | 10 | table[10] = 3 |
569
+ // | 1011 | 11 | table[11] = 3 |
570
+ // | 1100 | 12 | table[12] = 3 |
571
+ // | 1101 | 13 | table[13] = 3 |
572
+ // | 1110 | 14 | table[14] = 3 |
573
+ // | 1111 | 15 | table[15] = 3 |
574
+ //
575
+ // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
576
+ assembly ("memory-safe" ) {
577
+ r := or (r, byte (shr (r, x), 0x0000010102020202030303030303030300000000000000000000000000000000 ))
573
578
}
574
- return result;
575
579
}
576
580
577
581
/**
0 commit comments