9

How can I calculate or approximate the intersection(s) or lack thereof of a line and an exponential curve.

My goal is to avoid using an approach which first tessellates curves into line segments, and tests each line segment pair. That is O(n^2). I want something which can scale.

I think Lua is appropriate for this, based on evidence in the comments.

\documentclass[tikz,border=1cm]{standalone}
\begin{document}
    \begin{tikzpicture}
        \draw[->] (-2,0)  -- (2,0);
        \draw[->] (0,-2)  -- (0,e^2);
        \draw[domain=-2:2] plot (\x,e^\x);
        \draw[domain=-2:2] plot (\x,\x+1.5); % two intersections
        \draw[domain=-2:2] plot (\x,\x+1); % one intersection
        \draw[domain=-2:2] plot (\x,-\x+4.5); % one intersection
        \draw[domain=-2:2] plot (\x,\x); % zero intersections
        % My goal is to use pgfmath to calculate, or if 
        % necessary iteratively approximate, the intersections 
        % of these lines with the exponential curve.
        % If it is not easy in pgfmath, then I want a Lua-based solution.
    \end{tikzpicture}
\end{document}

output

14
  • could you explain why you do not want to use intersections? note that the code there uses fpu in places to avoid problems with pgfmath, so trying to do it with the latter may be problematic. (but I would prefer l3fp to fpu these days.) Commented yesterday
  • @cfr Intersections feels like the wrong approach because it just operates on existing paths, and not on the parametric equations which defined those paths. Commented yesterday
  • BTW, exp(\x) is more efficient than e^\x = ln{e)*\exp{\x} since it doesn't have to compute ln(e)=1. exp uses a polynomial approximaiton (Taylor's series) Commented yesterday
  • 1
    I was more thinking of your preference for doing it with pgfmath. b/c then you would need to do something to reduce the chances of exceeding tex's max dimension and also think about whether it is accurate enough. a lua solution is different: you do not have to think about the limitations of tex arithmetic in that case and starting from the maths makes more sense. I mean, I wouldn't start from that library, but I would not try to use pgfmath ;). Commented yesterday
  • 1
    @cfr That is reasonable, and yes that is something I overlooked initially. Pgfmath is clearly not the tool to do general computational math. The practical approach is to use Lua then. Commented yesterday

2 Answers 2

10

I do the calculus exercise. You wonder about the intersection, if any of $e^x$ with $u x + v$. We examine the difference $e^x- ux -v$. It is a strictly convex function.

  • if $u<0$, the function is strictly increasing and vanishes at a unique abscissa which will be the one of the your intersection point. Newton method whatever the starting point will converge to the root. Better to start on its right, I have not detailed more.
  • if $u=0$ we have horizontal lines, left to reader.
  • if $u>0$, this time the difference is still convex but with a minimum. The value is $u - u \log u - v$. If this quantity is negative you have two intersection points, if it vanishes you have a tangent, if it is positive you have no intersection points. To find the intersection points do Newton method with either large positive or large negative starting point.

Hope it helps.

Edit: the starting point is crucial so the above is ill-advised to say "large starting point". Because as long as $e^x$ is large Newton's method will simply do roughly $x\mapsto x-1$ and take a long time to reach the root if you started too far (but I assume your real life examples have some reasonable bounds ,say $-10<x<10$). If $x$ is very negative (and slope $u$ positive), then situation is better, because the studied function whose root is aimed at is quasi linear, so after one iteration we are near $-v/u$ it seems and it should go fast (untested). So it seems to be easier to find the left-intersection point. In the case with negative slope, the sole intersection point can presumably be obtained starting Newton with the $-v/u$ mentioned above. Well, may be not the place for a mathematical treatise, let's leave some work to the AIs.

Mathematical treatise

