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
module Float64

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)

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