Java financial math equation

Asked

Viewed 439 times

5

How can I encode this equation in Java?

750=(1-(1+j)^(-10))/j*86

inserir a descrição da imagem aqui

  • What would code? Solve the equation?

  • Solve the equation in code form

  • You want to find the value of j?

  • Yes I intend to find the value of j

  • I can provide a numerical approximation, I don’t know exact solution for equations of this type. I will post soon

  • Although it’s not what I’m looking for, it’s always good to learn something new. Send it to me if you can by email or right here >> [email protected]

  • I will post as an answer, interest here on this site help the community creating a knowledge base than simply take a doubt and that answer get lost

  • @Jeffersonquesado That’s why it’s a formula of financial mathematics. I implemented in javascript a very similar last semester of my post. I’ll see if I can find her.

  • It would really help, thank you!

  • 750=((1-(1+j) (-10))/j*)86

  • @Leocaracciolo? I did not understand your comment... was to put in evidence that the 86 multiplies the division as a whole and not just the denominator?

  • so that it doesn’t seem to be the j multiplied by 86, but everything that is between parentheses that is multiplied by 86.

  • so that it doesn’t seem to be the j multiplied by 86, but everything that is between parentheses that is multiplied by 86. Alias i tb erred in the placement of last parenthesis the correct is 750=((1-(1+j) (-10))/j)*86

Show 8 more comments

2 answers

5

I’m using the trapezoid method to solve this equation. This method also refers to the name "secant method".

The trapezoid method is very close to that of the Newton-Raphson algorithm, but instead of using the derivative uses the difference between two given points to search for the next try point. It is not all the functions that fit the use of this method to find its roots. This equation of yours, for example, is not.

Newton-Raphson method:

Método de Newton-Raphson

"Animation of Newton’s method" by Ralf Pfeifer is licensed under CC-BY-SA 3.0

Trapezoid method:

Método dos trapézios

"Illustration of the Secant method" Jitse Niesen, public domain.

I played in the Wolframalpha to know one of the real roots and see if I can get close.

import java.util.function.DoubleUnaryOperator;

public class ResolucaoTrapezio {
    private Double raiz;
    private Integer iteracoesTotal;
    private Double errRaiz;

    public boolean achouRaiz() {
        return raiz != null;
    }

    public Double getRaiz() {
        return raiz;
    }

    public Double getErrRaiz() {
        return errRaiz;
    }

    public Integer getIteracoesTotal() {
        return iteracoesTotal;
    }

    public ResolucaoTrapezio(DoubleUnaryOperator func, double x0, double x1, double err, int iteracoes) {
        achaRaiz(func, x0, x1, err, iteracoes);
    }

    public void achaRaiz(DoubleUnaryOperator func, double x0, double x1, double err, int iteracoes) {
        double y0, y1;

        y0 = func.applyAsDouble(x0);
        if (diffErrAceitavel(y0, err)) {
            iteracoesTotal = 0;
            raiz = x0;
            errRaiz = -y0;
            return;
        }

        for (int it = 0; it < iteracoes; it++) {
            y1 = func.applyAsDouble(x1);

            if (diffErrAceitavel(y1, err)) {
                iteracoesTotal = it + 1;
                raiz = x1;
                errRaiz = -y1;
                return;
            }

            // entrou em laço infinito =(
            if (y1 == y0) {
                break;
            }

            // próximo passo, achando o próximo x
            double x2 = x0 - y0*(x1 - x0)/(y1 - y0);

            // atualizando: x_{i} <-- x_{i-1}
            x0 = x1;
            x1 = x2;

            // atualizando: y0 recebe o último y encontrado
            y0 = y1;
        }
        iteracoesTotal = null;
        raiz = null;
        errRaiz = null;
        return;
    }

    private static boolean diffErrAceitavel(double y0, double err) {
        return Math.abs(y0) < err;
    }
}

This object, from the constructor, tries to find the answer using the trapezoid method. It has some purposeful limitations to avoid divergent processing, such as rectangle detection and number of iterations. It also considers that the root is a number close enough to zero according to a past error. I’m using 7 decimal places of accuracy, so the error is guaranteed to be less than 0.0000001.

If the root cannot be found, the value of getRaiz() and of getErrRaiz() will be null. I am always saving how many iterations I used to come to the conclusion that I arrived at the root or diverged from getIteracoesTotal().

For your function, I used the following formula:

(j) -> {
    double q0 = 750;
    double n = 10;
    double p = 86;

    return p*(1 -  Math.pow(1 + j, -n)) / j - q0;
}

If you want to find the value of another variable, just put the variable as a parameter and set the value of j. For example hypothetical:

(n) -> {
    double q0 = 750;
    double p = 86;
    double j = 0.0256902;

    return p*(1 -  Math.pow(1 + j, -n)) / j - q0;
}

