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);
Update
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.