Optimized gas costs in ceilDiv (#4553)
This commit is contained in:
5
.changeset/angry-dodos-grow.md
Normal file
5
.changeset/angry-dodos-grow.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'openzeppelin-solidity': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
`Math`: Optimized gas cost of `ceilDiv` by using `unchecked`.
|
||||||
@ -110,9 +110,15 @@ library Math {
|
|||||||
return a / b;
|
return a / b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (a + b - 1) / b can overflow on addition, so we distribute.
|
// The following calculation ensures accurate ceiling division without overflow.
|
||||||
|
// Since a is non-zero, (a - 1) / b will not overflow.
|
||||||
|
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
|
||||||
|
// but the largest value we can obtain is type(uint256).max - 1, which happens
|
||||||
|
// when a = type(uint256).max and b = 1.
|
||||||
|
unchecked {
|
||||||
return a == 0 ? 0 : (a - 1) / b + 1;
|
return a == 0 ? 0 : (a - 1) / b + 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
|
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
|
||||||
|
|||||||
@ -16,10 +16,11 @@ contract MathTest is Test {
|
|||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
assertEq(a, 0);
|
assertEq(a, 0);
|
||||||
} else {
|
} else {
|
||||||
uint256 maxdiv = UINT256_MAX / b;
|
uint256 expect = a / b;
|
||||||
bool overflow = maxdiv * b < a;
|
if (expect * b < a) {
|
||||||
assertTrue(a > b * (result - 1));
|
expect += 1;
|
||||||
assertTrue(overflow ? result == maxdiv + 1 : a <= b * result);
|
}
|
||||||
|
assertEq(result, expect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user