|
| 1 | +package rfqmath |
| 2 | + |
| 3 | +import ( |
| 4 | + "math/big" |
| 5 | + |
| 6 | + "golang.org/x/exp/constraints" |
| 7 | +) |
| 8 | + |
| 9 | +// Arithmetic defines the basic arithmetic operations. The structure of the |
| 10 | +// interfaces allows for chaining the arithmetic operations. |
| 11 | +type Arithmetic[N any] interface { |
| 12 | + // Add returns the sum of the two numbers. |
| 13 | + Add(N) N |
| 14 | + |
| 15 | + // Mul returns the product of the two numbers. |
| 16 | + Mul(N) N |
| 17 | + |
| 18 | + // Sub returns the difference of the two numbers. |
| 19 | + Sub(N) N |
| 20 | + |
| 21 | + // Div returns the division of the two numbers. |
| 22 | + Div(N) N |
| 23 | +} |
| 24 | + |
| 25 | +// Int is an interface that represents an integer types and the operations we |
| 26 | +// care about w.r.t that type. |
| 27 | +type Int[N any] interface { |
| 28 | + // Arithmetic asserts that the target type of this interface satisfies |
| 29 | + // the Arithmetic interface. This lets us get around limitations |
| 30 | + // regarding recursive types in Go. |
| 31 | + Arithmetic[N] |
| 32 | + |
| 33 | + // Equals returns true if the two integers are equal. |
| 34 | + Equals(other N) bool |
| 35 | + |
| 36 | + // ToFloat converts the integer to a float. |
| 37 | + ToFloat() float64 |
| 38 | + |
| 39 | + // FromFloat converts a float to the integer type. |
| 40 | + FromFloat(float64) N |
| 41 | + |
| 42 | + // ToUint64 converts the integer to a uint64. |
| 43 | + ToUint64() uint64 |
| 44 | + |
| 45 | + // FromUint64 converts a uint64 to the integer type. |
| 46 | + FromUint64(uint64) N |
| 47 | +} |
| 48 | + |
| 49 | +// NewInt creates a new integer of the target type. |
| 50 | +func NewInt[N Int[N]]() N { |
| 51 | + var n N |
| 52 | + return n |
| 53 | +} |
| 54 | + |
| 55 | +// GoInt is a concrete implementation of the Int interface for the set of |
| 56 | +// built-in integer types. It ends up mapping the integers to a uint64 |
| 57 | +// internally for operations. |
| 58 | +type GoInt[T constraints.Unsigned] struct { |
| 59 | + value T |
| 60 | +} |
| 61 | + |
| 62 | +// NewGoInt creates a new GoInt from the given integer. |
| 63 | +func NewGoInt[T constraints.Unsigned](value T) GoInt[T] { |
| 64 | + return GoInt[T]{ |
| 65 | + value: value, |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +// Add returns the sum of the two integers. |
| 70 | +func (b GoInt[T]) Add(other GoInt[T]) GoInt[T] { |
| 71 | + return GoInt[T]{ |
| 72 | + value: b.value + other.value, |
| 73 | + } |
| 74 | +} |
| 75 | + |
| 76 | +// Mul returns the product of the two integers. |
| 77 | +func (b GoInt[T]) Mul(other GoInt[T]) GoInt[T] { |
| 78 | + return GoInt[T]{ |
| 79 | + value: b.value * other.value, |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +// Sub returns the difference of the two integers. |
| 84 | +func (b GoInt[T]) Sub(other GoInt[T]) GoInt[T] { |
| 85 | + return GoInt[T]{ |
| 86 | + value: b.value - other.value, |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +// Div returns the division of the two integers. |
| 91 | +func (b GoInt[T]) Div(other GoInt[T]) GoInt[T] { |
| 92 | + return GoInt[T]{ |
| 93 | + value: b.value / other.value, |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +// ToFloat converts the integer to a float. |
| 98 | +func (b GoInt[T]) ToFloat() float64 { |
| 99 | + return float64(b.value) |
| 100 | +} |
| 101 | + |
| 102 | +// FromFloat converts a float to the integer type. |
| 103 | +func (b GoInt[T]) FromFloat(f float64) GoInt[T] { |
| 104 | + b.value = T(f) |
| 105 | + return b |
| 106 | +} |
| 107 | + |
| 108 | +// ToUint64 converts the integer to a uint64. |
| 109 | +func (b GoInt[T]) ToUint64() uint64 { |
| 110 | + return uint64(b.value) |
| 111 | +} |
| 112 | + |
| 113 | +// FromUint64 converts a uint64 to the integer type. |
| 114 | +func (b GoInt[T]) FromUint64(u uint64) GoInt[T] { |
| 115 | + b.value = T(u) |
| 116 | + return b |
| 117 | +} |
| 118 | + |
| 119 | +// Equals returns true if the two integers are equal. |
| 120 | +func (b GoInt[T]) Equals(other GoInt[T]) bool { |
| 121 | + return b.value == other.value |
| 122 | +} |
| 123 | + |
| 124 | +// A compile-time constraint to ensure that the GoInt type implements the Int |
| 125 | +// interface. |
| 126 | +var _ Int[GoInt[uint]] = GoInt[uint]{} |
| 127 | + |
| 128 | +// BigInt is a concrete implementation of the Int interface using Go's big |
| 129 | +// integer type. |
| 130 | +type BigInt struct { |
| 131 | + value *big.Int |
| 132 | +} |
| 133 | + |
| 134 | +// NewBigInt creates a new BigInt from the given integer. |
| 135 | +func NewBigInt(value *big.Int) BigInt { |
| 136 | + return BigInt{ |
| 137 | + value: value, |
| 138 | + } |
| 139 | +} |
| 140 | + |
| 141 | +// copyInt returns a copy of the internal big.Int. This is used to ensure we |
| 142 | +// don't mutate the underlying bit.Int during arithmetic operations. |
| 143 | +func (b BigInt) copyInt() *big.Int { |
| 144 | + return new(big.Int).Set(b.value) |
| 145 | +} |
| 146 | + |
| 147 | +// Add returns the sum of the two integers. |
| 148 | +func (b BigInt) Add(other BigInt) BigInt { |
| 149 | + return BigInt{ |
| 150 | + value: b.copyInt().Add(b.value, other.value), |
| 151 | + } |
| 152 | +} |
| 153 | + |
| 154 | +// Mul returns the product of the two integers. |
| 155 | +func (b BigInt) Mul(other BigInt) BigInt { |
| 156 | + return BigInt{ |
| 157 | + value: b.copyInt().Mul(b.value, other.value), |
| 158 | + } |
| 159 | +} |
| 160 | + |
| 161 | +// Sub returns the difference of the two integers. |
| 162 | +func (b BigInt) Sub(other BigInt) BigInt { |
| 163 | + return BigInt{ |
| 164 | + value: b.copyInt().Sub(b.value, other.value), |
| 165 | + } |
| 166 | +} |
| 167 | + |
| 168 | +// Div returns the division of the two integers. |
| 169 | +func (b BigInt) Div(other BigInt) BigInt { |
| 170 | + return BigInt{ |
| 171 | + value: b.copyInt().Div(b.value, other.value), |
| 172 | + } |
| 173 | +} |
| 174 | + |
| 175 | +// ToFloat converts the integer to a float. |
| 176 | +func (b BigInt) ToFloat() float64 { |
| 177 | + floatVal, _ := b.value.Float64() |
| 178 | + return floatVal |
| 179 | +} |
| 180 | + |
| 181 | +// FromFloat converts a float to the integer type. |
| 182 | +func (b BigInt) FromFloat(f float64) BigInt { |
| 183 | + if b.value == nil { |
| 184 | + b.value = new(big.Int) |
| 185 | + } |
| 186 | + |
| 187 | + b.value.SetInt64(int64(f)) |
| 188 | + return b |
| 189 | +} |
| 190 | + |
| 191 | +// FromUint64 converts a uint64 to the integer type. |
| 192 | +func (b BigInt) FromUint64(u uint64) BigInt { |
| 193 | + if b.value == nil { |
| 194 | + b.value = new(big.Int) |
| 195 | + } |
| 196 | + |
| 197 | + b.value.SetUint64(u) |
| 198 | + return b |
| 199 | +} |
| 200 | + |
| 201 | +// ToUint64 converts the integer to a uint64. |
| 202 | +func (b BigInt) ToUint64() uint64 { |
| 203 | + return b.value.Uint64() |
| 204 | +} |
| 205 | + |
| 206 | +// Equals returns true if the two integers are equal. |
| 207 | +func (b BigInt) Equals(other BigInt) bool { |
| 208 | + return b.value.Cmp(other.value) == 0 |
| 209 | +} |
| 210 | + |
| 211 | +// A compile-time constraint to ensure that the BigInt type implements the Int |
| 212 | +// interface. |
| 213 | +var _ Int[BigInt] = BigInt{} |
0 commit comments