Fixed Point Numbers
Much of the math in the ReserveManager contract involves fractional numbers. To represent these values, we use 256-bit integers, where:
- 96 bits are reserved for the integer component
- 96 bits are reserved for the fractional component
Note: This is the minimum that the developer really needs to understand about fixed point numbers. Our SDK provides a fixed type with easy conversions and all the necessary operations to emulate any pool action
To convert a number to or from fixed-point format, multiply it by 2^FRACTIONAL_BITS — in our case, 2^96.
This can be done more efficiently using a bit shift by FRACTIONAL_BITS.
Solidity Example
uint256 x = 5;
uint256 fixedPoint = x << 96; // equivalent to multiplying by 2^96
uint256 original = fixedPoint >> 96; // convert back to integerMultiplying and Dividing Fixed Point Numbers
When multiplying or dividing two fixed-point numbers, you must account for the scaling factor being doubled or removed during the operation.
Multiplication
For example, consider two fixed-point representations of the number 1:
1in 160.96 fixed-point is1 * 2^96- Multiplying two fixed-point numbers:
1 * 2^96 * 1 * 2^96 = 1 * 2^192
→ We’re now scaled by an extra factor of2^96, so we need to divide it out afterward.
Solidity Example
uint256 one = 1 << 96; // fixed-point 1.0
uint256 product = (one * one) >> 96; // rescale back to 160.96 format
uint256 quotient = (one << 96) / one; // pre-shift by 96 bits to avoid precision lossFor easier conversions outside of solidity where the developer normally has access to floating point numbers, you can calculate the value in floating-point format by casting it as a float and dividing it by 2^FRACTIONAL_BITS.
const floatVal = Number(fixedVal) / (2 ** FRACTIONAL_BITS) Note that converting from fixed to floating point involves slight precision loss, if your application requires exact emulation of the pool you must use fixed point numbers in the exact same way that the pool does.