The script below contains a few commands that illustrate the idea compactly:
- You can define a function of x via [func $expression]
- You can define the derivative of that function via [deriv funcname]
- You can get the value of a function for a specific value
# functions.tcl --
#
# Package for analysing real functions
# (sample Workbench module)
#
# Notes:
# This package provides basic analysis functionality for real
# functions of one variable.
#
# Version information:
# version 0.1: initial implementation, july 2002
package provide Functions 0.1
namespace eval ::Workbench {
variable nextID 0
# uniqueID --
# Create a unique ID (private)
#
# Arguments:
# expression Expression using "x" as independent variable
# evaluating to the function value
#
# Result:
# Name of a new command implementing the function
#
# Side effect:
# Create a new command that takes one argument, x, and
# returns the function value
#
proc uniqueID {typename} {
variable nextID
incr nextID
return "${typename}##$nextID"
}
} ;# End of namespace
namespace eval ::Functions {
namespace export func deriv
# func --
# Create a new function
#
# Arguments:
# expression Expression using "x" as independent variable
# evaluating to the function value
#
# Result:
# Name of a new command implementing the function
#
# Side effect:
# Create a new command that takes one argument, x, and
# returns the function value
#
proc func {expression} {
set name [::Workbench::uniqueID "X-FUNCTION"]
interp alias {} $name {} [namespace current]::xfunc_impl $expression
return $name
}
# xfunc_impl --
# Implementation of an "x function"
#
# Arguments:
# expression Expression using "x" (hidden via [interp alias])
# x Independent variable
#
# Result:
# Function value
#
proc xfunc_impl {expression x} {
expr $expression
}
# deriv --
# Create a new function that evaluates to the derivative of the given
# function
#
# Arguments:
# funcname Name (!) of the function
# step Step for the numerical derivation
#
# Result:
# Name of a new command implementing the function's derivative
#
# Side effect:
# Create a new command that takes one argument, x, and
# returns the original function's derivative
#
proc deriv {funcname {step 0.01} } {
upvar $funcname fname
set name [::Workbench::uniqueID "X-DERIVATIVE"]
set expression [lindex [interp alias {} $fname] 1]
interp alias {} $name {} [namespace current]::xderiv_impl $fname [expr {$step*0.5}]
return $name
}
# xderiv_impl --
# Implementation of the derivative of an "x function"
#
# Arguments:
# fname Name (!) of the function
# step Step size for numerical derivation
# xv Independent variable
# Result:
# Value of derivative
#
# Note:
# By using the
#
proc xderiv_impl {fname step xv} {
set x [expr {$xv-$step}]
set fx1 [$fname $x]
set x [expr {$xv+$step}]
set fx2 [$fname $x]
expr {($fx2-$fx1)/(2.0*$step)}
}
} ;# End of namespace
#
# Import the functions procedures
#
namespace import ::Functions::*
#
# Simple demo
#
if { [file tail [info script]] == [file tail $::argv0] } {
puts "Simply a parabola: y = x^2"
set f [func {$x*$x}]
set df [deriv f]
set x 0.0
while { $x < 10.1 } {
puts "[$f $x] [$df $x]"
set x [expr {$x+1.0}]
}
puts "A more complex function"
set f [func {sin($x)*$x}]
set df [deriv f]
set x 0.0
while { $x < 10.1 } {
puts "[$f $x] [$df $x]"
set x [expr {$x+0.1}]
}
}
