Arjen Markus (14 july 2008) Recently, on the Tclers' chat, someone had a problem with the [expr] command as in their installation tclsh apparently did not have any math functions. While it was easy enough to provide an alternative for sqrt() (see Square root for instance), a function like exp() presents more difficulties. Or does it?
Not really: Abramowitz and Stegun come to the rescue, along with a few properties of the exponential function. The result is remarkably accurate. I leave the log, sin, cos, tan, acos, asin and atan functions as an exercise.
# approx_exp.tcl --
# An approximation of the exponential function
# (Based on Abramowicz and Stegun)
#
# exp --
# Compute an approximation of exp(x)
#
# Arguments:
# x Value for which to evaluate the exponential function
#
# Returns:
# Approximation of exp(x)
#
proc exp {x} {
set ln2 0.693147805599543
set E 2.718281828459045
set sqrtE 1.6487212707001282
#
# As the valid range for the basic approximation is 0 - ln(2),
# reduce the argument
#
set factor 1.0
if { $x > 0.0 } {
set reciproke 1
} else {
set reciproke 0
set x [expr {-$x}]
}
while { $x > 1.0 } {
set x [expr {$x - 1.0}]
set factor [expr {$factor * $E}]
}
if { $x > $ln2 } {
set x [expr {$x - 0.5}]
set factor [expr {$factor * $sqrtE}]
}
#puts "Reduced x: $x $factor"
set exp [expr {(1.0 + $x * (-0.9998684 + $x * (0.4982926 +
+ $x * (-0.1595332 + $x * 0.0293641))))}]
if { $reciproke } {
set exp [expr {$factor / $exp}]
} else {
set exp [expr {$factor * $exp}]
}
return $exp
}
# main --
# Put it to the test
#
puts [format "%12s %12s%12s%12s%12s" X "exp x" "exp(x)" "abs. diff" "rel. diff"]
foreach x {0.1 0.2 0.5 1.3 2.4 4.05 -0.1 -0.2 -0.5 1.3 2.4 4.05} {
set exp1 [exp $x]
set exp2 [expr {exp($x)}]
puts [format "%12.4f:%12.4f%12.4f%12.4e%12.4e" $x $exp1 $exp2 [expr {$exp1-$exp2}] \
[expr {$exp1/$exp2-1.0}]]
}