I was trying to compile the mulDiv function, part of the uniswap-v3-core code base, but I am getting the following error:

Unary operator - cannot be applied to type uint256

This is the line where it breaks:

uint256 twos = -denominator & denominator;

I am using Solidity v0.8.3, while they used Solidity v0.7.6.

This doesn't seem to be listed in the v0.8.0 breaking changes. How can I make it work in v0.8 while ensuring that the logic stays the same?


The unary operator - negates the given number. It is easier to see what it does with signed integers. If we use the int8 type and we negate the positive number 10, we get -10 back.

Now, unsigned integers can't represent negative numbers, of course. What Solidity does when negating an uint8 x (in v0.7 and below) is to return type(uint8).max - x + 1. For example, negating 10 gives us 246.

The following function that I wrote returns true for all possible values of x:

function checkNegativeUnary(uint8 x) external pure returns (bool result) {
    uint8 a = -x;
    uint8 b = type(uint8).max - x + 1;
    result = a == b;

Since it seems like Solidity v0.8 forbids the negation of unsigned integers now, to make the mulDiv compile we should rewrite that denominator like this:

uint256 twos = (type(uint256).max - denominator + 1) & denominator;

This doesn't overflow because denominator can never be 0, due to another check made earlier in the function:

// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);


I managed to find a shorter implementation, as per the answers in this Q&A I started in the CS SE: How to find the largest power of two divisor of a given integer?:

uint256 twos = denominator & (~denominator + 1);

Note that this is faster than the other solution only if you're using checked arithmetic.


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.