2
function cells() public {
        uint256 canvas = 4000;
        uint256 c = 1;
        uint256 columns = 4;

        uint256 x = 400000000000000000 * (100000000000000 / 400000000000000);
        uint256 _x = canvas * (1 / 4 * (10**14));
}

I am facing an issue with the above code and I am baffled.

_x works as it is and returns the correct value 100000000000000000, however if I change to:

uint256 _x = canvas * (c / columns * (10**14));

The outcome of above is 0?

1 Answer 1

2

It's not underflow/overflow, which is when you try and store a value that's <0 or >2^256 into a uint256, the issue is loss of precision.

To walk through your example, solidity will solve the equation from left to right.

canvas * (c / columns * (10**14))

becomes

4000 * (1 / 4 * (10**14))

the first step would be to solve the 1/4 in the parenthesis. However, since you are doing uint math, you lose precision on any result that isn't a whole number. the .25 get rounded to 0, and as such, the next step becomes:

4000 * (0 * (10**14))

One way to solve this is to change the order of operations, so you do the multiplication first before division.

(canvas * c * 10**14)/columns

This still risks loss of precisions as the result will be rounded down to the nearest uint256. And as Shiyason mentioned, you have to consider overflow if the numerator result is larger than 256.

Overflow/underflow can be protected against using SafeMath, or you can use a library that handles >uint256 math such as FullMath: https://github.com/smartcontractkit/open-oracle/blob/c2bd41df808f49ea5a3bd7abc78d8d5745a28b3d/contracts/Uniswap/UniswapLib.sol

edit: updating link to FullMath library.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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