mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-04 06:14:50 +01:00
252 lines
11 KiB
Text
252 lines
11 KiB
Text
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 always uses the `double' type with whatever corresponding
|
|
precision is provided by the compiler and the library.
|
|
|
|
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(")'. The return status is 0 if the arithmetic value
|
|
of the expression is non-zero, 1 if it is zero, and 2 if an error occurred.
|
|
|
|
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(arithmetic base)
|
|
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.
|
|
|
|
An integer expression or a base given in the form
|
|
`var(base)tt(#)var(n)' may contain underscores (`tt(_)') after the
|
|
leading digit for visual guidance; these are ignored in computation.
|
|
Examples are tt(1_000_000) or tt(0xffff_ffff) which are equivalent to
|
|
tt(1000000) and tt(0xffffffff) respectively.
|
|
|
|
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.
|
|
|
|
The var(base) may be replaced or followed by an underscore, which may
|
|
itself be followed by a positive integer (if it is missing the value 3
|
|
is used). This indicates that underscores should be inserted into the
|
|
output string, grouping the number for visual clarity. The following
|
|
integer specifies the number of digits to group together. For example:
|
|
|
|
example(setopt cbases
|
|
print $(( [#16_4] 65536 ** 2 )))
|
|
|
|
outputs `tt(0x1_0000_0000)'.
|
|
|
|
The feature can be used with floating
|
|
point numbers, in which case the base must be omitted; grouping
|
|
is away from the decimal point. For example,
|
|
|
|
example(zmodload zsh/mathfunc
|
|
print $(( [#_] sqrt+LPAR()1e7+RPAR() )))
|
|
|
|
outputs `tt(3_162.277_660_168_379_5)' (the number of decimal places
|
|
shown may vary).
|
|
|
|
pindex(C_BASES, use of)
|
|
pindex(OCTAL_ZEROES, use of)
|
|
If the tt(C_BASES) option is set, hexadecimal numbers in the standard C
|
|
format, for example tt(0xFF) instead of the usual `tt(16#FF)'. If the
|
|
option tt(OCTAL_ZEROES) is also set (it is not by default), octal numbers
|
|
will be treated similarly and hence appear as `tt(077)' instead of
|
|
`tt(8#77)'. This option has no effect on the output of bases other than
|
|
hexadecimal and octal, and these formats are always understood on input.
|
|
|
|
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. All numeric parts (before and after the
|
|
decimal point and in the exponent) may contain underscores after the
|
|
leading digit for visual guidance; these are ignored in computation.
|
|
|
|
cindex(arithmetic operators)
|
|
cindex(operators, arithmetic)
|
|
An arithmetic expression uses nearly the same syntax and
|
|
associativity of expressions as in C.
|
|
|
|
In the native mode of operation, 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.
|
|
|
|
With the option tt(C_PRECEDENCES) the precedences (but no other
|
|
properties) of the operators are altered to be the same as those in
|
|
most other languages that support the relevant operators:
|
|
|
|
startsitem()
|
|
sitem(tt(PLUS() - ! ~ PLUS()PLUS() --))(unary plus/minus, logical NOT, complement, {pre,post}{in,de}crement)
|
|
sitem(tt(**))(exponentiation)
|
|
sitem(tt(* / %))(multiplication, division, modulus (remainder))
|
|
sitem(tt(PLUS() -))(addition, subtraction)
|
|
sitem(tt(<< >>))(bitwise shift left, right)
|
|
sitem(tt(< > <= >=))(comparison)
|
|
sitem(tt(== !=))(equality and inequality)
|
|
sitem(tt(&))(bitwise AND)
|
|
sitem(tt(^))(bitwise XOR)
|
|
sitem(tt(|))(bitwise OR)
|
|
sitem(tt(&&))(logical AND)
|
|
sitem(tt(^^))(logical XOR)
|
|
sitem(tt(||))(logical OR)
|
|
sitem(tt(? :))(ternary operator)
|
|
sitem(tt(= PLUS()= -= *= /= %= &= ^= |= <<= >>= &&= ||= ^^= **=))(assignment)
|
|
sitem(tt(,))(comma operator)
|
|
endsitem()
|
|
|
|
Note the precedence of exponentiation in both cases is below
|
|
that of unary operators, hence `tt(-3**2)' evaluates as `tt(9)', not
|
|
tt(-9). Use parentheses where necessary: `tt(-(3**2))'. This is
|
|
for compatibility with other shells.
|
|
|
|
cindex(mathematical functions, use of)
|
|
cindex(functions, math, use of)
|
|
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 value of
|
|
this character and an expression of the form `tt(#)var(foo)' gives the
|
|
value of the first character of the contents of the parameter var(foo).
|
|
Character values are according to the character set used in the current
|
|
locale; for multibyte character handling the option tt(MULTIBYTE) must be
|
|
set. Note that this form is different from `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.
|