texinode(Arithmetic Evaluation)(Conditional Expressions)(Jobs & Signals)(Top) chapter(Arithmetic Evaluation) ifzman(\ sect(Arithmetic Evaluation) )\ cindex(arithmetic evaluation) cindex(evaluation, arithmetic) findex(let, use of) The shell can perform integer and floating point arithmetic, either using the builtin tt(let), or via a substitution of the form tt(\$((...))). For integers, the shell is usually compiled to use 8-byte precision where this is available, otherwise precision is 4 bytes. This can be tested, for example, by giving the command `tt(print - \$(( 12345678901 )))'; if the number appears unchanged, the precision is at least 8 bytes. Floating point arithmetic is always double precision. The tt(let) builtin command takes arithmetic expressions as arguments; each is evaluated separately. Since many of the arithmetic operators, as well as spaces, require quoting, an alternative form is provided: for any command which begins with a `tt(LPAR()LPAR())', all the characters until a matching `tt(RPAR()RPAR())' are treated as a quoted expression and arithmetic expansion performed as for an argument of tt(let). More precisely, `tt(LPAR()LPAR())var(...)tt(RPAR()RPAR())' is equivalent to `tt(let ")var(...)tt(")'. For example, the following statement example((( val = 2 + 1 ))) is equivalent to example(let "val = 2 + 1") both assigning the value 3 to the shell variable tt(val) and returning a zero status. cindex(bases, in arithmetic) Integers can be in bases other than 10. A leading `tt(0x)' or `tt(0X)' denotes hexadecimal. Integers may also be of the form `var(base)tt(#)var(n)', where var(base) is a decimal number between two and thirty-six representing the arithmetic base and var(n) is a number in that base (for example, `tt(16#ff)' is 255 in hexadecimal). The var(base)tt(#) may also be omitted, in which case base 10 is used. For backwards compatibility the form `tt([)var(base)tt(])var(n)' is also accepted. It is also possible to specify a base to be used for output in the form `tt([#)var(base)tt(])', for example `tt([#16])'. This is used when outputting arithmetical substitutions or when assigning to scalar parameters, but an explicitly defined integer or floating point parameter will not be affected. If an integer variable is implicitly defined by an arithmetic expression, any base specified in this way will be set as the variable's output arithmetic base as if the option `tt(-i) var(base)' to the tt(typeset) builtin had been used. The expression has no precedence and if it occurs more than once in a mathematical expression, the last encountered is used. For clarity it is recommended that it appear at the beginning of an expression. As an example: example(typeset -i 16 y print \$(( [#8] x = 32, y = 32 )) print \$x \$y) outputs first `tt(8#40)', the rightmost value in the given output base, and then `tt(8#40 16#20)', because tt(y) has been explicitly declared to have output base 16, while tt(x) (assuming it does not already exist) is implicitly typed by the arithmetic evaluation, where it acquires the output base 8. When an output base is specified using the `tt([#)var(base)tt(])' syntax, an appropriate base prefix will be output if necessary, so that the value output is valid syntax for input. If the tt(#) is doubled, for example `tt([##16])', then no base prefix is output. Floating point constants are recognized by the presence of a decimal point or an exponent. The decimal point may be the first character of the constant, but the exponent character tt(e) or tt(E) may not, as it will be taken for a parameter name. cindex(arithmetic operators) cindex(operators, arithmetic) An arithmetic expression uses nearly the same syntax, precedence, and associativity of expressions in C. The following operators are supported (listed in decreasing order of precedence): startsitem() sitem(tt(PLUS() - ! ~ PLUS()PLUS() --))(unary plus/minus, logical NOT, complement, {pre,post}{in,de}crement) sitem(tt(<< >>))(bitwise shift left, right) sitem(tt(&))(bitwise AND) sitem(tt(^))(bitwise XOR) sitem(tt(|))(bitwise OR) sitem(tt(**))(exponentiation) sitem(tt(* / %))(multiplication, division, modulus (remainder)) sitem(tt(PLUS() -))(addition, subtraction) sitem(tt(< > <= >=))(comparison) sitem(tt(== !=))(equality and inequality) sitem(tt(&&))(logical AND) sitem(tt(|| ^^))(logical OR, XOR) sitem(tt(? :))(ternary operator) sitem(tt(= PLUS()= -= *= /= %= &= ^= |= <<= >>= &&= ||= ^^= **=))(assignment) sitem(tt(,))(comma operator) endsitem() The operators `tt(&&)', `tt(||)', `tt(&&=)', and `tt(||=)' are short-circuiting, and only one of the latter two expressions in a ternary operator is evaluated. Note the precedence of the bitwise AND, OR, and XOR operators. cindex(math functions) cindex(functions, math) Mathematical functions can be called with the syntax `var(func)tt(LPAR())var(args)tt(RPAR())', where the function decides if the var(args) is used as a string or a comma-separated list of arithmetic expressions. The shell currently defines no mathematical functions by default, but the module tt(zsh/mathfunc) may be loaded with the tt(zmodload) builtin to provide standard floating point mathematical functions. An expression of the form `tt(##)var(x)' where var(x) is any character sequence such as `tt(a)', `tt(^A)', or `tt(\M-\C-x)' gives the ASCII value of this character and an expression of the form `tt(#)var(foo)' gives the ASCII value of the first character of the value of the parameter var(foo). Note that this is different from the expression `tt(\$#)var(foo)', a standard parameter substitution which gives the length of the parameter var(foo). `tt(#\)' is accepted instead of `tt(##)', but its use is deprecated. Named parameters and subscripted arrays can be referenced by name within an arithmetic expression without using the parameter expansion syntax. For example, example(((val2 = val1 * 2))) assigns twice the value of tt(\$val1) to the parameter named tt(val2). An internal integer representation of a named parameter can be specified with the tt(integer) builtin. cindex(parameters, integer) cindex(integer parameters) findex(integer, use of) Arithmetic evaluation is performed on the value of each assignment to a named parameter declared integer in this manner. Assigning a floating point number to an integer results in rounding down to the next integer. cindex(parameters, floating point) cindex(floating point parameters) findex(float, use of) Likewise, floating point numbers can be declared with the tt(float) builtin; there are two types, differing only in their output format, as described for the tt(typeset) builtin. The output format can be bypassed by using arithmetic substitution instead of the parameter substitution, i.e. `tt(\${)var(float)tt(})' uses the defined format, but `tt(\$LPAR()LPAR())var(float)tt(RPAR()RPAR())' uses a generic floating point format. Promotion of integer to floating point values is performed where necessary. In addition, if any operator which requires an integer (`tt(~)', `tt(&)', `tt(|)', `tt(^)', `tt(%)', `tt(<<)', `tt(>>)' and their equivalents with assignment) is given a floating point argument, it will be silently rounded down to the next integer. Scalar variables can hold integer or floating point values at different times; there is no memory of the numeric type in this case. If a variable is first assigned in a numeric context without previously being declared, it will be implicitly typed as tt(integer) or tt(float) and retain that type either until the type is explicitly changed or until the end of the scope. This can have unforeseen consequences. For example, in the loop example(for (( f = 0; f < 1; f += 0.1 )); do # use \$f done) if tt(f) has not already been declared, the first assignment will cause it to be created as an integer, and consequently the operation `tt(f += 0.1)' will always cause the result to be truncated to zero, so that the loop will fail. A simple fix would be to turn the initialization into `tt(f = 0.0)'. It is therefore best to declare numeric variables with explicit types.