-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rfqmath: implement fixed point based arithmetic for RFQ
- Loading branch information
Showing
55 changed files
with
2,313 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# RFQ math | ||
|
||
This package contains code related to fixed point arithmetics used in RFQ | ||
exchange rate calculations. | ||
|
||
The high-level/conceptual explanation of [how RFQ (and related concepts such | ||
as the decimal display value and price oracles) works, can be found | ||
in this separate document](../docs/rfq-and-decimal-display.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
package rfqmath | ||
|
||
import ( | ||
"math/big" | ||
|
||
"golang.org/x/exp/constraints" | ||
) | ||
|
||
// Arithmetic defines the basic arithmetic operations. The structure of the | ||
// interfaces allows for chaining the arithmetic operations. | ||
type Arithmetic[N any] interface { | ||
// Add returns the sum of the two numbers. | ||
Add(N) N | ||
|
||
// Mul returns the product of the two numbers. | ||
Mul(N) N | ||
|
||
// Sub returns the difference of the two numbers. | ||
Sub(N) N | ||
|
||
// Div returns the division of the two numbers. | ||
Div(N) N | ||
} | ||
|
||
// Int is an interface that represents an integer types and the operations we | ||
// care about w.r.t that type. | ||
type Int[N any] interface { | ||
// Arithmetic asserts that the target type of this interface satisfies | ||
// the Arithmetic interface. This lets us get around limitations | ||
// regarding recursive types in Go. | ||
Arithmetic[N] | ||
|
||
// Equals returns true if the two integers are equal. | ||
Equals(other N) bool | ||
|
||
// ToFloat converts the integer to a float. | ||
ToFloat() float64 | ||
|
||
// FromFloat converts a float to the integer type. | ||
FromFloat(float64) N | ||
|
||
// ToUint64 converts the integer to a uint64. | ||
ToUint64() uint64 | ||
|
||
// FromUint64 converts a uint64 to the integer type. | ||
FromUint64(uint64) N | ||
} | ||
|
||
// NewInt creates a new integer of the target type. | ||
func NewInt[N Int[N]]() N { | ||
var n N | ||
return n | ||
} | ||
|
||
// GoInt is a concrete implementation of the Int interface for the set of | ||
// built-in integer types. It ends up mapping the integers to a uint64 | ||
// internally for operations. | ||
type GoInt[T constraints.Unsigned] struct { | ||
value T | ||
} | ||
|
||
// NewGoInt creates a new GoInt from the given integer. | ||
func NewGoInt[T constraints.Unsigned](value T) GoInt[T] { | ||
return GoInt[T]{ | ||
value: value, | ||
} | ||
} | ||
|
||
// Add returns the sum of the two integers. | ||
func (b GoInt[T]) Add(other GoInt[T]) GoInt[T] { | ||
return GoInt[T]{ | ||
value: b.value + other.value, | ||
} | ||
} | ||
|
||
// Mul returns the product of the two integers. | ||
func (b GoInt[T]) Mul(other GoInt[T]) GoInt[T] { | ||
return GoInt[T]{ | ||
value: b.value * other.value, | ||
} | ||
} | ||
|
||
// Sub returns the difference of the two integers. | ||
func (b GoInt[T]) Sub(other GoInt[T]) GoInt[T] { | ||
return GoInt[T]{ | ||
value: b.value - other.value, | ||
} | ||
} | ||
|
||
// Div returns the division of the two integers. | ||
func (b GoInt[T]) Div(other GoInt[T]) GoInt[T] { | ||
return GoInt[T]{ | ||
value: b.value / other.value, | ||
} | ||
} | ||
|
||
// ToFloat converts the integer to a float. | ||
func (b GoInt[T]) ToFloat() float64 { | ||
return float64(b.value) | ||
} | ||
|
||
// FromFloat converts a float to the integer type. | ||
func (b GoInt[T]) FromFloat(f float64) GoInt[T] { | ||
b.value = T(f) | ||
return b | ||
} | ||
|
||
// ToUint64 converts the integer to a uint64. | ||
func (b GoInt[T]) ToUint64() uint64 { | ||
return uint64(b.value) | ||
} | ||
|
||
// FromUint64 converts a uint64 to the integer type. | ||
func (b GoInt[T]) FromUint64(u uint64) GoInt[T] { | ||
b.value = T(u) | ||
return b | ||
} | ||
|
||
// Equals returns true if the two integers are equal. | ||
func (b GoInt[T]) Equals(other GoInt[T]) bool { | ||
return b.value == other.value | ||
} | ||
|
||
// A compile-time constraint to ensure that the GoInt type implements the Int | ||
// interface. | ||
var _ Int[GoInt[uint]] = GoInt[uint]{} | ||
|
||
// BigInt is a concrete implementation of the Int interface using Go's big | ||
// integer type. | ||
type BigInt struct { | ||
value *big.Int | ||
} | ||
|
||
// NewBigInt creates a new BigInt from the given integer. | ||
func NewBigInt(value *big.Int) BigInt { | ||
return BigInt{ | ||
value: value, | ||
} | ||
} | ||
|
||
// copyInt returns a copy of the internal big.Int. This is used to ensure we | ||
// don't mutate the underlying bit.Int during arithmetic operations. | ||
func (b BigInt) copyInt() *big.Int { | ||
return new(big.Int).Set(b.value) | ||
} | ||
|
||
// Add returns the sum of the two integers. | ||
func (b BigInt) Add(other BigInt) BigInt { | ||
return BigInt{ | ||
value: b.copyInt().Add(b.value, other.value), | ||
} | ||
} | ||
|
||
// Mul returns the product of the two integers. | ||
func (b BigInt) Mul(other BigInt) BigInt { | ||
return BigInt{ | ||
value: b.copyInt().Mul(b.value, other.value), | ||
} | ||
} | ||
|
||
// Sub returns the difference of the two integers. | ||
func (b BigInt) Sub(other BigInt) BigInt { | ||
return BigInt{ | ||
value: b.copyInt().Sub(b.value, other.value), | ||
} | ||
} | ||
|
||
// Div returns the division of the two integers. | ||
func (b BigInt) Div(other BigInt) BigInt { | ||
return BigInt{ | ||
value: b.copyInt().Div(b.value, other.value), | ||
} | ||
} | ||
|
||
// ToFloat converts the integer to a float. | ||
func (b BigInt) ToFloat() float64 { | ||
floatVal, _ := b.value.Float64() | ||
return floatVal | ||
} | ||
|
||
// FromFloat converts a float to the integer type. | ||
func (b BigInt) FromFloat(f float64) BigInt { | ||
if b.value == nil { | ||
b.value = new(big.Int) | ||
} | ||
|
||
b.value.SetInt64(int64(f)) | ||
return b | ||
} | ||
|
||
// FromUint64 converts a uint64 to the integer type. | ||
func (b BigInt) FromUint64(u uint64) BigInt { | ||
if b.value == nil { | ||
b.value = new(big.Int) | ||
} | ||
|
||
b.value.SetUint64(u) | ||
return b | ||
} | ||
|
||
// ToUint64 converts the integer to a uint64. | ||
func (b BigInt) ToUint64() uint64 { | ||
return b.value.Uint64() | ||
} | ||
|
||
// Equals returns true if the two integers are equal. | ||
func (b BigInt) Equals(other BigInt) bool { | ||
return b.value.Cmp(other.value) == 0 | ||
} | ||
|
||
// A compile-time constraint to ensure that the BigInt type implements the Int | ||
// interface. | ||
var _ Int[BigInt] = BigInt{} |
Oops, something went wrong.