Skip to content

Commit

Permalink
Add ceiling division operation to the Math.sol library (#2681)
Browse files Browse the repository at this point in the history
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
  • Loading branch information
3 people committed May 20, 2021
1 parent 5f7eda1 commit 7c754d0
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 3 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

## Unreleased

* `ERC20Votes`: add a new extension of the `ERC20` token with support for voting snapshots and delegation. This extension is compatible with Compound's `Comp` token interface. ([#2632](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2632))
* `ERC20Votes`: add a new extension of the `ERC20` token with support for voting snapshots and delegation. This extension is compatible with Compound's `Comp` token interface. ([#2632](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2632))
* Enumerables: Improve gas cost of removal in `EnumerableSet` and `EnumerableMap`.
* Enumerables: Improve gas cost of lookup in `EnumerableSet` and `EnumerableMap`.
* `Counter`: add a reset method. ([#2678](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2678))
* Tokens: Wrap definitely safe subtractions in `unchecked` blocks.
* `Math`: Add a `ceilDiv` method for performing ceiling division.

## 4.1.0 (2021-04-29)

Expand Down
4 changes: 4 additions & 0 deletions contracts/mocks/MathMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ contract MathMock {
function average(uint256 a, uint256 b) public pure returns (uint256) {
return Math.average(a, b);
}

function ceilDiv(uint256 a, uint256 b) public pure returns (uint256) {
return Math.ceilDiv(a, b);
}
}
11 changes: 11 additions & 0 deletions contracts/utils/math/Math.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,15 @@ library Math {
// (a + b) / 2 can overflow, so we distribute.
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}

/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a / b + (a % b == 0 ? 0 : 1);
}
}
29 changes: 27 additions & 2 deletions test/utils/math/Math.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { BN } = require('@openzeppelin/test-helpers');

const { BN, constants } = require('@openzeppelin/test-helpers');
const { expect } = require('chai');
const { MAX_UINT256 } = constants;

const MathMock = artifacts.require('MathMock');

Expand Down Expand Up @@ -55,4 +55,29 @@ contract('Math', function (accounts) {
expect(await this.math.average(a, b)).to.be.bignumber.equal(bnAverage(a, b));
});
});

describe('ceilDiv', function () {
it('does not round up on exact division', async function () {
const a = new BN('10');
const b = new BN('5');
expect(await this.math.ceilDiv(a, b)).to.be.bignumber.equal('2');
});

it('rounds up on division with remainders', async function () {
const a = new BN('42');
const b = new BN('13');
expect(await this.math.ceilDiv(a, b)).to.be.bignumber.equal('4');
});

it('does not overflow', async function () {
const b = new BN('2');
const result = new BN('1').shln(255);
expect(await this.math.ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(result);
});

it('correctly computes max uint256 divided by 1', async function () {
const b = new BN('1');
expect(await this.math.ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(MAX_UINT256);
});
});
});

0 comments on commit 7c754d0

Please sign in to comment.