I will focus on the case u>0. In order to analyze mathematically it is convenient to make a translation. The equation to solve is e^x = ux+v. Let t= x+v/u. On finds that the equation becomes e^t = ct with c= u exp(v/u). This can be transformed if one so wishes into a Lambert-W function type of equation -texp(-t)=-1/c so z exp(z)=-1/c with z=-t I will not use that.

Geometrically, as c>0 we see clearly that there is a c_0 such that c<c_0 give no solution, c=c_0 one, and c>c_0 gives two. It turns out that c_o = e: the line with slope e touches the exponential at point (1,e). Thus we can say in advance that for c>e we will have a solution w_1 in (0,1) and a solution w_2>1. This second solution is the most delicate because it probes when c increases the exponential regime.

Let's start with w_1. It is clear geometrically that it is larger than the abscissa of intersection of our line through the origin of slope c and the tangent to the exponential at t=0 of slope 1. So w_1 > 1/(c-1). We are in the convex decreasing part of the difference e^t - ct, so put t_0 = 1/(c-1) and apply Newton iteration, this gives a strictly increasing sequence which should be efficient to find the limit w_1. The formula to iterate is next(t) = (1-t)/(c exp(-t) - 1).

More challenging is finding w_2. We would like a starting point to the right of it. I convert the equation e^t = c t into the equation t = d + log (t)with d = log(c) >1. If we plot the line of equation y = t-d we want its intersection the graph of log with abscissa w_2>1. The difference t - d - log(t) is convex and increasing for t>1 with zero slope at t=1 and negative value 1-d at t=1. We look for starting point sufficiently to the right but not too much so that Newton will not start from too far. Now if d is large, the solution should be approximately t=d + log(d). In fact we see that iterating t<- d+log(t) will converge geometrically, and stay always to the left of the seeked root w_2. So perhaps do this a couple of times, then apply Newton which will give us a point on the right of w_2 hopefully not too far and continue with Newton. So we set t_0=d, iterate a bunch of times t<- d +log(t), then switch to next(t) = ((d-1)+log(t))/(1 - 1/t).

Posting this for now, a numerical example later.

Numerical example

Please convert this into your favorite language. This handles only the equation exp(t) = ct with c>exp(1).

\documentclass{article}
\usepackage{xintexpr}

\newcommand\SolveExpEqualLin[1]{%
\begingroup\long\def\STOP##1\endgroup{}%
    \xintdeffloatvar c:= #1;%
    \xintifboolexpr{c>exp(1)}
         {}
         {Bad input $\xintfloateval{c}$ not greater than $\exp(1)$, Aborting!\STOP}%
    \xintdeffloatfunc f(t):=(1-t)/(c*exp(-t) - 1);%
    \xintdeffloatvar tn:=1/(c-1);%
    \xintdeffloatvar eps:=tn * 5e-16;%
    \xintloop
    \xintdeffloatvar new:=f(tn);%
    \xintifboolexpr{abs(new-tn)<eps}
         {\iffalse}%
         % maybe not update eps?
         {\xintdeffloatvar tn, eps :=new, new * 5e-16;\iftrue}
    \repeat
    \xintdeffloatvar w_1 := tn;%
    %
    \xintdeffloatfunc g(t):=log(c) + log(t);%
    \xintdeffloatvar tn:=log(c);%
    \xintdeffloatvar tn:=g(tn);%
    \xintdeffloatvar tn:=g(tn);%
    \xintdeffloatvar tn:=g(tn);%
    \xintdeffloatvar eps:=tn* 5e-16;%
    \xintdeffloatfunc k(t):=(g(t)-1)/(1 - 1/t);%
    \xintloop
    \xintdeffloatvar new:=k(tn);%
    \xintifboolexpr{abs(new-tn)<eps}
         {\iffalse}%
         % maybe not update eps?
         {\xintdeffloatvar tn, eps :=new, new * 5e-16;\iftrue}
    \repeat
    \xintdeffloatvar w_2 := tn;%
    %
    The solutions to the equation $\exp(t) = \xintfloateval{c}t$ are
    $t_1\approx\xintfloateval[-1]{w_1}$ and $t_2\approx\xintfloateval[-1]{w_2}$.
\endgroup
\par
}
\begin{document}
\xintFor* #1 in {\xintSeq{1}{10}}\do{\SolveExpEqualLin{#1}}
\end{document}

