The ACE programming language uses several basic suits when performing mathematical calculations. First and foremost is the integer suit. ACE allows two integer sizes; INT signifies an integer that is 4 bytes long, while BIG INT signifies an integer that is 8 bytes long. We need the BIG INT to represent large numbers (i.e., any integer that is too large to be stored in the same space that a regular INT would be stored). The leftmost bit of an integer will signify the sign of the integer.
The ACE programming language will also use the REAL suit, which acts like the C++ double data type. A REAL is 8 bytes long; we may be wasting space by using 8 bytes instead of 4, but it allows for twice the number of bits for fractional parts of a number. The REAL is a floating point type, and lets us have more precise real number values. The first bit represents the sign, the next 11 bits represent the exponential value, and the final 52 bits are reserved for representation of fractional parts of a number.
Also, ACE will use the FRAC type, but we don't count this as a primitive data type, because a FRAC is actually made up of integers or big integers. The FRAC type is actually a symbolic type that allows us to represent real numbers in fractional form. For example, 2.5 would be written in FRAC form as follows: 5/2.
Logical laws of inference are used quite extensively in the math world. So it makes sense that the ACE programming language would have a suit to represent the truth value of a statement. We've created the BOOLEAN suit, which has two values: :) and :(. Think of these symbols as happy faces or frowning faces. A happy face, :), represents true. A frowning face, :(, represents false. This convention should add to the readability and writability of a program written in ACE. To increase readability, a space is required before and after these symbols. An sample statement would be:
if((a and b) = = :) )
This makes the happy face more noticeable. The boolean symbols will be left-colon orientated (having the colon to the left of the parentheses). There may be controversy on happy representing True, and sad representing False; but it is more of yes and no, to a mathematical question. A question is asked: if a and b are true is like asking if a and b are correct.
The ACE programming language has no use for characters. ACE is a mathematical language. Ideally, an ACE program will be used as a plug-in for another language. The other language would handle a problem or application concerning characters or strings, while the ACE program deals exclusively with numbers, algebra, logic, etc. So therefore, ACE has no character type.
Again, we saw little need for a character string type in the ACE programming language, so we didn't include one. We initially thought a string might be useful to represent polynomials, but finally decided that arrays would be better suited for the task. For a more detailed explanation, see the array section below.
Enumeration is generally used to enumerate, or number, a list of user defined values. It is often used with characters, (representing ideas like the days of the week) to assign a numerical value to a particular character. Since we don't have any characters or any plans to allow the assigning of numbers to a user defined value, we see no need for enumerated types.
Subranges are used extensively in mathematics; they are generally referred to as intervals. So we've created an INTERVAL and SUBTYPE suit. An INTERVAL type allows us to use a subrange of a primitive numerical type. For example, the following statement would create a range of integers from 1 to 100:
INTERVAL INT 1..100 x;
The following command would create a subrange of real numbers, separated by a specified amount. The variable would be referred to as x. In this example, we create an range of real numbers between 1 and 3, separated by .5:
INTERVAL REAL 1..3 x STEP .5;
This would give us the following numbers within that range: 1, 1.5, 2, 2.5, 3.
So the general form of the INTERVAL type is as follows: INTERVAL <suit> first..last x, where first and last are of type <suit> (with an optional step statement for when <suit> is REAL or INT: STEP <some increment>).
The SUBTYPE suit allows the user to define a subrange consisting of primitive numerical types. For example, suppose we wanted a suit for positive prime numbers less than 25. We would say:
SUBTYPE INT (1, 2, 3, 5, 7, 11, 13, 17, 19, 23) prime;
So the general form of the subtype suit is as follows:
SUBTYPE <suit> (list of elements of type <suit>) <name of subtype>
First, a word concerning the importance of arrays in the ACE programming language. We are going to use arrays to represent polynomials. Take, for example, a basic quadratic equation of the following form: (a2)x^2 + (a1)x + a0. We can represent this equation mathematically in the form of a finite sequence: (a0, a1, a2). This makes it really easy to represent polynomials in our language in the form of an array. The coefficients a0, a1, a2 can be any suit (INT, REAL, whatever). a0 is stored in the first cell in the array, a1 in the second, etc. The degree of the polynomial (or the number of the highest power) determines the size of the array. For instance, in a quadratic equation, the degree is 2. That means it has an x^2 term, an x term, and a constant term, for three terms total (or degree+1). If a polynomial is degree 50, the array has to have 50+1 cells. This means that the array would have indices from 0 to 50.
An array in the ACE programming language is referenced by an aggregate name, and each element within the array is referenced by constants. The syntax for an array reference in ACE is relatively standard, as illustrated abstractly by this assignment statement:
<suit> array_name[index] = some_element
The suit of the subscripts or index values in ACE will always be integer (or INT), with no exception. Real numbers don't make good indices. We will also make sure that subscript ranges are implicitly checked; this way we can avoid out of range errors. The suit of the array's elements can be any primitive type: REAL, INT, BIG INT, or BOOLEAN.
Our arrays are stack-dynamic. This means the subscript ranges are dynamically bound. We decided to do this because when we multiply polynomials, the result is usually a polynomial with a greater degree (therefore requiring a larger array to store it). For example: if we multiply x+3 and x-4, which are both of degree 1 (and therefore require an array of size 2 for each polynomial), we get x^2 -x -12. The resulting polynomial is of degree 2, which means we need a size three array. Since polynomials may be provided by the user at runtime, we don't know the degree or size of polynomials we are adding or multiplying. Therefore, we declare a dynamic array to store the result, so it can become as large as necessary.
Storage allocation is also dynamic, because we don't exactly know how large of an array we are going to need to store a particular polynomial. Once subscript ranges are bound and the storage allocated, they remain fixed for the lifetime of the array. This is fine for our purposes.
We will probably use up to three array subscripts. One dimensional arrays in ACE are going to be most useful in equating polynomials, but one dimensional arrays can be used for other purposes, like lists and such. Two dimensional arrays will be used for the evaluation of matrices (which is important in calculus and linear algebra), and graphing. Three dimensional arrays could be used to represent a three dimensional Cartesian coordinate plane. This lets us graphically represent equations and polynomials. To represent two and three dimensional array, we use the following forms:
<suit> array_name[x][y]
<suit> array_name[x][y][z]
where x, y, and z are integers.
The ACE programming language is designed to initialize all array elements to zero when storage is allocated. This becomes useful when dealing with polynomials. Take, for example, the polynomial x^6 +x^2 +3. This is represented in the array with a 3 in the first cell, a 1 in the third cell, and a 1 in the seventh cell. The rest of the values in the array have already been initialized to zero. So the array looks like this: [ 3, 0, 1, 0, 0, 0, 1].
Two major operations have to be defined for arrays. The first (and easiest) is addition. When we add polynomials in the ACE language, we combine like terms. So (x+3) + (x+4) = [3, 1] + [4, 1] = [7, 2] = 2x +7. In this case, we add the elements of two or more arrays that have the same subscripts. So in the above example, we had two size 2 arrays, let's call them A and B. So the resulting array C was determined as follows:
C[i] = A[i] + B[i] where i is some subscript.
Now, multiplication is a little more difficult. Because when we multiply two polynomials A and B, the degree of the resulting polynomial C is usually larger than either product. In fact, the rule for determining the resulting polynomial's degree is as follows:
degree(C) = degree(A) + degree(B) +1.
Take, for example, (x^2 + 4) * (x). The result is (x^3 +4x), which is of degree 3. A degree 3 polynomial requires an array of size 4. This is equivalent to the degree of (x^2 +4) (i.e. 2) plus the degree of (x) (i.e. 1) plus 1, or 2 + 1 + 1 = 4. This is where the dynamic nature of our arrays come into play.
Take A to be a degree two polynomial: (a2)x^2 +(a1)x +(a0), or [a0, a1, a2]
Take B to be a degree two polynomial: (b2)x^2 +(b1)x +(b0), or [b0, b1, b2]
Multiplication A * B is defined as follows:
[a0b0, a0b1 + a1b0, a0b2 + a1b1 + a2b0, a0(0) + a1b2 + a2b1 + (0)b0, a0(0) + a1(0) +a2b2 +(0)b1 + (0)b2] = [a0b0, a0b1 + a1b0, a0b2 + a1b1 +a2b0, a1b2 + a2b1, a2b2]
In the above rule, (0) means the number zero; all other numbers are part of the coefficient labels.
Multiplication for other polynomials follow this same pattern. The pattern may be difficult to discern, but basically what's going on is that we are taking the first elements of A and B to figure out the first element of C, the first two elements of A and B to figure out the second element of C, the first three elements of A and B to figure out the third element of C, and so on.
To use our example above for (x^2 + 4)...or [4, 0, 1]...and (x)...or [0, 1].
[4, 0, 1] * [0, 1] = [4*0, 4*1 + 0*0, 4*0 + 0*1 + 1*0, 4*0 + 0*0 + 1*1 +0*0] =
[0, 4, 0, 1] = x^3 + 4x (see, it works!)
Division can be performed by figuring out the reciprocal of a polynomial and then multiplying. Similarly, we can do subtraction by adding the negative of a polynomial.
We want to design arrays so that accesses are done in the following manner:
The address of array[k] = the address of array[0] + ((k-1)*(the size of the element in the array))
We are using row major order, because of our vast use of polynomials and matrices. Our two dimensional arrays will be made up of an array of arrays; forming a table of values. Three dimensional arrays will follow the same format; being an array of two dimensional arrays.
The ACE programming language will not support record types. We couldn't think of any mathematical application that would require the use of a record-like structure.
A union type can store different type values at different times during execution. Unlike the UNDEF suit which will be defined once, union types can change. Once the UNDEF is defined, the definition remains. In calculation of expressions, ACE will consist of union types. Using ACE, the programmer has the advantage to make a program which can take various numeric inputs. If a real and an integer are multiplied together, a real will be given as an answer. Union types will be an internal feature of the language, only used by the compiler, in evaluation of mixed node expressions.
At compile time, union types will be implemented by the compiler itself.
In the example above, the card that the multiplication is to be stored
in would be made a real. Another example would be a card's suit
that depended on the calculation of the card. The card could possibly
have an integer suit or a fraction suit. This will only be known
at time of calculation.
The ACE programming language supports unordered sets of primitive numerical types. Sets in our language are handled by our SUBTYPE suit. We will have operations defined to deal with sets/subtypes, including intersect(), + (i.e. union), - (i.e. difference), member().
3.7.2 Implementation of set types
See our reference to SUBTYPE above.
The ACE programming language will not use pointers. We do not allow for the aliasing of cards, and we have no need for complex structures like linked lists, which are dynamic and by nature require pointers.