70 lines
2.1 KiB
Solidity
70 lines
2.1 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.36;
|
|
|
|
/// @title 512 bit multiply then divide without intermediate overflow.
|
|
library FullMath {
|
|
function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
|
|
unchecked {
|
|
uint256 prod0;
|
|
uint256 prod1;
|
|
assembly {
|
|
let mm := mulmod(a, b, not(0))
|
|
prod0 := mul(a, b)
|
|
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
|
|
}
|
|
|
|
if (prod1 == 0) {
|
|
require(denominator > 0, "FullMath: DIV_ZERO");
|
|
assembly {
|
|
result := div(prod0, denominator)
|
|
}
|
|
return result;
|
|
}
|
|
|
|
require(denominator > prod1, "FullMath: OVERFLOW");
|
|
|
|
uint256 remainder;
|
|
assembly {
|
|
remainder := mulmod(a, b, denominator)
|
|
}
|
|
assembly {
|
|
prod1 := sub(prod1, gt(remainder, prod0))
|
|
prod0 := sub(prod0, remainder)
|
|
}
|
|
|
|
uint256 twos = (0 - denominator) & denominator;
|
|
assembly {
|
|
denominator := div(denominator, twos)
|
|
}
|
|
assembly {
|
|
prod0 := div(prod0, twos)
|
|
}
|
|
assembly {
|
|
twos := add(div(sub(0, twos), twos), 1)
|
|
}
|
|
prod0 |= prod1 * twos;
|
|
|
|
uint256 inv = (3 * denominator) ^ 2;
|
|
inv *= 2 - denominator * inv;
|
|
inv *= 2 - denominator * inv;
|
|
inv *= 2 - denominator * inv;
|
|
inv *= 2 - denominator * inv;
|
|
inv *= 2 - denominator * inv;
|
|
inv *= 2 - denominator * inv;
|
|
|
|
result = prod0 * inv;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
|
|
unchecked {
|
|
result = mulDiv(a, b, denominator);
|
|
if (mulmod(a, b, denominator) > 0) {
|
|
require(result < type(uint256).max, "FullMath: ROUND_OVERFLOW");
|
|
result++;
|
|
}
|
|
}
|
|
}
|
|
}
|