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:
"Animation of Newton’s method" by Ralf Pfeifer is licensed under CC-BY-SA 3.0
Trapezoid method:
"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:
What would code? Solve the equation?
– Pablo Almeida
Solve the equation in code form
– Weriky Alphazero
You want to find the value of
j
?– Jefferson Quesado
Yes I intend to find the value of j
– Weriky Alphazero
I can provide a numerical approximation, I don’t know exact solution for equations of this type. I will post soon
– Jefferson Quesado
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]
– Weriky Alphazero
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
– Jefferson Quesado
@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.
– Victor Stafusa
It would really help, thank you!
– Weriky Alphazero
750=((1-(1+j) (-10))/j*)86
– user60252
@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?
– Jefferson Quesado
so that it doesn’t seem to be the j multiplied by 86, but everything that is between parentheses that is multiplied by 86.
– user60252
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
– user60252