mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-11-04 07:21:06 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			263 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
	
		
			12 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($LPAR()LPAR())var(...)tt(RPAR()RPAR()).  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 and a leading
 | 
						|
`tt(0b)' or `tt(0B)' binary.
 | 
						|
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 are output 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(name)' gives the
 | 
						|
value of the first character of the contents of the parameter var(name).
 | 
						|
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(name)', a standard
 | 
						|
parameter substitution which gives the length of the parameter var(name).
 | 
						|
`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 towards zero.
 | 
						|
 | 
						|
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(>>)' and their equivalents with
 | 
						|
assignment) is given a floating point argument, it will be silently rounded
 | 
						|
towards zero except for `tt(~)' which rounds down.
 | 
						|
 | 
						|
Users should beware that, in common with many other programming
 | 
						|
languages but not software designed for calculation, the evaluation of
 | 
						|
an expression in zsh is taken a term at a time and promotion of integers
 | 
						|
to floating point does not occur in terms only containing integers.  A
 | 
						|
typical result of this is that a division such as tt(6/8) is truncated,
 | 
						|
in this being rounded towards 0.  The tt(FORCE_FLOAT) shell option can
 | 
						|
be used in scripts or functions where floating point evaluation is
 | 
						|
required throughout.
 | 
						|
 | 
						|
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.
 |