// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; library MulDivMath { // compute res = floor(a * b / c), assuming res < 2^256 function mulDivFloor( uint256 a, uint256 b, uint256 c ) internal pure returns (uint256 res) { // let prodMod2_256 = a * b % 2^256 uint256 prodMod2_256; // let prodDiv2_256 = a * b / 2^256 uint256 prodDiv2_256; assembly { let prodModM1 := mulmod(a, b, not(0)) prodMod2_256 := mul(a, b) prodDiv2_256 := sub(sub(prodModM1, prodMod2_256), lt(prodModM1, prodMod2_256)) } if (prodDiv2_256 == 0) { require(c > 0); assembly { res := div(prodMod2_256, c) } return res; } // we should ensure that a * b /c < 2^256 before calling require(c > prodDiv2_256); uint256 resMod; assembly { resMod := mulmod(a, b, c) // a * b - resMod prodDiv2_256 := sub(prodDiv2_256, gt(resMod, prodMod2_256)) prodMod2_256 := sub(prodMod2_256, resMod) // compute lowbit of c let lowbit := not(c) lowbit := add(lowbit, 1) lowbit := and(lowbit, c) // c / lowbit c := div(c, lowbit) // a * b / lowbit prodMod2_256 := div(prodMod2_256, lowbit) lowbit := add(div(sub(0, lowbit), lowbit), 1) prodDiv2_256 := mul(prodDiv2_256, lowbit) prodMod2_256 := or(prodMod2_256, prodDiv2_256) // get inv of c // cInv * c = 1 (mod 2^4) let cInv := xor(mul(3, c), 2) cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^8 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^16 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^32 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^64 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^128 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^256 // a * b / c = prodMod2_256 * cInv (mod 2^256) res := mul(prodMod2_256, cInv) } } // compute res = ceil(a * b / c), assuming res < 2^256 function mulDivCeil( uint256 a, uint256 b, uint256 c ) internal pure returns (uint256 res) { res = mulDivFloor(a, b, c); if (mulmod(a, b, c) > 0) { require(res < type(uint256).max); res++; } } }