I have the following variables where all values are multiplied by 1e18 to represent fixed-point numbers on the EVM:

uint totalShares = 100;
uint sharesAlice = 20;
uint sharesBob = 30;
uint sharesCharlie = 50;
uint undervalue = n; //invariant

function getNum(uint shares_) public returns(uint) {
   return shares_.mulDiv(n, totalShares);

I have now the following statement that derives from the snippet above, proven to be true:

getNum(totalShares) != getNum(sharesAlice) + getNum(sharesBob) + getNum(sharesCharlie);

Why is this statement true and how can I make it not true (meaning that both values in the statement are equal?

I think it has something to do with rounding errors and the limit that 18 decimals place into irrational numbers. If this is true, my main question would be then how do I brake that statement (aka make both values equal)?


  • What's the value of n? Nov 30, 2023 at 6:08
  • It's indifferent. What matters is that it's a constant value that never changes. @ZartajAfser
    – dNyrM
    Nov 30, 2023 at 10:37
  • That's why I am asking. It might be the reason for rounding up of integers and returning true for the above statement. Nov 30, 2023 at 10:59
  • More than the reason, I'm looking for the solution. I think that the issue is the rounding, but I'd like to turn that statement into false. And one of the constraints of the operation is the invariant, that doesn't change. @ZartajAfser
    – dNyrM
    Nov 30, 2023 at 18:41
  • Mate, as long as you don't find the reason for the error, how are you supposed to solve that error? Dec 1, 2023 at 4:10

1 Answer 1


The reason I asked for the value of n is because it is the only part affecting your code. I tried implementing the same logic and guess what, I found out that when I gave undervalue a value of 1 ether it returned false for the statement, and when I gave it a random value of 12345 it returned true as in your case.

1 ether and 12345 are just examples, what I meant was when the value of underValue is something ending with zeroes then it doesn't round up the output.

The value of undervalue determines the value of bool because the rest of everything is fine.

Here is the code I used, you can try it out on remix:

contract abc {
    uint256 totalShares = 100;
    uint256 sharesAlice = 20;
    uint256 sharesBob = 30;
    uint256 sharesCharlie = 50;
    uint256 undervalue = 12345; //Try with this value and then 1 ether. 

    function getNum(uint256 shares_) public view returns (uint256) {
        return mulDiv(shares_, undervalue, totalShares);

    function mulDiv(
        uint256 a,
        uint256 b,
        uint256 c
    ) internal pure returns (uint256) {
        return (a * b) / c;

    function compare() external view returns (bool) {
            getNum(totalShares) !=
            getNum(sharesAlice) + getNum(sharesBob) + getNum(sharesCharlie);

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.