DiffSharp


l'Hôpital's Rule

l'Hôpital's rule is a method for evaluating limits involving indeterminate forms. The rule states that, under some conditions, the indeterminate limits

\[ \begin{eqnarray*} \lim_{x \to c} \frac{f(x)}{g(x)} &=& \frac{0}{0} \; ,\\ \lim_{x \to c} \frac{f(x)}{g(x)} &=& \frac{\pm\infty}{\pm\infty} \end{eqnarray*}\]

can be found by differentiating the numerator and the denominator and taking the limit, that is

\[ \lim_{x \to c} \frac{f(x)}{g(x)} = \lim_{x \to c} \frac{f'(x)}{g'(x)} \; .\]

Let us try to find

\[ \lim_{x \to 0} \frac{2 \sin x - \sin 2x}{x - \sin x}\]

which involves the indeterminate form \(0 / 0\).

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
// Define f(x)
let f x = 2. * sin x - sin (2. * x)

// Define g(x)
let g x = x - sin x

// Try to evaluate the limit at x = 0
let lim = f 0. / g 0.

As expected, we get a nan as a result, meaning the result of this operations is undefined.

val lim : float = nan

Using DiffSharp, we can generate a sequence of repeated applications of l'Hôpital's rule.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
open DiffSharp.AD.Float64

// Differentiate f(x) and g(x) n times and evaluate the division
let lhopital f g n x = diffn n f x / diffn n g x

// Generate an infinite sequence of lhopital applications,
// starting from the undifferentiated limit (n = 0)
let lhseq f g x = Seq.initInfinite (fun n -> lhopital f g n x)

// Use lhseq with f(x) and g(x), at x = 0
let l = lhseq (fun x -> 2. * sin x - sin (2. * x)) (fun x -> x - sin x) (D 0.)

The first four elements (\(n = 0,\dots,4\)) of this infinite sequence are

val l : seq [nan; nan; nan; D 6.0; ...]

For \(n = 0\), we have the original indeterminate value of the limit (since the 0-th derivative of a function is itself).

For \(n = 3\), we have the value of this limit as

\[ \lim_{x \to 0} \frac{2 \sin x - \sin 2x}{x - \sin x} = 6 \; ,\]

after 3 applications of l'Hôpital's rule.

We can check this by manually differentiating:

\[ \begin{eqnarray*} \lim_{x \to 0} \frac{2 \sin x - \sin 2x}{x - \sin x} &=& \lim_{x \to 0} \frac{2\cos x - 2\cos 2x}{1 - \cos x}\\ &=& \lim_{x \to 0} \frac{-2 \sin x + 4 \sin 2x}{\sin x}\\ &=& \lim_{x \to 0} \frac{-2 \cos x + 8 \cos 2x}{\cos x}\\ &=& \frac{-2 + 8}{1}\\ &=& 6 \; . \end{eqnarray*}\]

We can go further and automate this process by searching for the first element of the sequence that is not indeterminate.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
// Check if x is not indeterminate
let isdeterminate x =
    not (System.Double.IsInfinity(x)
    || System.Double.IsNegativeInfinity(x)
    || System.Double.IsPositiveInfinity(x)
    || System.Double.IsNaN(x))

// Find the limit of f(x) / g(x) at a given point
let findlim f g x = Seq.find (float >> isdeterminate) (lhseq f g x)

// Find the limit of f(x) / g(x) at x = 0
let lim2 = findlim (fun x -> 2. * sin x - sin (2. * x)) (fun x -> x - sin x) (D 0.)
val lim2 : D = D -6.0

Let us use our function to evaluate some other limits.

The limit

\[ \lim_{x \to 0} \frac{\sin \pi x}{\pi x}\]

has indeterminate form \(0 / 0\) and can be evaluated by

\[ \lim_{x \to 0} \frac{\sin \pi x}{\pi x} = \lim_{y \to 0} \frac{\sin y}{y} = \lim_{y \to 0} \frac{\cos y}{1} = 1 \; .\]

