Version 9 of Additional math functions

Updated 2001-11-17 10:52:09

* integrate


I see a factorial function on 3-4 different pages -some not even about math. And yet none in the tcllib math library. Perhaps one should be submitted. How to determine best?


Perhaps this function should move to the Stats page mentioned above? Square mean and standard deviation:

 proc mean2 list {
        set sum 0
        foreach i $list {set sum [expr {$sum+$i*$i}]}
        expr {double($sum)/[llength $list]}
 }
 proc stddev list {
        set m [mean $list] ;# see below for [mean]
        expr {sqrt([mean2 $list]-$m*$m)}
 } ;# RS

Binomial coefficient: Perhaps the best (what criteria?) should move to the Binomial page and just a pointer to the page should be here? (This got too long; I'm keeping the best algorithm here, moving the previous discussion to Binomial Coefficients. This solution is called binom3 in that page.)

 proc binom {m n} {
     set n [expr {(($m-$n) > $n) ? $m-$n : $n}]

     if {$n > $m}  {return 0}
     if {$n == $m} {return 1}

     set res 1
     set d 0
     while {$n < $m} {
         set res [expr {($res*[incr n])/[incr d]}]
     }
     set res
 }

Prime factors of an integer:

 proc primefactors n {
    # a number x is prime if [llength [primefactors $x]]==1
    set res {}
    set f 2
    while {$f<=$n} {
        while {$n%$f==0} {
            set n [expr {$n/$f}]
            lappend res $f
        }
        set f [expr {$f+2-($f==2)}]
    }
    set res
 } ;#RS

Linear regression and correlation coefficient:

 proc reg,cor points {
    # linear regression y=ax+b for {{x0 y0} {x1 y1}...}
    # returns {a b r}, where r: correlation coefficient
    foreach i {N Sx Sy Sxy Sx2 Sy2} {set $i 0}
    foreach point $points {
        foreach {x y} $point break
        set Sx  [expr {$Sx  + $x}]
        set Sy  [expr {$Sy  + $y}]
        set Sx2 [expr {$Sx2 + $x*$x}]
        set Sy2 [expr {$Sy2 + $y*$y}]
        set Sxy [expr {$Sxy + $x*$y}]
        incr N
    }
    set t1 [expr {$N*$Sxy - $Sx*$Sy}]
    set t2 [expr {$N*$Sx2 - $Sx*$Sx}]
    set a [expr {double($t1)/$t2}]
    set b [expr {double($Sy-$a*$Sx)/$N}]
    set r [expr {$t1/(sqrt($t2)*sqrt($N*$Sy2-$Sy*$Sy))}]
    list $a $b $r
 } ;#RS

Sign of a number:

 proc sgn {a} {expr {$a>0 ? 1 : $a<0 ? -1 : 0}} ;# rmax

Actually,

    string compare $a 0

seems to give the correct result for all integer values and floating point values not equal to 0.

0.0 (and 0.00 etc) [string compare 0.0 0] returns 1, however.


Traditional degrees: clock format can be put to un-timely uses. As degrees especially in geography are also subdivided in minutes and seconds, how's this one-liner for formatting decimal degrees:

 proc dec2deg x {concat [expr int($x)]� [clock format [expr round($x*3600)] -format "%M' %S\""]}

An additional -gmt 1 switch is needed if you happen to live in a non-integer timezone. (RS)

Cross-sum of non-negative integers:

 proc crosssum {x} {expr [join [split $x ""] +]}

Note that this expression may not be braced. (RS)


Should this function move to the Stats page? Means of a number list: (arithmetic, geometric, quadratic, harmonic)

 proc mean  L {expr ([join $L +])/[llength $L].}
 proc gmean L {expr pow([join $L *],1./[llength $L])}
 proc qmean L {expr sqrt((pow([join $L ,2)+pow(],2))/[llength $L])}
 proc hmean L {expr [llength $L]/(1./[join $L +1./])}

where qmean is the best braintwister... For a list of {1 2} the string

 sqrt((pow( 1 ,2)+pow( 2 ,2))/ 2)

(blanks added for clarity) is built up and fed to expr, where it makes a perfectly well-formed expression if not braced. (RS)


Logarithm to any base:

 proc log {base x} {expr {log($x)/log($base)}} ;# RS

A faster logarithm to base two:

 proc ld x "expr {log(\$x)/[expr log(2)]}"

This is an example of a "live" proc body - the divisor is computed only once, at definition time. With a single backslash escape needed, it's worth the fun ;-) (RS)


Epsilon: Comparing two floats x,y for equality is most safely done by testing abs($x-$y)<$eps, where eps is a sufficiently small number. You can find out which eps is good for your machine with the following code:

 proc eps {{base 1}} {
    set eps 1e-20
    while {$base-$eps==$base} {
        set eps [expr {$eps+1e-22}]
    }
    set eps     [expr {$eps+1e-22}]
 }
 % eps 1
 5.55112000002e-017 ;# on both my Win2K/P3 and Sun/Solaris
 % eps 0.1
 6.93889999999e-018
 % eps 0.01
 8.674e-019
 % eps 0.001
 1.085e-019

CritLib (see the Critcl page) now includes an adapted version of Donal K. Fellows' extension which lets you write numerical functions for "expr" in Tcl. See the "mathf" readme [L1 ] - JCW


Mathematically oriented extensions - Arts and crafts of Tcl-Tk programming