solving exp(t)=ct

With TikZ (general case)

The code is extended to handle all possibilities, I also declared once and for all some functions of two variables for efficiency, and was more careful in termination criterion for Newton's method. I am not nimble with TikZ and can not do easily some obvious improvements the displayed plots are in need of. Incidentally I found a bug of \xintifsgnexpr and had to renounce using it.

\documentclass[tikz,border=1cm]{standalone}
\usepackage{xintexpr}


\xintdeffloatfunc F(t,c) := (1-t)/(c*exp(-t) - 1);
\xintdeffloatfunc G(t,d) := d + log(t);
\xintdeffloatfunc K(t,d) := (G(t,d)-1)/(1 - 1/t);
\newcommand\SolveExpEqualLin[2]{%
\begingroup
    \xintdeffloatvar u:= #1;%
    \xintdeffloatvar v:= #2;%
    % There appears to be a bug in XINT with \xintifsgnexpr
    % when used with input starting with a zero. (I was
    % skeptical but it seems to be real, I reported to maintainer
    % and I am awaiting response).
    \xintifboolexpr{u>0}
       {\SolveExpEqualLinPos}%
       {\xintifboolexpr{u<0}
             {\SolveExpEqualLinNeg}
             {\SolveExpEqualLinZero}}
\endgroup
}
% negative slope. Always exactly one root.
% Attention to computation of epsilon.  If the root is exactly zero
% we are doomed if we let it evolve to be dynamically proportional
% to the computed approximation.
% So we compute eps only at first ieration. The value is then 1/(c-1)
% which is not zero.
\newcommand\SolveExpEqualLinNeg{%
    \xintdeffloatvar delta:= v/u;%
    \xintdeffloatvar c:= u * exp(delta);% c<0
    \xintdeffloatvar tn:= F(0, c);%
    % it turned out that it was too small here with 5e-16
    % because it could be that iteration fell into
    % infinite loop ...6-->...8-->...6-->..6 etc as last
    % significant figure.  So let's be more cautious.
    \xintdeffloatvar eps:=abs(tn) * 1e-15;% attention to sign...
    \xintloop
    \xintdeffloatvar new:=F(tn,c);%
    \xintifboolexpr{abs(new-tn)<eps}
         {\iffalse}%
         {\xintdeffloatvar tn := new;\iftrue}
    \repeat
    \xdef\roots{\xintfloateval{tn-delta}}%
}

% zero slope
\newcommand\SolveExpEqualLinZero{%
    \xintifboolexpr{v<=0}{\xdef\roots{}}{\xdef\roots{\xintfloateval{log(v)}}}%
}

% positive slope
\newcommand\SolveExpEqualLinPos{%
    \xintdeffloatvar delta:= v/u;%
    \xintdeffloatvar c:= u * exp(delta);%
    \xintdeffloatvar d:= log(u) + delta;%
    \xintifboolexpr{d-1>1e-15}
      {\SolveExpEqualLinPosTwo}
      {\xintifboolexpr{d-1<-1e-15}
           {\xdef\roots{}}%
           {\xdef\roots{\xintfloateval{1 - delta}}}%
      }%
}

