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