Selaa lähdekoodia

Optimized gas costs in `ceilDiv` (#4553)

carter-ya 1 vuosi sitten
vanhempi
sitoutus
e5fb718d40
3 muutettua tiedostoa jossa 18 lisäystä ja 6 poistoa
  1. 5 0
      .changeset/angry-dodos-grow.md
  2. 8 2
      contracts/utils/math/Math.sol
  3. 5 4
      test/utils/math/Math.t.sol

+ 5 - 0
.changeset/angry-dodos-grow.md

@@ -0,0 +1,5 @@
+---
+'openzeppelin-solidity': minor
+---
+
+`Math`: Optimized gas cost of `ceilDiv` by using `unchecked`.

+ 8 - 2
contracts/utils/math/Math.sol

@@ -110,8 +110,14 @@ library Math {
             return a / b;
         }
 
-        // (a + b - 1) / b can overflow on addition, so we distribute.
-        return a == 0 ? 0 : (a - 1) / b + 1;
+        // 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;
+        }
     }
 
     /**

+ 5 - 4
test/utils/math/Math.t.sol

@@ -16,10 +16,11 @@ contract MathTest is Test {
         if (result == 0) {
             assertEq(a, 0);
         } else {
-            uint256 maxdiv = UINT256_MAX / b;
-            bool overflow = maxdiv * b < a;
-            assertTrue(a > b * (result - 1));
-            assertTrue(overflow ? result == maxdiv + 1 : a <= b * result);
+            uint256 expect = a / b;
+            if (expect * b < a) {
+                expect += 1;
+            }
+            assertEq(result, expect);
         }
     }