% positive slope, two roots
\newcommand\SolveExpEqualLinPosTwo{%
    \xintdeffloatvar tn:=1/(c-1);%
    \xintdeffloatvar eps:=tn * 1e-15;%
    \xintloop
    \xintdeffloatvar new:=F(tn,c);%
    \xintifboolexpr{abs(new-tn)<eps}
         {\iffalse}%
         {\xintdeffloatvar tn:=new;\iftrue}
    \repeat
    \xintdeffloatvar w_1 := tn;%
    %
    \xintdeffloatvar tn:=d;%
    \xintdeffloatvar tn:=G(tn, d);%
    \xintdeffloatvar tn:=G(tn, d);%
    \xintdeffloatvar tn:=G(tn, d);%
    \xintdeffloatvar eps:=tn* 1e-15;% careful not too small
    \xintloop
    \xintdeffloatvar new:=K(tn, d);%
    \xintifboolexpr{abs(new-tn)<eps}
         {\iffalse}%
         {\xintdeffloatvar tn :=new;\iftrue}%
    \repeat
    \xintdeffloatvar w_2 := tn;%
    %
    %The solutions to the equation $\exp(t) = \xintfloateval{c}t$ are
    %$t_1\approx\xintfloateval[-1]{w_1}$ and $t_2\approx\xintfloateval[-1]{w_2}$.
    \xdef\roots{\xintfloateval{w_1-delta}, \xintfloateval{w_2-delta}}%
}


