Search Apps Documentation Source Content File Folder Download Copy Actions Download

bit_math.gno

2.53 Kb ยท 92 lines
 1package gnsmath
 2
 3import (
 4	u256 "gno.land/p/gnoswap/uint256"
 5)
 6
 7var (
 8	msbShifts = []bitShift{
 9		{u256.Zero().Lsh(u256.One(), 128), 128}, // 2^128
10		{u256.Zero().Lsh(u256.One(), 64), 64},   // 2^64
11		{u256.Zero().Lsh(u256.One(), 32), 32},   // 2^32
12		{u256.Zero().Lsh(u256.One(), 16), 16},   // 2^16
13		{u256.Zero().Lsh(u256.One(), 8), 8},     // 2^8
14		{u256.Zero().Lsh(u256.One(), 4), 4},     // 2^4
15		{u256.Zero().Lsh(u256.One(), 2), 2},     // 2^2
16		{u256.Zero().Lsh(u256.One(), 1), 1},     // 2^1
17	}
18
19	lsbShifts = []bitShift{
20		{u256.Zero().Sub(u256.Zero().Lsh(u256.One(), 128), u256.One()), 128}, // 2^128 - 1
21		{u256.Zero().Sub(u256.Zero().Lsh(u256.One(), 64), u256.One()), 64},   // 2^64 - 1
22		{u256.Zero().Sub(u256.Zero().Lsh(u256.One(), 32), u256.One()), 32},   // 2^32 - 1
23		{u256.Zero().Sub(u256.Zero().Lsh(u256.One(), 16), u256.One()), 16},   // 2^16 - 1
24		{u256.Zero().Sub(u256.Zero().Lsh(u256.One(), 8), u256.One()), 8},     // 2^8 - 1
25		{u256.NewUint(0xf), 4}, // 2^4 - 1 = 15
26		{u256.NewUint(0x3), 2}, // 2^2 - 1 = 3
27		{u256.NewUint(0x1), 1}, // 2^1 - 1 = 1
28	}
29)
30
31// bitShift represents a bit pattern and corresponding shift amount for bit manipulation.
32type bitShift struct {
33	bitPattern *u256.Uint
34	shift      uint
35}
36
37// BitMathMostSignificantBit returns the 0-based position of the most significant bit in x.
38// This function is essential for AMM calculations involving price ranges and tick boundaries.
39//
40// Parameters:
41//   - x: the value for which to compute the most significant bit
42//
43// Returns the index of the most significant bit (0-255).
44//
45// Panics if x is zero.
46func BitMathMostSignificantBit(x *u256.Uint) uint8 {
47	if x.IsZero() {
48		panic(errMSBZeroInput)
49	}
50
51	temp := x.Clone()
52	r := uint8(0)
53
54	for _, s := range msbShifts {
55		if temp.Gte(s.bitPattern) {
56			temp = temp.Rsh(temp, s.shift)
57			r += uint8(s.shift)
58		}
59	}
60
61	return r
62}
63
64// BitMathLeastSignificantBit returns the 0-based position of the least significant bit in x.
65// This function is used in AMM calculations for efficient bit manipulation and range queries.
66//
67// Parameters:
68//   - x: the value for which to compute the least significant bit
69//
70// Returns the index of the least significant bit (0-255).
71//
72// Panics if x is zero.
73func BitMathLeastSignificantBit(x *u256.Uint) uint8 {
74	if x.IsZero() {
75		panic(errLSBZeroInput)
76	}
77
78	temp := x.Clone()
79	hasSetBits := u256.Zero()
80	r := uint8(255)
81
82	for _, s := range lsbShifts {
83		hasSetBits = hasSetBits.And(temp, s.bitPattern)
84		if !hasSetBits.IsZero() {
85			r -= uint8(s.shift)
86		} else {
87			temp = temp.Rsh(temp, s.shift)
88		}
89	}
90
91	return r
92}