mirror of
https://github.com/Instadapp/dsa-governance.git
synced 2024-07-29 22:27:52 +00:00
156 lines
7.2 KiB
Solidity
156 lines
7.2 KiB
Solidity
// SPDX-License-Identifier: BUSL-1.1
|
|
pragma solidity 0.8.21;
|
|
|
|
/// @title library that represents a number in BigNumber(coefficient and exponent) format to store in smaller bits.
|
|
/// @notice the number is divided into two parts: a coefficient and an exponent. This comes at a cost of losing some precision
|
|
/// at the end of the number because the exponent simply fills it with zeroes. This precision is oftentimes negligible and can
|
|
/// result in significant gas cost reduction due to storage space reduction.
|
|
/// Also note, a valid big number is as follows: if the exponent is > 0, then coefficient last bits should be occupied to have max precision.
|
|
/// @dev roundUp is more like a increase 1, which happens everytime for the same number.
|
|
/// roundDown simply sets trailing digits after coefficientSize to zero (floor), only once for the same number.
|
|
library BigMathMinified {
|
|
/// @dev constants to use for `roundUp` input param to increase readability
|
|
bool internal constant ROUND_DOWN = false;
|
|
bool internal constant ROUND_UP = true;
|
|
|
|
/// @dev converts `normal` number to BigNumber with `exponent` and `coefficient` (or precision).
|
|
/// e.g.:
|
|
/// 5035703444687813576399599 (normal) = (coefficient[32bits], exponent[8bits])[40bits]
|
|
/// 5035703444687813576399599 (decimal) => 10000101010010110100000011111011110010100110100000000011100101001101001101011101111 (binary)
|
|
/// => 10000101010010110100000011111011000000000000000000000000000000000000000000000000000
|
|
/// ^-------------------- 51(exponent) -------------- ^
|
|
/// coefficient = 1000,0101,0100,1011,0100,0000,1111,1011 (2236301563)
|
|
/// exponent = 0011,0011 (51)
|
|
/// bigNumber = 1000,0101,0100,1011,0100,0000,1111,1011,0011,0011 (572493200179)
|
|
///
|
|
/// @param normal number which needs to be converted into Big Number
|
|
/// @param coefficientSize at max how many bits of precision there should be (64 = uint64 (64 bits precision))
|
|
/// @param exponentSize at max how many bits of exponent there should be (8 = uint8 (8 bits exponent))
|
|
/// @param roundUp signals if result should be rounded down or up
|
|
/// @return bigNumber converted bigNumber (coefficient << exponent)
|
|
function toBigNumber(
|
|
uint256 normal,
|
|
uint256 coefficientSize,
|
|
uint256 exponentSize,
|
|
bool roundUp
|
|
) internal pure returns (uint256 bigNumber) {
|
|
assembly {
|
|
let lastBit_
|
|
let number_ := normal
|
|
if gt(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
|
|
number_ := shr(0x80, number_)
|
|
lastBit_ := 0x80
|
|
}
|
|
if gt(number_, 0xFFFFFFFFFFFFFFFF) {
|
|
number_ := shr(0x40, number_)
|
|
lastBit_ := add(lastBit_, 0x40)
|
|
}
|
|
if gt(number_, 0xFFFFFFFF) {
|
|
number_ := shr(0x20, number_)
|
|
lastBit_ := add(lastBit_, 0x20)
|
|
}
|
|
if gt(number_, 0xFFFF) {
|
|
number_ := shr(0x10, number_)
|
|
lastBit_ := add(lastBit_, 0x10)
|
|
}
|
|
if gt(number_, 0xFF) {
|
|
number_ := shr(0x8, number_)
|
|
lastBit_ := add(lastBit_, 0x8)
|
|
}
|
|
if gt(number_, 0xF) {
|
|
number_ := shr(0x4, number_)
|
|
lastBit_ := add(lastBit_, 0x4)
|
|
}
|
|
if gt(number_, 0x3) {
|
|
number_ := shr(0x2, number_)
|
|
lastBit_ := add(lastBit_, 0x2)
|
|
}
|
|
if gt(number_, 0x1) {
|
|
lastBit_ := add(lastBit_, 1)
|
|
}
|
|
if gt(number_, 0) {
|
|
lastBit_ := add(lastBit_, 1)
|
|
}
|
|
if lt(lastBit_, coefficientSize) {
|
|
// for throw exception
|
|
lastBit_ := coefficientSize
|
|
}
|
|
let exponent := sub(lastBit_, coefficientSize)
|
|
let coefficient := shr(exponent, normal)
|
|
if and(roundUp, gt(exponent, 0)) {
|
|
// rounding up is only needed if exponent is > 0, as otherwise the coefficient fully holds the original number
|
|
coefficient := add(coefficient, 1)
|
|
if eq(shl(coefficientSize, 1), coefficient) {
|
|
// case were coefficient was e.g. 111, with adding 1 it became 1000 (in binary) and coefficientSize 3 bits
|
|
// final coefficient would exceed it's size. -> reduce coefficent to 100 and increase exponent by 1.
|
|
coefficient := shl(sub(coefficientSize, 1), 1)
|
|
exponent := add(exponent, 1)
|
|
}
|
|
}
|
|
if iszero(lt(exponent, shl(exponentSize, 1))) {
|
|
// if exponent is >= exponentSize, the normal number is too big to fit within
|
|
// BigNumber with too small sizes for coefficient and exponent
|
|
revert(0, 0)
|
|
}
|
|
bigNumber := shl(exponentSize, coefficient)
|
|
bigNumber := add(bigNumber, exponent)
|
|
}
|
|
}
|
|
|
|
/// @dev get `normal` number from `bigNumber`, `exponentSize` and `exponentMask`
|
|
function fromBigNumber(
|
|
uint256 bigNumber,
|
|
uint256 exponentSize,
|
|
uint256 exponentMask
|
|
) internal pure returns (uint256 normal) {
|
|
assembly {
|
|
let coefficient := shr(exponentSize, bigNumber)
|
|
let exponent := and(bigNumber, exponentMask)
|
|
normal := shl(exponent, coefficient)
|
|
}
|
|
}
|
|
|
|
/// @dev gets the most significant bit `lastBit` of a `normal` number (length of given number of binary format).
|
|
/// e.g.
|
|
/// 5035703444687813576399599 = 10000101010010110100000011111011110010100110100000000011100101001101001101011101111
|
|
/// lastBit = ^--------------------------------- 83 ----------------------------------------^
|
|
function mostSignificantBit(uint256 normal) internal pure returns (uint lastBit) {
|
|
assembly {
|
|
let number_ := normal
|
|
if gt(normal, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
|
|
number_ := shr(0x80, number_)
|
|
lastBit := 0x80
|
|
}
|
|
if gt(number_, 0xFFFFFFFFFFFFFFFF) {
|
|
number_ := shr(0x40, number_)
|
|
lastBit := add(lastBit, 0x40)
|
|
}
|
|
if gt(number_, 0xFFFFFFFF) {
|
|
number_ := shr(0x20, number_)
|
|
lastBit := add(lastBit, 0x20)
|
|
}
|
|
if gt(number_, 0xFFFF) {
|
|
number_ := shr(0x10, number_)
|
|
lastBit := add(lastBit, 0x10)
|
|
}
|
|
if gt(number_, 0xFF) {
|
|
number_ := shr(0x8, number_)
|
|
lastBit := add(lastBit, 0x8)
|
|
}
|
|
if gt(number_, 0xF) {
|
|
number_ := shr(0x4, number_)
|
|
lastBit := add(lastBit, 0x4)
|
|
}
|
|
if gt(number_, 0x3) {
|
|
number_ := shr(0x2, number_)
|
|
lastBit := add(lastBit, 0x2)
|
|
}
|
|
if gt(number_, 0x1) {
|
|
lastBit := add(lastBit, 1)
|
|
}
|
|
if gt(number_, 0) {
|
|
lastBit := add(lastBit, 1)
|
|
}
|
|
}
|
|
}
|
|
} |