\begin{document}
\begin{tikzpicture}
  \def\xmin{-0.5}
  \def\xmax{3.6}

  \draw[->] (\xmin,0) -- (\xmax,0);
  \draw[->] (0,-0.2) -- (0,{exp(\xmax)});
  \draw[domain=\xmin:\xmax,samples=200] plot (\x,{exp(\x)});

  \xintFor* #1 in {\xintSeq{3}{10}}\do{%
  \draw[domain=-0.1:\xmax,samples=2,color=gray,line width=0.1] plot (\x,{#1*\x});
  \SolveExpEqualLin{#1}{0}%
  \foreach \r in \roots { \fill[red] (\r,{exp(\r)}) circle (1.2pt); }
  }

\end{tikzpicture}


\begin{tikzpicture}
  \def\xmin{-3}
  \def\xmax{1.5}
  \def\step{0.25}

  \draw[->] (\xmin,0) -- (\xmax,0);
  \draw[->] (0,-0.2) -- (0,{exp(\xmax)});
  \draw[domain=\xmin:\xmax,samples=200] plot (\x,{exp(\x)});

  \edef\tmp{\xinteval{\xmin..[\step]..\xmax}}
  \xintFor #1 in {\tmp}\do{%
    \draw[domain=\xmin:#1,samples=2,color=blue!50,line width=0.3] plot (\x,{-\x+#1});
    \SolveExpEqualLin{-1}{#1}%
    \foreach \r in \roots { \fill[blue] (\r,{exp(\r)}) circle (1.2pt); }
  }

\end{tikzpicture}

\begin{tikzpicture}
  \def\xmin{-3}
  \def\xmax{1.5}
  \def\step{0.25}

  \draw[->] (\xmin,0) -- (\xmax,0);
  \draw[->] (0,-0.2) -- (0,{exp(\xmax)});
  \draw[domain=\xmin:\xmax,samples=200] plot (\x,{exp(\x)});

  \edef\tmp{\xinteval{\xmin..[\step]..\xmax}}
  \xintFor #1 in {\tmp}\do{%
    \draw[domain=#1:\xmax,samples=2,color=red!50,line width=0.3] plot (\x,{\x-#1});
    \SolveExpEqualLin{+1}{-#1}%
    \foreach \r in \roots { \fill[red] (\r,{exp(\r)}) circle (1.2pt); }
  }
\end{tikzpicture}
\end{document}

intercepts with exponential

intercepts, negative slope

intercepts, positive slope

2
  • Thank you, this is very interesting Commented yesterday
  • well I was afraid to be off-topic so thanks for your comment ;-) Commented yesterday
9

To compute the intersection(s) of the graphs of the exponential function 'y=e^x' and the line 'y=mx+b' (as already noted in the first answer to this question), it is convenient to consider the function 'f(x)=e^x-mx-b'. Since 'f' is strictly convex, it has at most two roots. Next, depending on the sign of 'm', we determine how many roots are possible and, if there are two, we bracket them. Then the roots are computed using the bisection method. This is exactly the approach implemented in the code below. I added two more examples to illustrate an important point: the roots exist, but they lie outside our interval.

\documentclass[tikz,border=1cm]{standalone}
\usepackage{luacode}

\begin{luacode*}
-- Compute intersections of y=exp(x) with y=m*x+b on [xmin,xmax]
-- Export x-roots into TeX macro \roots (empty if none).
function lineExpIntersections(m,b,xmin,xmax)
  local function f(x) return math.exp(x) - (m*x + b) end

  local function bisect(L,R, tol, maxit)
    tol   = tol   or 1e-6
    maxit = maxit or 60
    local fL, fR = f(L), f(R)
    if fL*fR > 0 then return nil end
    for _=1,maxit do
      local M  = 0.5*(L+R)
      local fM = f(M)
      if (R-L) < tol then return M end
      if fL*fM < 0 then
        R, fR = M, fM
      else
        L, fL = M, fM
      end
    end
    return 0.5*(L+R)
  end

  local roots = {}

  if m < 0 then
    -- strictly increasing => at most one root; find it if bracketed
    local r = bisect(xmin, xmax)
    if r then roots[#roots+1] = r end

  elseif m == 0 then
    -- exp(x)=b
    if b > 0 then
      local r = math.log(b)
      if r >= xmin and r <= xmax then roots[#roots+1] = r end
    end

  else
    -- m>0: 0/1/2 roots; minimum at x0=log(m)
    local x0   = math.log(m)
    local fmin = m - (m*math.log(m) + b) -- f(x0)

    if fmin == 0 then
      if x0 >= xmin and x0 <= xmax then roots[#roots+1] = x0 end
    elseif fmin < 0 then
      -- two roots globally; try to bracket each inside [xmin,xmax]
      local L1, R1 = xmin, math.min(x0, xmax)
      local L2, R2 = math.max(x0, xmin), xmax
      local r1 = bisect(L1, R1)
      local r2 = bisect(L2, R2)
      if r1 then roots[#roots+1] = r1 end
      if r2 then roots[#roots+1] = r2 end
    end
  end

  local out = {}
  for i=1,#roots do out[i] = string.format("%.12f", roots[i]) end
  tex.sprint("\\def\\roots{" .. table.concat(out, ",") .. "}")
end
\end{luacode*}

% TeX wrapper: defines \roots
\newcommand{\LineExpIntersections}[4]{%
  \directlua{lineExpIntersections(#1,#2,#3,#4)}%
}

\begin{document}
\begin{tikzpicture}
  \draw[->] (-2,0) -- (2,0);
  \draw[->] (0,-2) -- (0,{exp(2)});
  \draw[domain=-2:2,samples=200] plot (\x,{exp(\x)});

  \def\xmin{-2}
  \def\xmax{2}

  % 1) y = x + 1.5 (two intersections)
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{1*\x+1.5});
  \LineExpIntersections{1}{1.5}{\xmin}{\xmax}
  \foreach \r in \roots { \fill[red] (\r,{exp(\r)}) circle (1.2pt); }

  % 2) y = x + 1 (one intersection)
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{1*\x+1});
  \LineExpIntersections{1}{1}{\xmin}{\xmax}
  \foreach \r in \roots { \fill[green] (\r,{exp(\r)}) circle (1.2pt); }

  % 3) y = -x + 4.5 (one intersection)
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{-1*\x+4.5});
  \LineExpIntersections{-1}{4.5}{\xmin}{\xmax}
  \foreach \r in \roots { \fill[blue] (\r,{exp(\r)}) circle (1.2pt); }

  % 4) y = x (zero intersections)
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{1*\x});
  \LineExpIntersections{1}{0}{\xmin}{\xmax}
  \foreach \r in \roots { \fill (\r,{exp(\r)}) circle (1.2pt); }
  
  % 5) y = x + 4 (zero intersections)
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{1*\x+4});
  \LineExpIntersections{1}{4}{\xmin}{\xmax}
  \foreach \r in \roots { \fill[orange] (\r,{exp(\r)}) circle (1.2pt); }
  
  % 6) y = x + 5 (no intersections on [xmin,xmax]” или “roots outside the interval)  
  \def\txmax{1.5}
  \draw[domain=\xmin:\txmax,samples=2] plot (\x,{1*\x+5});
  \LineExpIntersections{1}{5}{\xmin}{\txmax}
  \foreach \r in \roots { \fill[orange] (\r,{exp(\r)}) circle (1.2pt); }

