0

I hope this question is not asked, but i googled too much and tried to find out the problem my self.

I'm trying to get a dynamic percentage using SafeMath

uint256 lowNumber = 316442921;
uint256 highNumber = 632885842;
uint256 distanceFromHigherNumber = 544386085;

In daily math i found a way to calculate that but it won't work here.

result = ((distanceFromHigherNumber - lowNumber) / (highNumber - lowNumber)) * 100;
percentage = 100 - result // in percentage should be ~ 28%

In solidity i did it this way:

uint256 result = (distanceFromHigherNumber.sub(lowNumber) / highNumber.sub(lowNumber)) * 100;
uint256 percentage = 100 - result;

It returns always 100, i guess it is maybe returning 1 instead of 0.72 and when i'm multiplying it by 100, when i play around it a little bit i get only zero or 100.

Any help please, i'm too new to solidity.

2 Answers 2

1

Solidity has no concept of floating-point numbers, so you need to work on an integer representation of your number.

Your idea is good, but the order of operations won't work on integers.

result = ((x - low) / (high - low))

Will always return a number between 0 and 1 by definition (unless you allow x < low or x > high but it wouldn't make any sense). Solidity only deals with integers, so it will return either 0 or 1, nothing in between. When you multiply this value by 100, you get either 0 or 100...

You need to multiply before doing the division, to immediately generate a number between 0 and 100 (or more depending on the precision that you are looking for).

This code returns the percentage that you are looking for when given 544386085 as parameter : 72.

pragma solidity ^0.7.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/math/SafeMath.sol";

    contract Percentage {
    
        using SafeMath for uint256;
        
        uint256 high = 632885842;  
        uint256 low =  316442921;
        uint256 precision = 2;
    
        function getPercentage(uint256 x) public view returns (uint256) {
            
            require(x >= low, "Number too low");
            require(x <= high, "Number too high");
            
            return x.sub(low).mul(10 ** precision) / high.sub(low);
        }
    }

Btw, SafeMath is superfluous here, since if you know that x >= low and x <= high (due to the require statements) there is no overflow / undeflow possible.

2
  • Thanks @hroussille it worked, really thanks. you saved my day. Now i can go to sleep :)
    – Ton Gok
    Nov 22, 2021 at 23:08
  • It worked for me! Thanks! But I'm wondering how to get a value based on the porcentage. May 22, 2023 at 17:59
-1
   contract c{
using SafeMath for uint256;
uint256 lowNumber = 316442921;
uint256 highNumber = 632885842;
uint256 distanceFromHigherNumber = 544386085;
unit percent = 100;
uint256 result = ((distanceFromHigherNumber.sub(lowNumber)).div(highNumber.sub(lowNumber))).mul(percent);
uint256 percentage = percent.sub(result);

}

You need to make sure that you have the using SafeMath for uint256; at the top of your contract and should be using sub, div, add, mul instead of the symbols. Whole point of using safeMath is to avoid using such characters. Also, check with brackets in the result.

Hope it helps. look at this documentation as well. https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol

2
  • I did exactly as you said, it returns 100 back
    – Ton Gok
    Nov 22, 2021 at 22:58
  • Don't do exactly what i did. I mentioned in my answer that you have to play around with it. I just gave you an idea on how to use safemath. Nov 23, 2021 at 10:36

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.