The ::tcl::mathfunc namespace provides commands for all the functions available in [expr]
::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.
| 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 |
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.
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);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)}
}
}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
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.
AMG: The man page for atan2 says that its arguments can't both be zero [L1 ]. 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?
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
}
}arjen: Mathematical functions defined this way can take lists as arguments and produce lists as results, as illustrated by these rather trivial examples:
proc tcl::mathfunc::maxlist {values} {
set maxvalue [lindex $values 0]
foreach value $values {
set maxvalue [expr {$value > $maxvalue? $value : $maxvalue}]
}
return $maxvalue
}
proc tcl::mathfunc::multiply {factor values} {
set result {}
foreach value $values {
lappend result [expr {$factor * $value}]
}
return $result
}
puts [expr {maxlist({4 1 2 3})}]
puts [expr {multiply(2,{4 1 2 3})}]