An example of calling this object is the following:

    public static void main(String[] args) {
        ResolucaoTrapezio resTrap = new ResolucaoTrapezio((j) -> {
            double q0 = 750;
            double n = 10;
            double p = 86;

            return p*(1 -  Math.pow(1 + j, -n)) / j - q0;
        }, -1.8, -1.5, 0.00000001, 1000);

        System.out.println("resolução da equação: " + resTrap.getRaiz() + ", nessa quantidade de iterações: " + resTrap.getIteracoesTotal() + " (erro " + resTrap.getErrRaiz() + ")");
    }

The output obtained was:

resolução da equação: -1.756371998522421, nessa quantidade de iterações: 10 (erro -3.410605131648481E-13)

Here, in the trapezoid method finding the first two good values is fundamental. The @Victorstafusa suggested that I should start with 0.25 and 0.5.

Testing the @Victorstafusa suggestion:

resolução da equação: null, nessa quantidade de iterações: 1000 (erro null)

Well, it diverged...

So, we can try to guess what are the starting points for this function... Let’s start from 0.001 until 0.9 as x0, step of 0.0001. Let’s make sure x1 difira de x0 one delta amid 0.00001 to 0.5 of x0 varying with each step 0.00001.

I can do it through the following for:

for (double x0 = 0.001; x0 <= 0.9; x0 += 0.0001) {
    for (double delta = 0.0001; delta <= 0.5; delta += 0.0001) {
        double x1 = x0 + delta;
        // processamento desejado aqui
    }
}

Trying to find the root...

public static void main(String[] args) {
    DoubleUnaryOperator f = (j) -> {
        double q0 = 750;
        double n = 10;
        double p = 86;

        return p*(1 -  Math.pow(1 + j, -n)) / j - q0;
    };

    int divergencias = 0;
    int convergencias = 0;
    int totalIteracoesAcc = 0;
    for (double x0 = 0.001; x0 <= 0.9; x0 += 0.0001) {
        for (double delta = 0.0001; delta <= 0.5; delta += 0.0001) {
            double x1 = x0 + delta;

            ResolucaoTrapezio resTrap = new ResolucaoTrapezio(f, x0, x1, 0.00000001, 1000);

            totalIteracoesAcc += resTrap.getIteracoesTotal();

            if (resTrap.achouRaiz()) {
                if (convergencias < 10) {
                    System.out.println(String.format("ACHOU RAIZ... parâmetros: x0 = %f x1 = %f; raiz = %f (err = %f); iterações %d", x0, x1, resTrap.getRaiz(), resTrap.getErrRaiz(), resTrap.getIteracoesTotal()));
                }
                convergencias++;
            } else {
                if (divergencias < 10) {
                    System.out.println(String.format("não achou raiz... parâmetros: x0 = %f x1 = %f; iterações %d", x0, x1, resTrap.getIteracoesTotal()));
                }
                divergencias++;
            }
            System.out.println(String.format("Já rodamos %d iterações ao todo; %d convergências, %d divergências", totalIteracoesAcc, convergencias, divergencias));
        }
    }
}

Exit:

ACHOU RAIZ... parâmetros: x0 = 0,001000 x1 = 0,001100; raiz = 0,025690 (err = -0,000000); iterações 6
Já rodamos 6 iterações ao todo; 1 convergências, 0 divergências
ACHOU RAIZ... parâmetros: x0 = 0,001000 x1 = 0,001200; raiz = 0,025690 (err = -0,000000); iterações 6
Já rodamos 12 iterações ao todo; 2 convergências, 0 divergências
ACHOU RAIZ... parâmetros: x0 = 0,001000 x1 = 0,001300; raiz = 0,025690 (err = -0,000000); iterações 6
Já rodamos 18 iterações ao todo; 3 convergências, 0 divergências
[... omitido por questão de porque sim ...]

Well, we found the root. Happy? I’m =D

Out of curiosity, if the algorithm ran for all possible combinations of x0 and x1, the time it would take...

Rodamos ao todo -1825970073 iterações ao todo; 12818639 convergências, 32136361 divergências
Tempo total: 519060 ms

Well, you blew the whole thing, I’ll put one long that should hold. I’ll also put long for the number of convergences and divergences due to doubts...

New result, now no overflow whole:

Rodamos ao todo 32533768295 iterações ao todo; 12818639 convergências, 32136361 divergências
Tempo total: 492871 ms

Reservation regarding the typing

I’m one of the greatest advocates that, when you’re dealing with financial math and money, you should use BigDecimal.

However, the solution to this problem was via numerical methods. It is so much so that I may not find the real root, but I have found a value that is to a maximum error of 1e-7 of 0. The calculations and results of these numerical methods carry an intrinsic error that does not fit the exact type BigDecimal, but it’s up to the scientific type double.

Read more:

  • In fact, I had suggested 0.25 and 0.5.

  • Sorry, I’ll update now... I found that the number of iterations above exceeds the int (just finished the execution)

  • Divergiu =P Nor will I need to change my answer too much

  • Thanks for the clarification

3


