0

how do I convert this code (javascript code) into solidity code and it will work?

function pmt(rate_per_period, number_of_payments, present_value, future_value){
if(rate_per_period != 0.0){
    // Interest rate exists
    var q = Math.pow(1 + rate_per_period, number_of_payments);
    return (rate_per_period * (future_value + (q * present_value))) / ((q-1) * (1 + rate_per_period ));

} else if(number_of_payments != 0.0){
    // No interest rate, but number of payments exists
    return -(future_value + present_value) / number_of_payments;
}

return 0;}

already did this function :

function PMT(uint _rate,uint256 _term,uint _pv) public view returns (uint)
{
     uint q = ((1 + _rate) ** _term);
    return (_rate *  (((1 + _rate) ** _term) * _pv)) / ((((1 + _rate) ** _term)-1) * (1+_rate));
}

and, how do I represent the decimal value in solidity? Fixed point numbers are not fully supported by Solidity yet. They can be declared, but cannot be assigned to or from.

for example the function parameters:

pmt(0.0025,12,700000);

*************EDIT

multiply function wont work

the arguments of the PMT :

  1. totalFunding (700000)
  2. totalMonths (12)
  3. totalYears(1)
  4. annualYieldInterest(3% - 0.03)

if i will power them via 10 ** 2 = 100 the parameters will be:

  1. totalFunding (70000000)
  2. totalMonths (1200)
  3. totalYears(100)
  4. annualYieldInterest(3% - 0.03 - 3)

before I start to calculate PMT function I have to calculate the parameters he gets:

  1. totalFunding : 70000000
  2. rate:3/1200 - 0.0025 (via the parameters above)
  3. totalMonths:12

so still I get float value.

2 Answers2

1

You may use ABDK Math 64.64 library. It has all functions you need (add, sub, mul, div, neg, pow) and operates with fixed point numbers. Note, that is uses binary rather than decimal fixed point, with 64 binary digits after dot. So, in order to convert decimal number into binary fixed point you basically need to multiply it by 2^64. To convert from fixed point to decimal, just divide by 2^64.

Using this library, your Javascript function may be ported to Solidity like this:

function pmt (
  int128 rate_per_period, int128 number_of_payments,
  int128 present_value, int128 future_value) public pure returns (int128) {
  if (rate_per_period != 0) {
    // Interest rate exists
    int128 q =
      ABDKMath64x64.pow (
        ABDKMath64x64.add (
          0x10000000000000000,
          rate_per_period),
        ABDKMath64x64.toUInt (
          number_of_payments));
    return
      ABDKMath64x64.div (
        ABDKMath64x64.mul (
          rate_per_period,
          ABDKMath64x64.add (
            future_value,
            ABDKMath64x64.mul (
              q,
              present_value))),
        ABDKMath64x64.mul (
          ABDKMath64x64.sub (
            q,
            0x10000000000000000),
          ABDKMath64x64.add (
            0x10000000000000000,
            rate_per_period)));
  } else if (number_of_payments != 0) {
    // No interest rate, but number of payments exists
    return
      ABDKMath64x64.div (
        ABDKMath64x64.neg (
          ABDKMath64x64.add (
            future_value,
            present_value)),
        number_of_payments);
  } else return 0;
}

Note that 1 became 0x10000000000000000, i.e. 2^64. You will need to multiply all arguments by 2^64 before passing them to this function, and you will need to divide result by 2^64 before use.

I just tried this Solidity function in Remix with the following arguments:

rate_per_period = 0.03    // = 0x7AE147AE147AE14 / 2^64
number_of_payments = 10.0 // = 0xA0000000000000000 / 2^64
present_value = 1.0       // = 0x10000000000000000 / 2^64
future_value = 2.0        // = 0x20000000000000000 / 2^64

and it returned me 0.2832 (= 0x487F82986F5A14DC / 2^64), which is the same as your Javascript functions returns for these parameters.

Mikhail Vladimirov
  • 13,572
  • 1
  • 38
  • 40
0

Your best bet is to multiply all values by a power of 10, such that you no longer have floating point numbers. Then perform your calculations, and divide the resulting value by 10**decimals outside the contract.

This is the same approach various tokens use for tracking balances.

Raghav Sood
  • 81,899
  • 22
  • 187
  • 195