Деление/проценты являются обязательной частью многих приложений, но их сложно реализовать, поскольку fixed
они ufixed
еще не поддерживаются в Solidity. Я придумал этот обходной путь:
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);
}
}
Если я хочу получить 12% от 27 и коллировать percent(27, 12)
, я правильно возвращаюсь 3
и 24
представляю 3.24
. Ограничение этого, конечно, в том, что это percent(12.5, 100)
невозможно.
Однако, если я звоню percent(17, 359)
, я возвращаюсь 61
и 3
. Однако реальный результат таков 61.03
, потому что fractional
0 uint
перед 3 отбрасывается. Есть ли способ узнать, есть ли у дробной части начальный нуль?
На мой взгляд, это, вероятно, неуместное использование логики в цепочке не только из-за сопутствующей неуклюжести кода, но и из-за затрат на газ, связанных с выполнением того, что вызывающий абонент может легко понять для себя.
Сказав это, можно было бы иметь дело с десятичными знаками, используя что-то вроде этого: Невозможно выполнить целочисленное деление
Эта интерпретация возвращает целое число процентов, правильно округленное в большую сторону. Например, 23,5% возвращает 24. Вы можете увеличить точность десятичных дробей, изменив то, как он работает с целочисленными преобразованиями.
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;
}
}
Надеюсь, поможет.
ОБНОВЛЯТЬ
Чтобы сделать обратное, следующим образом. Кроме того, увеличьте порядок, чтобы вернуть результат с более высокой точностью.
Здесь 12 на 27 (12,27) возвращает 324, что клиент может интерпретировать как 32,4%.
function getFraction(uint percent, uint base) public pure returns(uint portion) {
uint temp = percent * base * 10 + 5;
return temp / 10;
}
Основной вывод — работать с целыми числами. Хитрость с +5
и /10
заключается в том, чтобы обеспечить правильное округление.
(17, 359)
например, вернет 5
. Однако я имею в виду создание способа узнать точное целое и дробное число.uint
.Как упоминал Роб, работайте с целым числом. Я придумываю другой способ. В моем сценарии я должен хранить процентную ставку с базовой суммой. Чтобы найти процент и добавить к базовой сумме, формула выглядит следующим образом:
y = amount + (amount * percentValue / 100)
y = (100 * amount) + (amount * percentValue) /100
y*100 = amount * (100 + percentValue)
здесь y в основном ожидаемый результат. Я не делю значение на 100, поэтому значение останется целым, а во внешней части я делю значение и сохраняю только вывод
amount(100 + percentValue)
в солидности.
Шон Табризи
хорошая вибрация
X * Y
и100
. Не делитеX * Y
на,100
пока не дойдете до того момента, когда вам это действительно нужно. Например, предположим, что позже в вашем коде вам нужно умножить это значение наZ
, тогда в этот момент вы делаетеX * Y * Z / 100
.хорошая вибрация
Адибас03
100/3 = 0.03
и100/24 = 0.24