Skip to main content

  | मौसम…

411 समाचार
Public archive edition · Attributed source reporting with original dates · AI drafts are excluded

411 REFERENCE · Wikibooks

Tcl Programming/expr

Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.

Overview Arithmetic and logical operations (plus some string comparisons) are in Tcl concentrated in the expr command. It takes one or more arguments, evaluates them as an expression, and returns the result. The language of the expr command (also used in condition arguments of the if, for, while commands) is basically equivalent to C's expressions, with infix operators and functions. Unlike C, references to variables have to be done with $var. Examples: set a [expr {($b + sin($c))/2.}] if {$a > $b && $b > $c} {puts "ordered"} for {set i 10} {$i >= 0} {incr i -1} {puts $i...} ;# countdown The difference between Tcl syntax and expr syntax can be contrasted like this: [f $x $y] ;# Tcl: embedded command f($x,$y) ;# expr: function call, comma between arguments In another contrast to Tcl syntax, whitespace between "words" is optional (but still recommended for better readability :) And string constants must always be quoted (or braced if you wish): if {$keyword eq "foo"} ... Then again, Tcl commands can always be embedded into expressions, in square brackets as usual: proc max {x y} {expr {$x>$y? $x: $y}} expr {[max $a $b] + [max $c $d]} In expressions with numbers of mixed types, integers are coerced to doubles: % expr 1+2. 3.0 It is important to know that division of two integers is done as integer division: % expr 1/2 0 You get the (probably expected) floating-point division if at least one operand is double: % expr 1/2. 0.5 If you want to evaluate a string input by the user, but always use floating-point division, just transform it, before the call to expr, by replacing "/" with "*1./" (multiply with floating-point 1. before every division): expr [string map {/ *1./} $input] Brace your expressions In most cases it is safer and more efficient to pass a single braced argument to expr. Exceptions are: no variables or embedded commands to substitute operators or whole expressions to substitute The reason is that the Tcl parser parses unbraced expressions, while expr parses that result again. This may result in success for malicious code exploits: % set e {[file delete -force *]} % expr $e ;# will delete all files and directories % expr {$e} ;# will just return the string value of e That braced expressions evaluate much faster than unbraced ones, can be easily tested: % proc unbraced x {expr $x*$x} % proc braced x {expr {$x*$x}} % time {unbraced 42} 1000 197 microseconds per iteration % time {braced 42} 1000 34 microseconds per iteration The precision of the string representation of floating-point numbers is also controlled by the tcl_precision variable. The following example returns nonzero because the second term was clipped to 12 digits in making the string representation: % expr 1./3-[expr 1./3] 3.33288951992e-013 while this braced expression works more like expected: % expr {1./3-[expr 1./3]} 0.0 Operators Arithmetic, bitwise and logical operators are like in C, as is the conditional operator found in other languages (notably C): c?a:b -- if c is true, evaluate a, else b The conditional operator can be used for compact functional code (note that the following example requires Tcl 8.5 so that fac() can be called inside its own definition): % proc tcl::mathfunc::fac x {expr {$x<2? 1 : $x*fac($x-1)}} % expr fac(5) 120 Arithmetic operators The arithmetic operators are also like those found in C: + addition - (binary: subtraction. unary: change sign) * multiplication / (integer division if both operands are integer % (modulo, only on integers) ** power (available from Tcl 8.5) Bitwise operators The following operators work on integers only: & (AND) | (OR) ^ (XOR) ~ (NOT) << shift left >> shift right Logical operators The following operators take integers (where 0 is considered false, everything else true) and return a truth value, 0 or 1: && (and) || (or) ! (not - unary) Comparison operators If operands on both side are numeric, these operators compare them as numbers. Otherwise, string comparison is done. They return a truth value, 0 (false) or 1 (true): == equal != not equal > greater than >= greater or equal than < less than <= less or equal than As truth values are integers, you can use them as such for further computing, as the sign function demonstrates: proc sgn x {expr {($x>0) - ($x<0)}} % sgn 42 1 % sgn -42 -1 % sgn 0 0 String operators The following operators work on the string representation of their operands: eq string-equal ne not string-equal Examples how "equal" and "string equal" differ: % expr {1 == 1.0} 1 % expr {1 eq 1.0} 0 List operators From Tcl 8.5, the following operators are also available: a in b - 1 if a is a member of list b, else 0 a ni b - 1 if a is not a member of list b, else 0 Before 8.5, it's easy to write an equivalent function proc in {list el} {expr {[lsearch -exact $list $el]>=0}} Usage example: if [in $keys $key] ... which you can rewrite, once 8.5 is available wherever your work is to run, with if {$key in $keys} ... Functions The following functions are built-in: abs(x) - absolute value acos(x) - arc cosine. acos(-1) = 3.14159265359 (Pi) asin(x) - arc sine atan(x) - arc tangent atan2(y,x) ceil(x) - next-highest integral value cos(x) - cosine cosh(x) - hyperbolic cosine double(x) - convert to floating-point number exp(x) - e to the x-th power. exp(1) = 2.71828182846 (Euler number, e) floor(x) - next-lower integral value fmod(x,y) - floating-point modulo hypot(y,x) - hypotenuse (sqrt($y*$y+$x*$x), but at higher precision) int(x) - convert to integer (32-bit) log(x) - logarithm to base e log10(x) - logarithm to base 10 pow(x,y) - x to the y-th power rand() - random number > 0.0 and < 1.0 round(x) - round a number to nearest integral value sin(x) - sine sinh(x) - hyperbolic sine sqrt(x) - square root srand(x) - initialize random number generation with seed x tan(x) - tangent tanh(x) - hyperbolic tangent wide(x) - convert to wide (64-bit) integer Find out which functions are available with info functions: % info functions round wide sqrt sin double log10 atan hypot rand abs acos atan2 srand sinh floor log int tanh tan asin ceil cos cosh exp pow fmod Exporting expr functionalities If you don't want to write [[expr {$x+5}]] every time you need a little calculation, you can easily export operators as Tcl commands: foreach op {+ - * / %} {proc $op {a b} "expr {\$a $op \$b}"} After that, you can call these operators like in LISP: % + 6 7 13 % * 6 7 42 Of course, one can refine this by allowing variable arguments at least for + and *, or the single-argument case for -: proc - {a {b ""}} {expr {$b eq ""? -$a: $a-$b}} Similarly, expr functions can be exposed: foreach f {sin cos tan sqrt} {proc $f x "expr {$f\(\$x)}"} In Tcl 8.5, the operators can be called as commands in the ::tcl::mathop namespace: % tcl::mathop::+ 6 7 13 You can import them into the current namespace, for shorthand math commands: % namespace import ::tcl::mathop::* % + 3 4 ;# way shorter than [expr {3 + 4}] 7 % * 6 7 42 User-defined functions From Tcl 8.5, you can provide procs in the ::tcl::mathfunc namespace, which can then be used inside expr expressions: % proc tcl::mathfunc::fac x {expr {$x < 2? 1: $x * fac($x-1)}} % expr fac(100) 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 This is especially useful for recursive functions, or functions whose arguments need some expr calculations: % proc ::tcl::mathfunc::fib n {expr {$n<2? 1: fib($n-2)+fib($n-1)}} % expr fib(6) 13