0

Division/percentages is a required part of many applications but is difficult to implement since fixed and ufixed are not supported yet in Solidity. I've come up with this workaround:

  pragma solidity ^0.4.9;

  contract Math {

    function Math() public {}

    function percent(uint a, uint b) public constant returns(uint, uint) {
      uint c = a*b;
      uint integer = c/100;
      uint fractional = c%100;
      return (integer, fractional);
    }

  }

If I want to get 12% of 27 and call percent(27, 12), I correctly get back 3 and 24 representing 3.24. The limitation to this of course is that percent(12.5, 100) isn't possible.

However if I call percent(17, 359), I get back 61 and 3. The real result is 61.03, however, because fractional is a uint, the 0 in front of the 3 is dropped. Is there a way to find out if a fractional has a leading zero?

  • Using your logic, wouldn't any number < 10 have a leading zero for the fractional? Otherwise, it would return a 2 digit number between 10-99. – Shawn Tabrizi Jul 5 '18 at 20:35
  • There's no general solution here, because the number of leading zeros in the decimal part can be anything. You should probably do some self-thinking, on why you've established this requirement to begin with. In order to represent X% out of Y in full accuracy, you need to maintain a pair of numbers - numerator and denominator. More precisely - X * Y and 100. Don't divide X * Y by 100 until you get to the point where you really need it. For example, suppose that later in your code you need to multiply this value by Z, then at this point you do X * Y * Z / 100. – goodvibration Jul 6 '18 at 6:55
  • And of course, if you want to support fractional percentage as well, then you can increase 100 to whatever resolution you wish to achieve (i.e., 1000, 10000, etc). – goodvibration Jul 6 '18 at 6:57
  • I think you have the solution with indicating the resolution as @goodvibration described. Also your program already gives the right answer; as 100/3 = 0.03, and 100/24 = 0.24 – Adibas03 Jul 6 '18 at 8:14
0

In my opinion this is probably an inappropriate use of on-chain logic, not only because of the attendant awkwardness of the code, but also because of the gas cost involved in doing something the caller can easily figure out for themselves.

Having said that, one could deal with decimal places using something like this: Can't do any integer division

This interpretation returns an integer percentage properly rounded up. For example, 23.5% returns 24. You could increase the decimals of precision by tinkering with the way it plays with the integer conversions.

pragma solidity 0.4.24;

contract Percent {

    function getPercent(uint part, uint whole) public pure returns(uint percent) {
        uint numerator = part * 1000;
        require(numerator > part); // overflow. Should use SafeMath throughout if this was a real implementation. 
        uint temp = numerator / whole + 5; // proper rounding up
        return temp / 10;
    }
}

Hope it helps.

UPDATE

To do the reverse, as follows. Also, increase the order of magnitude to return a result with higher precision.

Here, 12 over 27 (12,27) returns 324 which the client can interpret as 32.4%.

function getFraction(uint percent, uint base) public pure returns(uint portion) {
    uint temp = percent * base * 10 + 5;
    return temp / 10;
}

The main takeaway is to work with integers. The trickery with +5 and /10 is to ensure correct rounding up.

  • Thanks Rob, testing your function using (17, 359) for example would return 5. However, I'm referring to creating a way to know the exact integer and fractional. – Mr. T Jul 6 '18 at 18:20
  • The link you referenced works similar to my code and has the same problem; the leading zero gets lost once stored in a uint. – Mr. T Jul 6 '18 at 18:23
  • I added another example. – Rob Hitchens - B9lab Jul 6 '18 at 21:10
0

As rob mentioned work with integer. I come up with other way around. In my scenerio i have to store the interest rate with the base amount. To find the percentage and add with the base amount the formula is as below

y = amount + (amount * percentValue / 100)
y = (100 * amount) + (amount * percentValue) /100
y*100 = amount * (100 + percentValue)

here y is basically the expected output. I am not dividing the value with 100 so the value will remain integer and on the frontend part I divide the value and i only store the output of

amount(100 + percentValue)

in solidity.

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.