4

Say you have two uint256 numbers, x, and y. One way to calculate the arithmetic average between them is this:

function avg(uint256 x, uint256 y) external returns (uint256 result) {
    result = (x + y) / 2;
}

But this doesn't work when the intermediate result x + y does not fit into uint256.

A seemingly better approach is the following:

function avg(uint256 x, uint256 y) external returns (uint256 result) {
    result = x / 2 + y / 2;
}

This doesn't overflow, but it doesn't work when both x and y are odd numbers - the 0.5 remainder is lost twice. Actually, if you'd prefer to round up the result, this doesn't work if either of x or y is an odd number.

How to take the average of two uint256 numbers in Solidity without overflowing?

1
  • 1
    When x <= y the average can be calculated as x + (y - x) / 2. – Ismael Mar 29 at 16:24
4

After posting the question, I realised I gave the answer myself.

I simply have to check if both x and y are odd numbers and, if yes, add 1 to the result:

function avg(uint256 x, uint256 y) external returns (uint256 result) {
    result = x / 2 + y / 2;
    if (x % 2 == 1 && y % 2 == 1) {
        result += 1;
    }
}

Update: I ended up optimising the function, since I found it rather expensive at ~210 gas. I wrapped the code in an unchecked block, used the bitwise operator AND instead of the MOD operation and finally applied De Morgan's law:

function avg(uint256 x, uint256 y) external view returns (uint256 result) {
    unchecked {
        result = (x >> 1) + (y >> 1);
        if (!(x & 1 == 0 || y & 1 == 0)) {
            result += 1;
        }
    }
}

Which reduced the cost to ~82 gas.

2nd Update: I managed to save even more gas by getting rid of the if block:

function avg(uint256 x, uint256 y) external view returns (uint256 result) {
    unchecked {
        result = (x >> 1) + (y >> 1) + (x & y & 1);
    }
}

Which reduced the gas cost to ~60.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.