Division in Ethereum Solidity
Asked Answered
A

2

17

I am creating a contract that issues tokens. I would like an account that holds tokens to be able to check what percentage they own out of all the tokens issued. I know that Ethereum has not implemented floating point numbers yet. What should I do?

Augusto answered 11/3, 2017 at 17:56 Comment(0)
S
24

It's probably best (lowest gas cost and trivial to implement) to perform that calculation on the client rather than in Solidity.

If you find you need it in Solidity, then it's just a matter of working with integers by shifting the decimal point. Similar to: https://en.wikipedia.org/wiki/Parts-per_notation

For example, this function let's you decide the degree of precision and uses one extra degree of precision to correctly round up:

pragma solidity ^0.4.6;

contract Divide {

  function percent(uint numerator, uint denominator, uint precision) public 

  constant returns(uint quotient) {

         // caution, check safe-to-multiply here
        uint _numerator  = numerator * 10 ** (precision+1);
        // with rounding of last digit
        uint _quotient =  ((_numerator / denominator) + 5) / 10;
        return ( _quotient);
  }

}

If you feed it 101,450, 3 you get 224, i.e. 22.4%.

Hope it helps.

Statius answered 11/3, 2017 at 19:49 Comment(8)
This would be needed for a calculation of how much the contract is able to pay out for the given token holder. For example if a token holder owns 20 tokens and there are 100 total tokens. The contract needs to be able to decide that 20 tokens is worth 20% of the total ether in the contract. The total ether may be 5 eth for example. Could I divide Wei? How would this work?Augusto
Fair enough, and No. The Wei is the smallest unit so you have to decide what to do with remainders. If you're going for full precision, then track fractional Wei using higher precision user balances as state variables ... occasional settlement when cumulative balance is large enough. Remember, it will cost gas to actually move a single unit of Wei so think about the efficiency of moving small amounts around.Statius
Ok, so how would I multiply that percentage? I would first need to turn it into a decimal (not sure how to do that), than I would need to multiply it by the [this].balance? By the way thanks for the help.Augusto
Well, if you pass 20,100,3 then you get 200 - let's call it "portion"), meaning 200 parts per thousand, or 20.0%. So, you can have as much precision as you need. Then, you could say amountToDivide * portion / 1000. 1,000 is 3(the original precision)**10. I corrected an oversight in the function so it correctly rounds up. BTW, "convert to decimal" is a shorthand I've heard in financial circles ... means multiply by 100. Nothing special. Also, comment about "safe-to" is in case you are dealing with large numbers that could overflow and do nasty things.Statius
So in what conditions would it not be safe to multiply?Augusto
Overflow. If the number is too large for uint256 it won't throw ... it'll just toss the high order bits and return a small number. Why you see example like if(a+b<a) throw; in the docs. Need to think that through for this case. Something like if(numerator*10*(precision+1) < numerator) throw; ... I would think it through a little more before I would say I'm sure about that check. Hopefully communicates the idea.Statius
Sorry for the silly question, but what is "5" from Rob's quotient equation?Pinwork
It handles rounding up because otherwise, Solidity truncates.Statius
S
0

You could use binary point or fixed number representation. Introduction to Fixed Point Number Representation For example

 11010.1 in base2 = 1 * 24 + 1 * 23 + 0 * 22 + 1 * 21 + 0* 20 + 1 * 2-1 = 26.5

Percentage is calculated by

  // x is the percentage
  a/b = x/100 => x= (100*a)/b

to calculate the division of big numbers, you can use FixidityLib.sol library.

function divide(Fixidity storage fixidity, int256 a, int256 b) public view returns (int256) {
    if(b == fixidity.fixed_1) return a;
    assert(b != 0);
    return multiply(fixidity, a, reciprocal(fixidity, b));
}

There are too many mathematical libraries or contracts and each implements divide operation differently:

FloatMath.sol

DSMath Contract

abdk-libraries-solidity

openzeppelin-contracts

Sasnett answered 16/11, 2022 at 2:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.