Version 16 of tcl::mathfunc

Updated 2008-04-23 08:00:01 by dkf

Tcl 8.5 namespace that contains the definitions of all functions used in expr. 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.

[TODO: Combine text below with this page]


AMG: TIP 232 [L1 ] creates the ::tcl::mathfunc namespace which contains commands implementing the [expr] math functions. The functions are documented in the mathfunc(n) man page [L2 ]. (Previous to TIP 232, the math functions were documented in expr(n).)


List of functions

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

AMG: Why is the Wiki converting spaces to tabs in the markup for the above table? It doesn't seem to be doing it correctly, either. Somebody please look into this.

Lars H: Have you considered the possibility that it was you that did it? (The change happened with an edit you saved.) It's the kind of thing I would expect to see if editing the wiki from within a text editor (e.g. Emacs) and that is set to convert spaces to tabs without asking.

AMG: If so, it's a bug in Firefox, because that's what I used. I say it's a bug rather than merely an unasked-for feature because no tab stop setting makes the columns come out right again. Also, I wasn't the one who reformatted this table using the new markup, yet the problem was here when I edited it to put the blank column in the middle. Maybe Firefox retabbed it when loading the edit page. As an experiment, I will manually fix the table. Let's see what gets saved.


Thanks to TIP 232 [L3 ], you can create new functions without having to resort to Tcl_CreateMathFunc(3) [L4 ]. This makes it possible for pure Tcl scripts to extend [expr]. Also this makes it possible to rewrite or delete math functions, two things that were previously impossible even for extensions written in C. (I have written code that needed this functionality; I guess it's time to update it!)

This makes math function arguments much more flexible, just as flexible as those of Tcl procs and commands. One possibility worth noting is variadic numbers of arguments, a feature used by the shiny, new min() and max() functions.

One more neat trick is calling math functions without using [expr]; they're regular Tcl commands now. Combine this with TIP 174 Math Operators as Commands, and you can avoid using [expr] altogether, bypassing the problems discussed at brace your expr-essions.

See the TIP for more creative usage ideas.


Neil Madden writes [L5 ]:

namespace eval tcl::mathfunc { namespace import ::otherns::* }

as a one liner to import a namespace worth of math functions into expr.


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: Here's a math function I sometimes find useful. It accepts three arguments, and it returns whichever of the three is between the other two. It's mostly useful to clamp a number to a range.

 proc ::tcl::mathfunc::mid {a b c} {
     lindex [lsort -real [list $a $b $c]] 1
 }

It can also be implemented as a bunch of [if]s, which is how I do it in C.

Here is one incorrect implementation you should watch out for:

 proc ::tcl::mathfunc::mid {a b c} {
     expr {max($a, min($b, $c))}
 }

This is what Allegro (include/allegro/base.h) has used since the dawn of time. :^( I'm reporting it now; hopefully it'll be fixed. If you're curious, see [L6 ] for my writeup.

KPV The folk algorithm for finding the middle number (or second highest in a longer list) is to take the max of the pair-wise mins. To wit:

  max(min($a,$b), min($a,$c), min($b,$c))

LV So what is an example of a case in which the second, incorrect, version of the algorithm fails? Answer: "incorrect_mid 1 0 0" returns 1. The problem is it doesn't (always) handle the case where two of the inputs are the same. Doh.

AMG: I thought the problem was that it doesn't handle the case of the first input being greater than the other two. This wasn't a problem for Allegro because everyone used its MID macro thusly: MID(minimum_value, value_to_clamp, maximum_value).


RS 2008-01-02: Here's a little example for a user-defined recursive factorial function:

 % proc tcl::mathfunc::fac x {expr {$x<2? 1: $x*fac($x-1)}}
 % expr fac(5)
 120