This one performs the calculation using the bisection method, looking for the j in the range of 105 up to 1. He works with BigDecimals rounding divisions to 21 decimal places and working with a margin of error of 105 gross value of q0 found to accept the solution.

Here’s the code:

import java.math.BigDecimal;
import java.math.RoundingMode;

class Calculo {

    private static final BigDecimal CEM = new BigDecimal(100);
    private static final BigDecimal DOIS = new BigDecimal(2);

    private static final int PRECISAO_CALCULO = 21;
    private static final int PRECISAO_FINAL = 5;

    private static final BigDecimal DELTA =
            BigDecimal.ONE.divide(BigDecimal.TEN.pow(PRECISAO_FINAL));

    private static final BigDecimal financiamento(int n, BigDecimal j, BigDecimal p) {
        BigDecimal a = BigDecimal.ONE.add(j).pow(n);

        BigDecimal b = BigDecimal.ONE.divide(
                a,
                PRECISAO_CALCULO,
                RoundingMode.HALF_EVEN);

        return BigDecimal.ONE
                .subtract(b)
                .multiply(p)
                .divide(j, PRECISAO_CALCULO, RoundingMode.HALF_EVEN);
    }

    private static final BigDecimal taxaFinanciamento(
            BigDecimal q0,
            int n,
            BigDecimal p)
    {
        BigDecimal j1 = DELTA;
        BigDecimal j2 = BigDecimal.ONE;
        BigDecimal q1 = financiamento(n, j1, p);
        BigDecimal q2 = financiamento(n, j2, p);
        BigDecimal m1 = q1.subtract(q0);
        BigDecimal m2 = q2.subtract(q0);
        if (m1.abs().compareTo(DELTA) <= 0) return j1;
        if (m2.abs().compareTo(DELTA) <= 0) return j2;
        for (int i = 0; i < 50; i++) {
            if (m1.signum() == m2.signum()) {
                throw new ArithmeticException("Fora do intervalo"
                        + ": q1=[" + q1 + "], j1=[" + j1 + "], m1=[" + m1 + "]"
                        + ", q2=[" + q2 + "], j2=[" + j2 + "], m2=[" + m2 + "]"
                        + ", i=" + i);
            }
            BigDecimal j3 = j1.add(j2).divide(DOIS);
            BigDecimal q3 = financiamento(n, j3, p);
            BigDecimal m3 = q3.subtract(q0);
            if (m3.abs().compareTo(DELTA) <= 0) return j3;
            if (m3.signum() == m1.signum()) {
                q1 = q3;
                j1 = j3;
            } else {
                q2 = q3;
                j2 = j3;
            }
        }
        throw new ArithmeticException("Não convergiu"
                + ": q1=[" + q1 + "], j1=[" + j1 + "], m1=[" + m1 + "]"
                + ", q2=[" + q2 + "], j2=[" + j2 + "], m2=[" + m2 + "]");
    }

    private static void teste(int q0, int p, int n) {
        BigDecimal bdq0Ideal = new BigDecimal(q0);
        BigDecimal bdp = new BigDecimal(p);
        BigDecimal j = taxaFinanciamento(bdq0Ideal, n, bdp);
        BigDecimal bdq0Obtido = financiamento(n, j, bdp);
        System.out.println("----------");
        System.out.println("q0-ideal=[" + bdq0Ideal + "]");
        System.out.println("p=[" + bdp + "]");
        System.out.println("j=[" + j + "]");
        System.out.println("q0-obtido=[" + bdq0Obtido + "]");
        System.out.println("----------");
        System.out.println();
    }

    public static void main(String[] args) {
        teste(750, 86, 10);
        teste(750, 85, 10);
    }
}

Here’s the way out:

----------
q0-ideal=[750]
p=[86]
j=[0.025690244208984076976776123046875]
q0-obtido=[749.999997639096753068406]
----------

----------
q0-ideal=[750]
p=[85]
j=[0.023429261477030813694000244140625]
q0-obtido=[749.999996056141438963093]
----------

This exit means that:

  • For a value of p = 86 and a q0 desired of 750, it has been calculated that a j = 2,5690244...% produces a q0 = 749,99999763...

  • For a value of p = 85 and a q0 desired of 750, it has been calculated that a j = 2,3429261...% produces a q0 = 749,99999605...

See here working on ideone.

  • From what I have just read about this method, it is much more suitable to the case. In the trapezoid method, the possibility of it diverging is much greater

  • What would be the mistake of not converged? I realized that if I put the value of the portion at 85 it returns this error Exception in thread "AWT-Eventqueue-0" java.lang.Arithmeticexception: Not converged: 749.92995258177 0.0234472656267621283632252016104757785797119140625 749.92995258175 0.023447265626763016532763117538706865161656573333740234375

  • @Werikyalphazero This meant that after 50 attempts, he gave up and could not find the solution, showing the nearest value he reached. However, I have reviewed and edited the code and corrected this error. Now it can solve this case.

  • Thanks for the help

Browser other questions tagged

You are not signed in. Login or sign up in order to post.