1

I would like to solve the following equation: tan(x) = 1/x

What I did:

syms x
eq = tan(x) == 1/x;
sol = solve(eq,x)

But this gives me only one numerical approximation of the solution. After that I read about the following:

[sol, params, conds] = solve(eq, x, 'ReturnConditions', true)

But this tells me that it can't find an explicit solution.

How can I find numerical solutions to this equation within some given range?

Dev-iL
  • 23,742
  • 7
  • 57
  • 99
user137425
  • 429
  • 6
  • 17

3 Answers3

3

I've never liked using solvers "blindly", that is, without some sort of decent initial value selection scheme. In my experience, the values you will find when doing things blindly, will be without context as well. Meaning, you'll often miss solutions, think something is a solution while in reality the solver exploded, etc.

For this particular case, it is important to realize that fzero uses numerical derivatives to find increasingly better approximations. But, derivatives for f(x) = x · tan(x) - 1 get increasingly difficult to accurately compute for increasing x:

enter image description here

As you can see, the larger x becomes, the better f(x) approximates a vertical line; fzero will simply explode! Therefore it is imperative to get an estimate as closely to the solution as possible before even entering fzero.

So, here's a way to get good initial values.

Consider the function

f(x) = x · tan(x) - 1

Knowing that tan(x) has Taylor expansion:

tan(x) ≈ x + (1/3)·x³ + (2/15)·x⁵ + (7/315)·x⁷ + ...

we can use that to approximate the function f(x). Truncating after the second term, we can write:

f(x) ≈ x · (x + (1/3)·x³) - 1

Now, key to realize is that tan(x) repeats with period π. Therefore, it is most useful to consider the family of functions:

fₙ(x) ≈ x · ( (x - n·π) + (1/3)·(x - n·π)³) - 1

Evaluating this for a couple of multiples and collecting terms gives the following generalization:

f₀(x) = x⁴/3 - 0π·x³ + ( 0π² + 1)x² - (0π +   (0π³)/3)·x  - 1
f₁(x) = x⁴/3 - 1π·x³ + ( 1π² + 1)x² - (1π +   (1π³)/3)·x  - 1
f₂(x) = x⁴/3 - 2π·x³ + ( 4π² + 1)x² - (2π +   (8π³)/3)·x  - 1
f₃(x) = x⁴/3 - 3π·x³ + ( 9π² + 1)x² - (3π +  (27π³)/3)·x  - 1
f₄(x) = x⁴/3 - 4π·x³ + (16π² + 1)x² - (4π +  (64π³)/3)·x  - 1
                              ⋮
fₙ(x) = x⁴/3 - nπ·x³ + (n²π² + 1)x² - (nπ +  (n³π³)/3)·x  - 1

Implementing all this in a simple MATLAB test:

% Replace this with the whole number of pi's you want to 
% use as offset 
n = 5;

% The coefficients of the approximating polynomial for this offset
C = @(npi) [1/3
            -npi
            npi^2 + 1
            -npi - npi^3/3
            -1];

% Find the real, positive polynomial roots
R = roots(C(n*pi));
R = R(imag(R)==0);
R = R(R > 0);

% And use these as initial values for fzero()
x_npi = fzero(@(x) x.*tan(x) - 1, R)

In a loop, this can produce the following table:

% Estimate (polynomial)    Solution (fzero)
 0.889543617524132          0.860333589019380    0·π
 3.425836967935954          3.425618459481728    1·π
 6.437309348195653          6.437298179171947    2·π
 9.529336042900365          9.529334405361963    3·π
12.645287627956868         12.645287223856643
15.771285009691695         15.771284874815882    
18.902410011613000         18.902409956860023
22.036496753426441         22.036496727938566    ⋮
25.172446339768143         25.172446326646664    
28.309642861751708         28.309642854452012
31.447714641852869         31.447714637546234
34.586424217960058         34.586424215288922   11·π 

As you can see, the approximant is basically equal to the solution. Corresponding plot:

enter image description here

