The Tcl command for doing math type operations is expr
. The following discussion of the
expr
command is extracted and
adapted from the expr
man page. Many
commands use expr
behind the scenes in
order to evaluate test expressions, such as if
, while
and
for
loops, discussed in later sections.
All of the advice given here for expr
also holds for these other commands.
expr
takes all of its arguments ("2
+ 2" for example) and evaluates the result as a Tcl "expression"
(rather than a normal command), and returns the value. The
operators permitted in Tcl expressions include all the standard
math functions, logical operators, bitwise operators, as well as
math functions like rand()
, sqrt()
, cosh()
and so on. Expressions almost
always yield numeric results (integer or floating-point values).
Performance tip: enclosing the arguments to
expr
in curly braces will result in
faster code. So do expr {$i * 10}
instead of simply expr $i * 10
WARNING: You should always use
braces when evaluating expressions that may contain user input, to avoid
possible security breaches. The expr
command performs its own round of substitutions on variables and
commands, so you should use braces to prevent the Tcl interpreter doing
this as well (leading to double substitution). To illustrate the
danger, consider this interactive session:
% set userinput {[puts DANGER!]} [puts DANGER!] % expr $userinput == 1 DANGER! 0 % expr {$userinput == 1} 0
In the first example, the code contained in the user-supplied input
is evaluated, whereas in the second the braces prevent this potential
danger. As a general rule, always surround expressions with braces,
whether using expr
directly or some other
command that takes an expression (such as if
or while
).
A Tcl expression consists of a combination of operands, operators, and parentheses. White space may be used between operands, operators and parentheses; it is ignored by the expression processor. Where possible, operands are interpreted as integer values. Integer values may be specified in decimal (the normal case), in octal (if the first character of the operand is 0), or in hexadecimal (if the first two characters of the operand are 0x).
Note that the octal and hexadecimal conversion takes place
differently in the expr
command
than in the Tcl substitution phase. In the substitution phase,
a \x32
would be converted to an ascii "2", while expr
would convert 0x32
to a
decimal 50.
If an operand does not have one of the integer formats given above, then it is treated as a floating-point number, if that is possible. Floating-point numbers may be specified in any of the ways accepted by an ANSI-compliant C compiler. For example, all of the following are valid floating-point numbers:
2.1 3. 6E4 7.91e+16 .000001
If no numeric interpretation is possible, then an operand is left as a string (and only a limited set of operators may be applied to it).
Note however, that it does not support numbers of the following forms:
2,1 - a decimal comma, instead of a decimal point 2,100 - a thousands separatorIt is possible to deal with numbers in that form, but you will have to convert these "strings" to numbers in the standard form first.
Beware of leading zeros: 0700 is not interpreted as the decimal number 700 (seven hundred), but as the octal number 700 = 7*8*8 = 448 (decimal).
Worse, if the number contains a digit 8 or 9 an error results:
% expr {0900+1} expected integer but got "0900" (looks like invalid octal number)Octal numbers are in fact a relic of the past, when such number formats were much more common.
Operands may be specified in any of the following ways:
The valid operators are listed below, grouped in decreasing order of precedence:
eq
) or
inequality (ne
).
and two operators for checking if a string is contained in a list
(in
) or not (ni
).
These operators all return 1 (true) or 0 (false).
Using these operators ensures that the operands are regarded
exclusively as strings (and lists), not as possible numbers:
% expr { "9" == "9.0"} 1 % expr { "9" eq "9.0"} 0
% set x 1 % expr { $x>0? ($x+1) : ($x-1) } 2
Tcl supports the following mathematical functions in expressions:
abs acos asin atan atan2 bool ceil cos cosh double entier exp floor fmod hypot int isqrt log log10 max min pow rand round sin sinh sqrt srand tan tanh wide
Besides these functions, you can also apply commands within an expression. For instance:
% set x 1 % set w "Abcdef" % expr { [string length $w]-2*$x } 4
Tcl supports the following functions to convert from one representation of a number to another:
double int wide entier
double()
converts a number to a
floating-point number.
int()
converts a number to an
ordinary integer number (by truncating the decimal part).
wide()
converts a number to a
so-called wide integer number (these numbers have a larger range).
entier()
coerces a number to an integer of
appropriate size to hold it without truncation. This might return the same
as int() or wide() or an integer of arbitrary size (in Tcl 8.5 and above).
The next lesson explains the various types of numbers in more detail.
set X 100 set Y 256 set Z [expr {$Y + $X}] set Z_LABEL "$Y plus $X is " puts "$Z_LABEL $Z" puts "The square root of $Y is [expr { sqrt($Y) }]\n" puts "Because of the precedence rules \"5 + -3 * 4\" is: [expr {-3 * 4 + 5}]" puts "Because of the parentheses \"(5 + -3) * 4\" is: [expr {(5 + -3) * 4}]" set A 3 set B 4 puts "The hypotenuse of a triangle: [expr {hypot($A,$B)}]" # # The trigonometric functions work with radians ... # set pi6 [expr {3.1415926/6.0}] puts "The sine and cosine of pi/6: [expr {sin($pi6)}] [expr {cos($pi6)}]" # # Working with arrays # set a(1) 10 set a(2) 7 set a(3) 17 set b 2 puts "Sum: [expr {$a(1)+$a($b)}]"