mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 18:10:56 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			189 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
	
		
			8.4 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 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(foo) 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.
 | |
| 
 | |
| 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.
 | |
| 
 | |
| 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.
 | |
| 
 | |
| 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(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 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.
 |