Rody Oldenhuis
  • 37,726
  • 7
  • 50
  • 96
  • Why not just simply multiplying with the offending term `cos(x)` to find the pole-free equation `x*sin(x)-cos(x)==0`? – Lutz Lehmann Nov 22 '16 at 10:18
  • @LutzL hmm....and then what? It's still hard to find good initial estimates for that one. That is an angle-dependent phasor, meaning, it is identical to `√(x²+1) · sin(x + atan2(-1,x))`. As you can see, the period is not a "clean" 2π, but depends on `x`. You can add `n·π` to the first solution you find to get subsequent estimates, and for this case I think that is indeed good enough. But, experience shows that for *other* cases where the period is not *exactly* what you assume in the initial estimates, you will eventually converge twice to the same solution, and miss the next one... – Rody Oldenhuis Nov 22 '16 at 10:40
  • @LutzL well, you are free to add an answer that makes mine look laughable, I genuinely like it when that happens :) – Rody Oldenhuis Nov 22 '16 at 10:41
  • Did just that, put my view into an answer. -- Are you thinking of modified problems `tan(a*x)=1/x` or still other additional terms? – Lutz Lehmann Nov 22 '16 at 10:55
2

To find a numerical solution to a function within some range, you can use fzero like this:

fun = @(x)x*tan(x)-1; % Multiplied by x so fzero has no issue evaluating it at x=0.
range = [0 pi/2];
sol = fzero(fun,range);

The above would return just one solution (0.8603). If you want additional solutions, you will have to call fzero more times. This can be done, for example, in a loop:

fun = @(x)tan(x)-1/x;

RANGE_START = 0;
RANGE_END = 3*pi;
RANGE_STEP = pi/2;

intervals = repelem(RANGE_START:RANGE_STEP:RANGE_END,2);
intervals = reshape(intervals(2:end-1),2,[]).';

sol = NaN(size(intervals,1),1);

for ind1 = 1:numel(sol)
  sol(ind1) = fzero(fun, mean(intervals(ind1,:)));
end

sol = sol(~isnan(sol)); % In case you specified more intervals than solutions.

Which gives:

[0.86033358901938;
 1.57079632679490; % Wrong
 3.42561845948173;
 4.71238898038469; % Wrong
 6.43729817917195; 
 7.85398163397449] % Wrong

Note that:

  1. The function is symmetric, and so are its roots. This means you can solve on just the positive interval (for example) and get the negative roots "for free".
  2. Every other entry in sol is wrong because this is where we have asymptotic discontinuities (tan transitions from +Inf to -Inf), which is mistakenly recognized by MATLAB as a solution. So you can just ignore them (i.e. sol = sol(1:2:end);.
Dev-iL
  • 23,742
  • 7
  • 57
  • 99
2

Multiply the equation by x and cos(x) to avoid any denominators that can have the value 0,

f(x)=x*sin(x)-cos(x)==0

Consider the normalized function

h(x)=(x*sin(x)-cos(x)) / (abs(x)+1)

For large x this will be increasingly close to sin(x) (or -sin(x) for large negative x). Indeed, plotting this this is already visually true, up to an amplitude factor, for x>pi.

For the first root in [0,pi/2] use the Taylor approximation at x=0 of second degree x^2-(1-0.5x^2)==0 to get x[0]=sqrt(2.0/3) as root approximation, for the higher ones take the sine roots x[n]=n*pi, n=1,2,3,... as initial approximations in the Newton iteration xnext = x - f(x)/f'(x) to get

 n        initial              1. Newton         limit of Newton

 0    0.816496580927726    0.863034004302817    0.860333589019380
 1    3.141592653589793    3.336084918413964    3.425618459480901
 2    6.283185307179586    6.403911810682199    6.437298179171945
 3    9.424777960769379    9.512307014150883    9.529334405361963
 4   12.566370614359172   12.635021895208379   12.645287223856643
 5   15.707963267948966   15.764435036320542   15.771284874815882
 6   18.849555921538759   18.897518573777646   18.902409956860023
 7   21.991148575128552   22.032830614521892   22.036496727938566
 8   25.132741228718345   25.169597069842926   25.172446326646664
 9   28.274333882308138   28.307365162331923   28.309642854452012
10   31.415926535897931   31.445852385744583   31.447714637546234
11   34.557519189487721   34.584873343220551   34.586424215288922
Lutz Lehmann
  • 25,219
  • 2
  • 22
  • 51