Solving trigon equation numerically with JS browser
Given values for variables s
, v
and h
, and also for a library like numeric.js how can I numerically solve the following equation for a
with a certain degree of precision?
I want to use JS algorithm for browser use.
-
this is a transcendental equation
I am assuming a real domain , in which case you cannot separate the unknown from it (in general), but you can still solve it numerically (as you suggested)
-
I'm too lazy to do the right analysis
2a.sinh(h/2a)=sqrt(s.s-v.v)
but if I see it correctly, it
2a.sinh(h/2a)
is monotonic, so letc=sqrt(s.s-v.v)
's keep it simple and quick. Since I see itc >= 0
, so ifh >= 0
, thena = <0,+inf)
-
find the value crossing
double a0,a1,da=initial accuracy step; for (a1=0.0;2a.sinh(h/2a)<=sqrt(s.s-v.v);a1+=da);
now
a1
has an approximated upper boundary solutionfor (a0=a1;2a.sinh(h/2a)>sqrt(s.s-v.v);a0-=da);
now
a0
contains an approximate solution with a bounded boundary -
find the required solution accuracy
ifa0==a1
, then you have found the exact solution, so stop Iffabs(a1-a0)<=accuracy
you are in your accuracy, stop and lowerda
, for exampleda*=0.01;
, this will increase the accuracy100
once. Now look for a solution again, but only on an interval<a0,a1>
, and repeat this until a solution is found
[notes]
Another example of solving a transcendental equation: solving the Kepler equation . When nothing else works, you can still try this:
- How proximity search works
Separating variables and parameters
You can start by replacing b = a / h. This will turn your equation into
2b * sinh (1 / (2b)) = sqrt (s²-v²) / h
This way you have all the inputs on the right side and the variable on the left side, but unfortunately it still happens in a few places in transcendental form. The advantage is that we can now treat the right-hand side as a single number to get some idea of this function.
Look at the graph first
The function looks good enough:
So, you can standard numerical root search methods for example. Newton's method to find the position at which this function takes a given value (i.e. the value you are calculating from the right side). If you interpret the search for root as finding places where the function is zero, then the function for which you want to find zeros is the difference, i.e.
2a * sinh (h / (2a)) - sqrt (s²-v²)
Using optimizations from numeric.js
If you want to use numeric.js it numeric.uncmin
is most likely your best choice. At least this is the best I could find in the docs. (There may be some hungry implementation of root search out there, but if so, I haven't been able to find it yet.) You would try to find the minimum function
(2a * sinh (h / (2a)) - sqrt (s²-v²)) ²
is interpreted as a function of a and hopes that this minimum is actually (close to zero). You can get better results (like faster convergence and / or lower error) by also supplying the gradient (derivative) of this function as a separate argument. You can use Wolfram Alpha to find this derivative.
Further rewriting the function
Define f as f (b) = 2b * sinh (1 / (2b)). You are trying to figure out at which position f takes a given value. To speed up convergence, you can try to turn this f into another function that is close to linear. Playing with the plots I came up with this:
g (b) = (f (b) - 1) ^ (- 1/2)
You can apply the same transformation to the right to see the desired value for this function. For b> 0.06 this looks quite linear, so it should converge very quickly. If your parameters are expected in a range where it is almost linear, but even for a smaller b, it should be no worse than the original formulation. You can use a linear form to calculate the starting position of your Newton method, but I wouldn't bother: as long as you start with a large enough value, the first step of Newton's method will do just that.