Page contents
See Also edit
Documentation edit
- official reference

- TIP 232

- for the creation of the ::tcl::mathfunc namespace
- TIP 174

- Math Operators as Commands. Presents various usage ideas.
Description edit
::tcl::mathfunc was made available in Tcl 8.5. Operators are in tcl::mathop. Note that changing or adding to these commands changes the set of functions available in expr. Also note that when your code is executing in a namespace other than the global one, you can define your own functions in the "yourNS::tcl::mathfunc" namespace.List of built-in functions edit
| Operation | Name | Args | Operation | Name | Args | |
|---|---|---|---|---|---|---|
| Absolute value | abs | arg | Hypotenuse length | hypot | x y | |
| Arc cosine | acos | arg | Coerce to word-sized integer | int | arg | |
| Arc sine | asin | arg | Natural logarithm | log | arg | |
| Arc tangent | atan | arg | Base-10 logarithm | log10 | arg | |
| Four-quadrant arc tangent | atan2 | y x | Greatest value | max | args | |
| Coerce to boolean | bool | arg | Least value | min | args | |
| Round up to whole number | ceil | arg | Power | pow | x y | |
| Cosine | cos | arg | Random float in range [0,1) | rand | ||
| Hyberbolic cosine | cosh | arg | Round to whole number | round | arg | |
| Coerce to float | double | arg | Sine | sin | arg | |
| Coerce to integer | entier | arg | Hyperbolic sine | sinh | arg | |
| Exponential | exp | arg | Square root | sqrt | arg | |
| Round down to whole number | floor | arg | Seed random number generator | srand | arg | |
| Remainder | fmod | x y | Tangent | tan | arg | |
| Coerce to 64-bit integer | wide | arg | Hyperbolic tangent | tanh | arg | |
| Integer part of square root | isqrt | arg |
User-Defined Functions edit
TIP 232
provides for script-level creation of new functions, analagous to the C level Tcl_CreateMathFunc(3)
.[expr] can be extended with new functions by adding commands to ::tcl::mathfunc, or to a tcl::matchfunc child namespace of any other namespace. In the latter case, the additional [expr] functions are only available to commands in the parent namespace.Functions can also be overriden or deleted from [expr] by overriding or modifying the corresponding procedure in an appropriate tcl::mathfunc namespace. This functionality was previously not available, even at the C level.[expr] function arguments are now just as flexible as those of Tcl procs and commands. Variadic numbers of arguments are also possible, and illustrated by by the min() and max() functions.[expr] functions can now also be called as procedures without using [expr] at all. This is one way to to bypassing the problems discussed at brace your expr-essions.Defining New Functions at the C Level edit
AM: On the c.l.t the other day [is this as of May 2003?], Martin Russell asked about how to define new math functions. If you want to do it without the help of DKF's extension [??] and CrtLib [ critcl's critlib?], then here is a recipe provided by Pat Thoyts:Something along these lines.static Tcl_MathProc ArbLogProc;
static int
ArbLogProc(clientData, interp, args, resultPtr)
ClientData clientData;
Tcl_Interp *interp; /* current interpreter */
Tcl_Value *args; /* input arguments */
Tcl_Value *resultPtr; /* where to store the result */
{
double b, n, d;
b = args[0].doubleValue;
n = args[1].doubleValue;
/* do your maths and assign d to the result */
d = 1.0;
resultPtr->type = TCL_DOUBLE;
resultPtr->doubleValue = d;
return TCL_OK;
}in your package initialisation...Tcl_ValueType arblogArgs[2] = { TCL_DOUBLE, TCL_DOUBLE };
Tcl_CreateMathFunc(interp, "arblog", 2, arblogArgs, ArbLogProc,
(ClientData)NULL);Namespace-local tcllib::mathfun edit
As of Tcl 8.5, if any namespace has a child namespace called tcl::mathfunc (notice that it's a relative name), [expr] will look first in that namespace for available functions. I.e., either ::tcl::matfunc::f or [namespace current]::tcl::mathfunc::f can resolve f($x).In the following example, any proc in mynamespace can use logbase():namespace eval mynamespace {
proc tcl::mathfunc::logbase {x b} {
expr {log($x) / log($b)}
}
proc dostuff {} {
...
expr {logbase($some_var,$some_other_var)}
}
}func: a Convenient Procedure edit
DKF: A little helper for when writing custom functions:proc func {name arguments body} {
proc tcl::mathfunc::$name $arguments [list expr $body]
}This lets us write factorials as just this:func fac x { $x<2 ? 1 : $x*fac($x-1) }It can be useful to import functions from elsewhere into the local tcl::mathfunc namespace:namespace eval tcl::mathfunc { namespace import ::otherns::* }References:tcl talked badly (and high on reddit) ,comp.lang.tcl ,2008-02-15
Using Math Functions in a Namespace edit
DKF: If you like doing your computations the Lisp way, add this to your scripts:namespace path {::tcl::mathop ::tcl::mathfunc}Now you can use all the above functions (and the math operators) as commands without qualification.atan2 edit
AMG: The man page for atan2 says that its arguments can't both be zero [1]. On one system I checked, expr atan2(0,0) returns 0.0. On other systems, I suspect it may behave differently. Right? If so, shouldn't the implementation of atan2 check if both arguments are zero and throw an error?Non-Math mathfunc edit
bsg: Non-math mathfunc: who says all mathfunc's have to be about math. Turning common tcl commands into functions can clean up conditional statements, making them easier to read.Turn something like this:if {[lindex $data [expr {2*$i +1}]] eq [lindex $items [expr {2*$itemno +1}]]} {break}into this:if {lindex($data, (2*$i+1)) eq lindex($items, (2*$itemno +1))} {break}Another example:if { $priv(mBar) eq [string range $menu 0 [expr {[string length $priv(mBar)] - 1}]]} { ... }
if { $priv(mBar) eq substr($menu, 0, (strlen($priv(mBar)) - 1))} { ... }Notice how it also eliminates the recursive expr calls.Here's what I've found useful so far:namespace eval tcl::mathfunc {
proc strlen {str} {
::string length $str
}
proc stridx {str index} {
::string index $str $index
}
proc substr {str first last} {
::string range $str $first $last
}
proc llength {list} {
::llength $list
}
proc lindex {list index args} {
::lindex $list $index {*}$args
}
proc lrange {list first last} {
::lrange $list $first $last
}
}
