Bessel functions

Arjen Markus (15 june 2004) While looking for some background information on special mathematical functions I found a very convenient formula to approximate zeroth and first order Bessel functions (for small enough arguments). It is based on Gaussian quadrature, a well-known approximation of definite integrals. So, here are the humble beginnings of a new mathematical module ...


 # bessel.tcl --
 #    Evaluate the most common Bessel functions via quadrature formulas
 #

 # namespace special
 #    Create a convenient namespace for the "special" mathematical functions
 #
 namespace eval ::math::special {
    #
    # Define a number of common mathematical constants
    #
    variable pi 3.1415926
 }

 # J0 --
 #    Zeroth-order Bessel function
 #
 # Arguments:
 #    x         Value of the x-coordinate
 # Result:
 #    Value of J0(x)
 #
 proc ::math::special::J0 {x} {
    variable pi
    #
    # Determine the number of components (very crude heuristic)
    # (We use a quadrature formula here and use the symmetry of
    # the cos function to reduce the number of actually computed
    # components by a gfactor 2.
    #

    set ncomps [expr {2*int($x/2.0+0.5)}]
    if { $ncomps < 6 } {
       set ncomps 6
    }

    set result 0.0
    for { set i 1 } { $i < $ncomps } { incr i 2 } {
       set result [expr {$result + cos( $x * cos((2*$i-1)*$pi/(2.0*$ncomps)) ) }]
    }

    expr {2.0*$result/$ncomps}
 }

 # J1 --
 #    First-order Bessel function
 #
 # Arguments:
 #    x         Value of the x-coordinate
 # Result:
 #    Value of J1(x)
 #
 proc ::math::special::J1 {x} {
    variable pi
    #
    # Determine the number of components (very crude heuristic)
    # (We use a quadrature formula here and use the symmetry of
    # the cos function to reduce the number of actually computed
    # components by a gfactor 2.
    #

    set ncomps [expr {2*int($x/2.0+0.5)}]
    if { $ncomps < 6 } {
       set ncomps 6
    }

    set result 0.0
    for { set i 1 } { $i < $ncomps } { incr i 2 } {
       set factor [expr {cos((2*$i-1)*$pi/(2.0*$ncomps))}]
       set result [expr {$result + $factor * sin( $x * $factor) }]
    }

    expr {2.0*$result/$ncomps}
 }

 # J1/2 --
 #    Half-order Bessel function
 #
 # Arguments:
 #    x         Value of the x-coordinate
 # Result:
 #    Value of J1/2(x)
 #
 proc ::math::special::J1/2 {x} {
    variable pi
    #
    # This Bessel function can be expressed in terms of elementary
    # functions. Therefore use the explicit formula
    #
    if { $x != 0.0 } {
       expr {sqrt(2.0/$pi/$x)*sin($x)}
    } else {
       return 0
    }
 }

 # some tests --
 #
 foreach x {0.0 2.0 4.4 6.0} {
    puts "J0($x) = [::math::special::J0 $x] - J1($x) = [::math::special::J1 $x] \
 - J1/2($x) = [::math::special::J1/2 $x]"
 }