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