6

I'm trying to calculate a percentage of a number in solidity with the following code.

The percentage is technically basis points (10000ths, instead of 100ths) because I want decimal percentage values.

uint128 is enough for expressing the normal numbers, but to try to avoid precision errors, I cast the values to int256 for the calculation.

pragma solidity 0.4.24;
contract PercentageCalc {
  uint128 public bp = 185; // 1.85% in basis points (parts per 10,000)

  function calculatePercentage(
    uint128 theNumber
  )
  public
  view
  returns (uint128) {
    return uint128(int256(theNumber) / int256(10000) * int256(bp));
  }
}

The problem is if I input 111111111111111111 as theNumber, the output is 2055555555555535 instead of the desired output of 2055555555555555 (what I get by doing the calculation with for example BigNumber.js).

I'm guessing it is some precision error I have overlooked. How do it get the desired output of 2055555555555555?

  • 1
    MULTIPLY BEFORE YOU DIVIDE!!! (and make sure that the multiplication doesn't overflow of course). – goodvibration Aug 2 '18 at 13:30
9

Do the multiplication first:

return theNumber * bp / 10000;

The problem with dividing first is that the result is an integer, so it chops off anything that drops behind the decimal point.

The thing to watch out for when multiplying first is integer overflow, so make sure your numbers are in an appropriate range where such multiplication won't exceed the maximum value of your data type.

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.