misc.tcl

Go to the documentation of this file.
00001 /*  math.tcl --*/
00002 /* */
00003 /*  Collection of math functions.*/
00004 /* */
00005 /*  Copyright (c) 1998-2000 by Ajuba Solutions.*/
00006 /* */
00007 /*  See the file "license.terms" for information on usage and redistribution*/
00008 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00009 /*  */
00010 /*  RCS: @(#) $Id: misc.tcl,v 1.6 2005/10/10 14:02:47 arjenmarkus Exp $*/
00011 
00012 package require Tcl 8.2     ;/*  uses [lindex $l end-$integer]*/
00013 namespace ::math {
00014 }
00015 
00016 /*  ::math::cov --*/
00017 /* */
00018 /*  Return the coefficient of variation of three or more values*/
00019 /* */
00020 /*  Arguments:*/
00021 /*  val1    first value*/
00022 /*  val2    second value*/
00023 /*  args    other values*/
00024 /* */
00025 /*  Results:*/
00026 /*  cov coefficient of variation expressed as percent value*/
00027 
00028 ret  ::math::cov (type val1 , type val2 , type args) {
00029      set sum [ expr { $val1+$val2 } ]
00030      set N [ expr { [ llength $args ] + 2 } ]
00031      foreach val $args {
00032         set sum [ expr { $sum+$val } ]
00033      }
00034      set mean [ expr { $sum/$N } ]
00035      set sigma_sq 0
00036      foreach val [ concat $val1 $val2 $args ] {
00037         set sigma_sq [ expr { $sigma_sq+pow(($val-$mean),2) } ]
00038      }
00039      set sigma_sq [ expr { $sigma_sq/($N-1) } ] 
00040      set sigma [ expr { sqrt($sigma_sq) } ]
00041      if { $mean != 0.0 } { 
00042         set cov [ expr { ($sigma/$mean)*100 } ]
00043      } else {
00044         return -code error -errorinfo "Cov undefined for data with zero mean" -errorcode {ARITH DOMAIN}
00045      }
00046      set cov
00047 }
00048 
00049 /*  ::math::fibonacci --*/
00050 /* */
00051 /*  Return the n'th fibonacci number.*/
00052 /* */
00053 /*  Arguments:*/
00054 /*  n   The index in the sequence to compute.*/
00055 /* */
00056 /*  Results:*/
00057 /*  fib The n'th fibonacci number.*/
00058 
00059 ret  ::math::fibonacci (type n) {
00060     if { $n == 0 } {
00061     return 0
00062     } else {
00063     set prev0 0
00064     set prev1 1
00065     for {set i 1} {$i < $n} {incr i} {
00066         set tmp $prev1
00067         incr prev1 $prev0
00068         set prev0 $tmp
00069     }
00070     return $prev1
00071     }
00072 }
00073 
00074 /*  ::math::integrate --*/
00075 /* */
00076 /*  calculate the area under a curve defined by a set of (x,y) data pairs.*/
00077 /*  the x data must increase monotonically throughout the data set for the */
00078 /*  calculation to be meaningful, therefore the monotonic condition is*/
00079 /*  tested, and an error is thrown if the x value is found to be*/
00080 /*  decreasing.*/
00081 /* */
00082 /*  Arguments:*/
00083 /*  xy_pairs    list of x y pairs (eg, 0 0 10 10 20 20 ...); at least 5*/
00084 /*          data pairs are required, and if the number of data*/
00085 /*          pairs is even, a padding value of (x0, 0) will be*/
00086 /*          added.*/
00087 /*  */
00088 /*  Results:*/
00089 /*  result      A two-element list consisting of the area and error*/
00090 /*          bound (calculation is "Simpson's rule")*/
00091 
00092 ret  ::math::integrate ( type xy_, type pairs ) {
00093      
00094      set length [ llength $xy_pairs ]
00095      
00096      if { $length < 10 } {
00097         return -code error "at least 5 x,y pairs must be given"
00098      }   
00099      
00100      ;## are we dealing with x,y pairs?
00101      if { [ expr {$length % 2} ] } {
00102         return -code error "unmatched xy pair in input"
00103      }
00104      
00105      ;## are there an even number of pairs?  Augment.
00106      if { ! [ expr {$length % 4} ] } {
00107         set xy_pairs [ concat [ lindex $xy_pairs 0 ] 0 $xy_pairs ]
00108      }
00109      set x0   [ lindex $xy_pairs 0     ]
00110      set x1   [ lindex $xy_pairs 2     ]
00111      set xn   [ lindex $xy_pairs end-1 ]
00112      set xnminus1 [ lindex $xy_pairs end-3 ]
00113     
00114      if { $x1 < $x0 } {
00115         return -code error "monotonicity broken by x1"
00116      }
00117 
00118      if { $xn < $xnminus1 } {
00119         return -code error "monotonicity broken by xn"
00120      }   
00121      
00122      ;## handle the assymetrical elements 0, n, and n-1.
00123      set sum [ expr {[ lindex $xy_pairs 1 ] + [ lindex $xy_pairs end ]} ]
00124      set sum [ expr {$sum + (4*[ lindex $xy_pairs end-2 ])} ]
00125 
00126      set data [ lrange $xy_pairs 2 end-4 ]
00127      
00128      set xmax $x1
00129      set i 1
00130      foreach {x1 y1 x2 y2} $data {
00131         incr i
00132         if { $x1 < $xmax } {
00133            return -code error "monotonicity broken by x$i"
00134         }
00135         set xmax $x1
00136         incr i
00137         if { $x2 < $xmax } {
00138            return -code error "monotonicity broken by x$i"
00139         }
00140         set xmax $x2
00141         set sum [ expr {$sum + (4*$y1) + (2*$y2)} ]
00142      }   
00143      
00144      if { $xmax > $xnminus1 } {
00145         return -code error "monotonicity broken by xn-1"
00146      }   
00147     
00148      set h [ expr { ( $xn - $x0 ) / $i } ]
00149      set area [ expr { ( $h / 3.0 ) * $sum } ]
00150      set err_bound  [ expr { ( ( $xn - $x0 ) / 180.0 ) * pow($h,4) * $xn } ]  
00151      return [ list $area $err_bound ]
00152 }
00153 
00154 /*  ::math::max --*/
00155 /* */
00156 /*  Return the maximum of two or more values*/
00157 /* */
00158 /*  Arguments:*/
00159 /*  val first value*/
00160 /*  args    other values*/
00161 /* */
00162 /*  Results:*/
00163 /*  max maximum value*/
00164 
00165 ret  ::math::max (type val , type args) {
00166     set max $val
00167     foreach val $args {
00168     if { $val > $max } {
00169         set max $val
00170     }
00171     }
00172     set max
00173 }
00174 
00175 /*  ::math::mean --*/
00176 /* */
00177 /*  Return the mean of two or more values*/
00178 /* */
00179 /*  Arguments:*/
00180 /*  val first value*/
00181 /*  args    other values*/
00182 /* */
00183 /*  Results:*/
00184 /*  mean    arithmetic mean value*/
00185 
00186 ret  ::math::mean (type val , type args) {
00187     set sum $val
00188     set N [ expr { [ llength $args ] + 1 } ]
00189     foreach val $args {
00190         set sum [ expr { $sum + $val } ]
00191     }
00192     set mean [expr { double($sum) / $N }]
00193 }
00194 
00195 /*  ::math::min --*/
00196 /* */
00197 /*  Return the minimum of two or more values*/
00198 /* */
00199 /*  Arguments:*/
00200 /*  val first value*/
00201 /*  args    other values*/
00202 /* */
00203 /*  Results:*/
00204 /*  min minimum value*/
00205 
00206 ret  ::math::min (type val , type args) {
00207     set min $val
00208     foreach val $args {
00209     if { $val < $min } {
00210         set min $val
00211     }
00212     }
00213     set min
00214 }
00215 
00216 /*  ::math::product --*/
00217 /* */
00218 /*  Return the product of one or more values*/
00219 /* */
00220 /*  Arguments:*/
00221 /*  val first value*/
00222 /*  args    other values*/
00223 /* */
00224 /*  Results:*/
00225 /*  prod     product of multiplying all values in the list*/
00226 
00227 ret  ::math::product (type val , type args) {
00228     set prod $val
00229     foreach val $args {
00230         set prod [ expr { $prod*$val } ]
00231     }
00232     set prod
00233 }
00234 
00235 /*  ::math::random --*/
00236 /* */
00237 /*  Return a random number in a given range.*/
00238 /* */
00239 /*  Arguments:*/
00240 /*  args    optional arguments that specify the range within which to*/
00241 /*      choose a number:*/
00242 /*          (null)      choose a number between 0 and 1*/
00243 /*          val     choose a number between 0 and val*/
00244 /*          val1 val2   choose a number between val1 and val2*/
00245 /* */
00246 /*  Results:*/
00247 /*  num a random number in the range.*/
00248 
00249 ret  ::math::random (type args) {
00250     set num [expr {rand()}]
00251     if { [llength $args] == 0 } {
00252     return $num
00253     } elseif { [llength $args] == 1 } {
00254     return [expr {int($num * [lindex $args 0])}]
00255     } elseif { [llength $args] == 2 } {
00256     foreach {lower upper} $args break
00257     set range [expr {$upper - $lower}]
00258     return [expr {int($num * $range) + $lower}]
00259     } else {
00260     set fn [lindex [info level 0] 0]
00261     error "wrong # args: should be \"$fn ?value1? ?value2?\""
00262     }
00263 }
00264 
00265 /*  ::math::sigma --*/
00266 /* */
00267 /*  Return the standard deviation of three or more values*/
00268 /* */
00269 /*  Arguments:*/
00270 /*  val1    first value*/
00271 /*  val2    second value*/
00272 /*  args    other values*/
00273 /* */
00274 /*  Results:*/
00275 /*  sigma   population standard deviation value*/
00276 
00277 ret  ::math::sigma (type val1 , type val2 , type args) {
00278      set sum [ expr { $val1+$val2 } ]
00279      set N [ expr { [ llength $args ] + 2 } ]
00280      foreach val $args {
00281         set sum [ expr { $sum+$val } ]
00282      }
00283      set mean [ expr { $sum/$N } ]
00284      set sigma_sq 0
00285      foreach val [ concat $val1 $val2 $args ] {
00286         set sigma_sq [ expr { $sigma_sq+pow(($val-$mean),2) } ]
00287      }
00288      set sigma_sq [ expr { $sigma_sq/($N-1) } ] 
00289      set sigma [ expr { sqrt($sigma_sq) } ]
00290      set sigma
00291 }     
00292 
00293 /*  ::math::stats --*/
00294 /* */
00295 /*  Return the mean, standard deviation, and coefficient of variation as*/
00296 /*  percent, as a list.*/
00297 /* */
00298 /*  Arguments:*/
00299 /*  val1    first value*/
00300 /*  val2    first value*/
00301 /*  args    all other values*/
00302 /* */
00303 /*  Results:*/
00304 /*  {mean stddev coefvar}*/
00305 
00306 ret  ::math::stats (type val1 , type val2 , type args) {
00307      set sum [ expr { $val1+$val2 } ]
00308      set N [ expr { [ llength $args ] + 2 } ]
00309      foreach val $args {
00310         set sum [ expr { $sum+$val } ]
00311      }
00312      set mean [ expr { $sum/$N } ]
00313      set sigma_sq 0
00314      foreach val [ concat $val1 $val2 $args ] {
00315         set sigma_sq [ expr { $sigma_sq+pow(($val-$mean),2) } ]
00316      }
00317      set sigma_sq [ expr { $sigma_sq/($N-1) } ] 
00318      set sigma [ expr { sqrt($sigma_sq) } ]
00319      set cov [ expr { ($sigma/$mean)*100 } ]
00320      return [ list $mean $sigma $cov ]
00321 }
00322 
00323 /*  ::math::sum --*/
00324 /* */
00325 /*  Return the sum of one or more values*/
00326 /* */
00327 /*  Arguments:*/
00328 /*  val first value*/
00329 /*  args    all other values*/
00330 /* */
00331 /*  Results:*/
00332 /*  sum arithmetic sum of all values in args*/
00333 
00334 ret  ::math::sum (type val , type args) {
00335     set sum $val
00336     foreach val $args {
00337         set sum [ expr { $sum+$val } ]
00338     }
00339     set sum
00340 }
00341 
00342 /* ----------------------------------------------------------------------*/
00343 /* */
00344 /*  ::math::expectDouble --*/
00345 /* */
00346 /*  Format an error message that an argument was expected to be*/
00347 /*  double and wasn't*/
00348 /* */
00349 /*  Parameters:*/
00350 /*  arg -- Misformatted argument*/
00351 /* */
00352 /*  Results:*/
00353 /*  Returns an appropriate error message*/
00354 /* */
00355 /*  Side effects:*/
00356 /*  None.*/
00357 /* */
00358 /* ----------------------------------------------------------------------*/
00359 
00360 ret  ::math::expectDouble ( type arg ) {
00361     return [format "expected a floating-point number but found \"%.50s\"" $arg]
00362 }
00363 
00364 /* ----------------------------------------------------------------------*/
00365 /* */
00366 /*  ::math::expectInteger --*/
00367 /* */
00368 /*  Format an error message that an argument was expected to be*/
00369 /*  integer and wasn't*/
00370 /* */
00371 /*  Parameters:*/
00372 /*  arg -- Misformatted argument*/
00373 /* */
00374 /*  Results:*/
00375 /*  Returns an appropriate error message*/
00376 /* */
00377 /*  Side effects:*/
00378 /*  None.*/
00379 /* */
00380 /* ----------------------------------------------------------------------*/
00381 
00382 ret  ::math::expectInteger ( type arg ) {
00383     return [format "expected an integer but found \"%.50s\"" $arg]
00384 }
00385 
00386 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1