1: 
let lim3 = findlim (fun x -> sin (System.Math.PI * x)) (fun x -> System.Math.PI * x) (D 0.)
val lim3 : D = D 1.0

The limit

\[ \lim_{x \to 0} \frac{e^x - 1 - x}{x^2}\]

has indeterminate form \(0 / 0\) and can be evaluated by

\[ \lim_{x \to 0} \frac{e^x - 1 - x}{x^2} = \lim_{x \to 0} \frac{e^x - 1}{2x} = \lim_{x \to 0} \frac{e^x}{2} = \frac{1}{2} \; .\]

1: 
let lim4 = findlim (fun x -> exp x - 1 - x) (fun x -> x * x) (D 0.)
val lim4 : D = D 0.5

It should be noted that there are cases where repeated applications of l'Hôpital's rule do not lead to an answer without a transformation of variables.

val f : x:float -> float

Full name: Examples-lhopitalsrule.f
val x : float
val sin : value:'T -> 'T (requires member Sin)

Full name: Microsoft.FSharp.Core.Operators.sin
val g : x:float -> float

Full name: Examples-lhopitalsrule.g
val lim : float

Full name: Examples-lhopitalsrule.lim
val printf : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printf
namespace DiffSharp
namespace DiffSharp.AD
module Float64

from DiffSharp.AD
val lhopital : f:(D -> D) -> g:(D -> D) -> n:int -> x:D -> D

Full name: Examples-lhopitalsrule.lhopital
val f : (D -> D)
val g : (D -> D)
val n : int
val x : D
val diffn : n:int -> f:(D -> 'c) -> x:D -> 'c (requires member get_P and member get_T)

Full name: DiffSharp.AD.Float64.DiffOps.diffn
val lhseq : f:(D -> D) -> g:(D -> D) -> x:D -> seq<D>

Full name: Examples-lhopitalsrule.lhseq
module Seq

from Microsoft.FSharp.Collections
val initInfinite : initializer:(int -> 'T) -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.initInfinite
val l : seq<D>

Full name: Examples-lhopitalsrule.l
union case D.D: float -> D
val isdeterminate : x:float -> bool

Full name: Examples-lhopitalsrule.isdeterminate
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
namespace System
type Double =
  struct
    member CompareTo : value:obj -> int + 1 overload
    member Equals : obj:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member GetTypeCode : unit -> TypeCode
    member ToString : unit -> string + 3 overloads
    static val MinValue : float
    static val MaxValue : float
    static val Epsilon : float
    static val NegativeInfinity : float
    static val PositiveInfinity : float
    ...
  end

Full name: System.Double
System.Double.IsInfinity(d: float) : bool
System.Double.IsNegativeInfinity(d: float) : bool
System.Double.IsPositiveInfinity(d: float) : bool
System.Double.IsNaN(d: float) : bool
val findlim : f:(D -> D) -> g:(D -> D) -> x:D -> D

Full name: Examples-lhopitalsrule.findlim
val find : predicate:('T -> bool) -> source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.find
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
val lim2 : D

Full name: Examples-lhopitalsrule.lim2
val lim3 : D

Full name: Examples-lhopitalsrule.lim3
type Math =
  static val PI : float
  static val E : float
  static member Abs : value:sbyte -> sbyte + 6 overloads
  static member Acos : d:float -> float
  static member Asin : d:float -> float
  static member Atan : d:float -> float
  static member Atan2 : y:float * x:float -> float
  static member BigMul : a:int * b:int -> int64
  static member Ceiling : d:decimal -> decimal + 1 overload
  static member Cos : d:float -> float
  ...

Full name: System.Math
field System.Math.PI = 3.14159265359
val lim4 : D

Full name: Examples-lhopitalsrule.lim4
val exp : value:'T -> 'T (requires member Exp)

Full name: Microsoft.FSharp.Core.Operators.exp