Skip to main content
added meta code to highlight Lua code chunks
Source Link
Mico
  • 556.7k
  • 57
  • 760
  • 1.3k
\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}
-- 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}
 
\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}
-- 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}
\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}
\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}
\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}
 
\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}
added 5573 characters in body
Source Link
kabenyuk
  • 16.6k
  • 2
  • 12
  • 26

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}

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}
added 374 characters in body
Source Link
kabenyuk
  • 16.6k
  • 2
  • 12
  • 26
\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)
    localtol fL, fR = f(L),tol f(R)
  or 1e-6
 if fL == 0maxit then= returnmaxit Lor end60
    if fRlocal ==fL, 0fR then= returnf(L), f(R end)
    if fL*fR > 0 then return nil end
    for _=1,80maxit do
      local M  = 0.5*(L+R)
      local fM = f(M)
      if fM(R-L) ==< 0tol 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}

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.

\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)
    local fL, fR = f(L), f(R)
    if fL == 0 then return L end
    if fR == 0 then return R end
    if fL*fR > 0 then return nil end
    for _=1,80 do
      local M  = 0.5*(L+R)
      local fM = f(M)
      if fM == 0 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}

enter image description here

\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}

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.

Source Link
kabenyuk
  • 16.6k
  • 2
  • 12
  • 26
Loading