\end{tikzpicture}
\end{document}

P.S. If 'm' or 'fmin' is obtained as the result of computations, an “exactly zero” comparison may fail. In our examples everything is fine, but in the general case one should use something like 'if math.abs(m) < eps then ...', and so on.

enter image description here


Edit.
I slightly modified the stopping criterion for the bisection method. If the interval length 'R-L' becomes smaller than 'tol=10^{-6}', we stop and return the midpoint of the interval '[L,R]'. If, for some reason, we do not reach the desired accuracy in x within 'maxit=60' steps (a generous margin), the function returns the midpoint of the last interval.

Edit 2.
I added to my code the ability to choose between two methods for approximating the roots: the bisection method and Newton’s method. The choice can be made once for all examples, as in the code, or you can choose one of the two methods separately for each example. Alternatively, you can run each example twice, once with each method, and compare the results.

\documentclass[tikz,border=1cm]{standalone}
\usepackage{luacode}

\begin{luacode*}
-- Compute intersections of y=exp(x) with y=m*x+b on [xmin,xmax]
-- method = "bisection" or "newton"
-- Export x-roots into TeX macro \roots (empty if none).
function lineExpIntersections(m,b,xmin,xmax, method)
  method = method or "bisection"

  local function f(x)  return math.exp(x) - (m*x + b) end
  local function df(x) return math.exp(x) - m end

  local function bisect(L,R, tol, maxit)
    tol   = tol   or 1e-6
    maxit = maxit or 60
    local fL, fR = f(L), f(R)
    if fL*fR > 0 then return nil end
    for _=1,maxit do
      local M  = 0.5*(L+R)
      local fM = f(M)
      if (R-L) < tol then return M end
      if fL*fM < 0 then
        R, fR = M, fM
      else
        L, fL = M, fM
      end
    end
    return 0.5*(L+R)
  end
   
  -- Plain Newton on [L,R], starting from an endpoint (no fallback).
  local function newton(L,R, tol, maxit)
    tol   = tol   or 1e-6
    maxit = maxit or 30
    local fL, fR = f(L), f(R)
    if fL*fR > 0 then return nil end
  
    -- start from the endpoint with smaller |f|
    local x = (math.abs(fL) <= math.abs(fR)) and L or R
  
    -- if derivative is too small at chosen endpoint, try the other one
    if math.abs(df(x)) < 1e-15 then
      x = (x == L) and R or L
      if math.abs(df(x)) < 1e-15 then return nil end
    end
  
    for _=1,maxit do
      local fx = f(x)
      if math.abs(fx) < tol then return x end
      local dfx = df(x)
      if math.abs(dfx) < 1e-15 then return nil end
      local xnew = x - fx/dfx
      if xnew <= L or xnew >= R then return nil end
      x = xnew
    end
    return nil
  end

  local function solve_on_interval(L,R)
    if method == "newton" then
      return newton(L,R, 1e-6, 30)
    else
      return bisect(L,R, 1e-6, 60)
    end
  end

  local roots = {}

  if m < 0 then
    local r = solve_on_interval(xmin, xmax)
    if r then roots[#roots+1] = r end

  elseif m == 0 then
    if b > 0 then
      local r = math.log(b)
      if r >= xmin and r <= xmax then roots[#roots+1] = r end
    end

  else
    local x0   = math.log(m)
    local fmin = m - (m*math.log(m) + b) -- f(x0)

    if fmin == 0 then
      if x0 >= xmin and x0 <= xmax then roots[#roots+1] = x0 end
    elseif fmin < 0 then
      local L1, R1 = xmin, math.min(x0, xmax)
      local L2, R2 = math.max(x0, xmin), xmax
      local r1 = solve_on_interval(L1, R1)
      local r2 = solve_on_interval(L2, R2)
      if r1 then roots[#roots+1] = r1 end
      if r2 then roots[#roots+1] = r2 end
    end
  end

  local out = {}
  for i=1,#roots do out[i] = string.format("%.12f", roots[i]) end
  tex.sprint("\\def\\roots{" .. table.concat(out, ",") .. "}")
end
\end{luacode*}

% TeX wrapper: #5 is method: bisection/newton
\newcommand{\LineExpIntersections}[5]{%
  \directlua{lineExpIntersections(#1,#2,#3,#4,"#5")}%
}

\begin{document}
\begin{tikzpicture}
  \draw[->] (-2,0) -- (2,0);
  \draw[->] (0,-2) -- (0,{exp(2)});
  \draw[domain=-2:2,samples=200] plot (\x,{exp(\x)});

  \def\xmin{-2}
  \def\xmax{2}

  % Choose one:
  %\def\method{bisection}
  \def\method{newton}

  % 1) y = x + 1.5
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{1*\x+1.5});
  \LineExpIntersections{1}{1.5}{\xmin}{\xmax}{\method}
  \foreach \r in \roots { \fill[red] (\r,{exp(\r)}) circle (1.2pt); }

  % 2) y = x + 1
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{1*\x+1});
  \LineExpIntersections{1}{1}{\xmin}{\xmax}{\method}
  \foreach \r in \roots { \fill[green] (\r,{exp(\r)}) circle (1.2pt); }

  % 3) y = -x + 4.5
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{-1*\x+4.5});
  \LineExpIntersections{-1}{4.5}{\xmin}{\xmax}{\method}
  \foreach \r in \roots { \fill[blue] (\r,{exp(\r)}) circle (1.2pt); }

  % 4) y = x
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{1*\x});
  \LineExpIntersections{1}{0}{\xmin}{\xmax}{\method}
  \foreach \r in \roots { \fill (\r,{exp(\r)}) circle (1.2pt); }

  % 5) y = x + 4 (root outside [-2,2])
  \draw[domain=\xmin:\xmax,samples=2] plot (\x,{1*\x+4});
  \LineExpIntersections{1}{4}{\xmin}{\xmax}{\method}
  \foreach \r in \roots { \fill[orange] (\r,{exp(\r)}) circle (1.2pt); }

  % 6) y = x + 5 (no intersections on [-2,1.5])
  \def\txmax{1.5}
  \draw[domain=\xmin:\txmax,samples=2] plot (\x,{1*\x+5});
  \LineExpIntersections{1}{5}{\xmin}{\txmax}{\method}
  \foreach \r in \roots { \fill[yellow] (\r,{exp(\r)}) circle (1.2pt); }

\end{tikzpicture}
\end{document}
3
  • I think indeed that for plotting, obsession with Newton iteration as in my answer is a bit irrelevant as only 5 decimal places is already precise enough. But out of curioosity could you give Lua conversion of the code in my answer? (Sadly I did only explicitly the case of e^x = mx in your notations). I am unable to do it myself. Commented 17 hours ago
  • 2
    @user691586 I updated my answer to include Newton’s method. Choosing a suitable initial guess required a bit more care, but everything works. Commented 15 hours ago
  • +1. I've taken the liberty of editing your code to insert meta instructions to highlight the Lua code chunks. Feel free to revert. Commented 7 hours ago

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.