boolean, byte, short, integer, float, and double types should be familiar to most programmers as Boolean, unsigned char (integer in the range 0 to 255), short integer, integer, single-precision floating-point, and double-precision floating-point types.
complex and dcomplex types correspond to single-precision floating-point complex and double-precision floating-point complex numbers. These types are represented in Glish as a pair of floating-point numbers. One number is designated as the real portion and the other is designated as the imaginary portion of the complex number. In the case of complex, each of the numbers are single-precision, and in the case of dcomplex, each of the numbers are double-precision. There are two functions for accessing the components of these numbers. real returns the real portion of a complex value, and imag returns the imaginary portion of a complex value. These functions work on vectors of complex or dcomplex numbers. The length of the resultant vector is equal to the length of the vector argument.
These types are referred to collectively as numeric. Numeric
types can be used in arithmetic and logical
operations (see § 3.2.3-§ 3.2.4
below) as well as in comparisons (§ 3.2.5, page ). The maximum and
minimum values for numeric types can be found by looking at
There are two boolean constants: T and F. They represent the values of ``true" and ``false", respectively.
integer constants are just strings of digits, optionally preceded by a + or - sign: 1234, -42, and +5 for example.
You write floating-point constants in the usual ways, a string of digits with perhaps a decimal point and perhaps a scale-factor written in scientific notation. Optional + or - signs may be given before the digits or before the scientific notation exponent. Examples are -1234., 3.14159, and .003e-23. All floating-point constants are of type double.
dcomplex constants are written as a floating-point number followed by a + or - sign (this part is optional), followed by a second floating-point number which must be immediately, i.e. no whitespace, followed by an i. All complex constants are of type dcomplex. All of the following are valid:
23.12-7.2i 2.31+.003e-23i 2.3i 34 + 2iWhen no extra white space exists within the complex constant, the number is translated directly to a complex constant, otherwise an addition (of two complex numbers) is performed. So in 34 + 2i, 34 is converted to a dcomplex value, and this value is added to 2i. If the i does not immediately follow the imaginary portion, as in 4 - 3 i, a runtime error results. Omitting the imaginary floating point number results in a reference to the variable i, if it happens to exist.
You can freely intermix numeric types in expressions. When intermixed, values are promoted to the ``highest" type in the expression.
In general, this promotion follows a simple hierarchy:
(highest) dcomplex complex (*) double (*) float integer short byte boolean (lowest)where types are promoted upward (e.g., mixing a byte value and a float value will promote to float, since float appears higher in the list). The sole exception to this linear hierarchy is when mixing double values with complex values; these are always promoted to dcomplex, to preserve the precision of the double value. So if we had,
a := [T, F, T] a := 3.0 a := as_complex(-2+1i) b := [1, 2, 3] b := 4-3ia's type is initially boolean, becomes double with the first assignment, and finally becomes dcomplex after the last assignment to a. a ends up as a dcomplex despite the fact that a complex is assigned to it because a's type was double at the time of the assignment. b starts out as integer, but after the assignment, ends up dcomplex because complex constants are of type dcomplex.
When converting boolean
values to other numeric values,
``true" is promoted to 1 and false to 0. Thus
5 + T yields the integer value 6 and
3.2 * 4 yields the double value 12.8. The type
conversion functions can be used to prevent type promotion. For example,
as_integer(3.2) * 4yields the integer value 12. See § 9.2, page , for specifics on how each as_X function works. floor and ceiling can also be used to convert floating point values to integers (see § 9.2.2, page ).
For doing arithmetic, Glish supports
The first four have their usual meaning.
They evaluate their operands after converting them
to the higher type of the two and return a result of that type. Division
converts the operands to double and yields a double value, unless
a complex or dcomplex value is involved. If a complex value is one
of the division operands, the result is a dcomplex value.
can also be used as unary operators. For example,
% computes a modulus, defined in the same way as in the C language. It evaluates its operands as integer and returns an integer result.
^ does exponentiation. It evaluates its
operands as double values or dcomplex values if a complex
number is involved and returns a double or dcomplex value
of the same type as the evaluated operands. Thus
3^5returns the double value 243.0, but
2+3i ^ 2returns the dcomplex value -5+12i.
As discussed above in § 3.1.4, page , the arithmetic operators all operate element-by-element when given two equal-sized vectors. For example,
a := [1, 3, 5] b := a * 2:4assigns to b
[2, 9, 20]If one of the vectors is a scalar then the scalar is paired with each element in turn:
1:5 ^ 2yields the double vector
[1.0, 4.0, 9.0, 16.0, 25.0]Operations on vectors of different sizes, such as
1:5 ^ [2, 3]result in run-time errors.
Binary + and -
have the lowest precedence, *, /, and % have equal
and next highest precedence, and
^ has highest precedence of
the binary operators. The precedence of
^ is just below that
of the : operator discussed in § 3.1.4, page . The unary
+ and - operators have precedence just above :.
See § 4.13, page , for a table of the precedence of all Glish
All arithmetic operators associate from left-to-right except for
which associates from right-to-left.
Finally, a number of arithmetic functions are also available, most of which operate element-by-element on their operands. See § 9.3, page , for descriptions.
Glish supports three logical operators:
and ! ,
are Boolean ``and", ``or", and ``not", respectively.
| operators require
boolean operands, and other numeric types are not
automatically converted to boolean in this case. As with the arithmetic
operators, these operate on multi-element vectors element by element.
[T, F, F, T] & [F, F, T, T]yields
[F, F, F, T]while
[T, F, F, T] | Tyields
[T, T, T, T]See § 4.5, page , for a discussion of the related && and
The unary ! operator negates its operand. It first converts any numeric operand to boolean by treating a value of 0 (zero) as false and any other value as true. For example,
! [T, F, F, T]yields
[F, T, T, F]and
! 5e-238yields true.
The logical operators are left-associative.
| operator has
precedence just below &, which in turn is just below that of
the comparison operators (see § 3.2.5, page ). The !
operator has very high precedence, the same as unary + and -;
see § 3.2.3 and § 4.13.
§ 9.3, page , discusses the predefined functions for operating on logical values.
Glish provides the usual comparison operators:
They each take two operands, which
they convert to the higher of the two types (see § 3.2.2, page ).
They return a boolean vector corresponding to the element-by-element
comparison of the operands.
3 < 3.000001yields true, and
1:4 == [3,2,3,2]yields
[F, T, T, F]The boolean value ``true" is considered greater than ``false". For example,
F < Tyields true.
Comparisons are also defined for complex and dcomplex numbers. The result of a comparison operator applied to complex numbers is the result of the comparison applied to the real portion of those numbers. If however the real components of the complex numbers are equal, the result of the comparison is the comparison operator applied to the imaginary portion of the numbers. So the result of,
3-2i < 4+7iis true because, comparing the real components, 3 is less than 4. However,
3+2i < 3-1iis false because, now comparing the imaginary components since the real components are equal, 2 is not less than -1.
You can also use the
!= operators to compare non-numeric
values. See § 4.4, page for details.
The comparison operators are all non-associative and have equal precedence, just below that of binary + and - (see § 3.2.3, page ) and just above that of the logical & operator (see § 3.2.4, page ). See § 4.13, page , for a general discussion of precedence.
You can use numeric values to index vectors in two different ways. boolean values serve as masks for picking out vector elements where some condition is true, and non-boolean values (converted to integer) serve as indices for specifying a particular set of elements in a vector. See § 3.6, page , for a discussion of these different ways of indexing.