Primitive types

AUSTRA arithmetic is basically the same as on most programming languages. The language supports:

  • 32 bits integers, represented by the int type.

  • 64 bits integers, represented by the long type.

  • 64 bits double-precision reals, represented by the double type.

  • 2x64 bits double-precision complex values, represented by the complex type.

Smaller arithmetic types are automatically converted to bigger types when required: int to double, double to complex, and even int to complex. Double and long integer values can be converted into integer values using the toInt property, as in pi.toInt.

Operators

These are the operators available for integers and reals:

+

Addition. Can also be used as a unary operator.

-

Subtraction. Can also be used as a unary operator for negation.

*

Multiplication.

/

Both real and integer division.

%

Both integer and real remainders.

^

Power: 2^3 = 8, 9^0.5 = 3.

Most of them may also be used with complex numbers.

Though the power operator works both for integer, real and complex numbers, the compiler optimizes the special cases when the power is 2, 3 and 4, so equalities like this exactly holds:

Austra
i^2 = -1

The multiplication operator can be elided when the first operand is a real or an integer and it is immediately followed by an identifier:

Austra
2pi = 2 * pi
2x^2 + 3x + 1 = 2*x^2 + 3*x + 1
1/2x = 1 / (2*x)

AUSTRA also recognizes a superscript 2 (²) as an operator to square a value:

Austra
2x² + 3x + 1 = 2*x^2 + 3*x + 1

The AUSTRA code editor simplifies typing this operator with the keys combination (Ctrl+G, 2).

Comparisons

These operators are used for comparing all compatible operands:

=

Equality.

!=

Inequality.

<>

A synonym for the inequality operator.

<

Less than.

<=

Less than or equal to.

>

Greater than.

>=

Greater than or equal to.

<-

Belongs to. Right side must be a vector or a sequence.

A fancy synonym for the membership operator (<-).

The membership operator can be used with sequences, vectors, matrices, and series:

Austra
34 <- [1..100];
0 <- vec::random(1024)

When the right side of the membership operator is a time series, the left operand may be either a real or a date:

Austra
0.0 <- appl.rets;
1@jan2020 <- appl

Comparisons can be fused for numeric operands using the following syntax:

Austra
sqrt(pi) <= pi <= pi²

Fused ranges only require combining same-direction comparisons. For instance, <= and < are compatible, but < and > are not.

Complex properties and operators

When you have a complex value in your hands, you can drill into it using a dot and a property name, to extract information about the poor little value:

real

The real part of the complex.

imaginary

The imaginary part of the complex.

magnitude

A magnitude, i.e., the distance to complex(0, 0).

phase

The phase, in radians.

Austra
let c = complex(3, 4) in
        c = c.real + c.imaginary * i

If typing magnitude is too hard for your nerves, you can use mag as an accepted synonym. real can be shortened to re, and imag and even im can be used instead of imaginary. Since my heart is cold and empty for phase, on the other hand, there is no diminutive for that fellow.

In addition to the usual operators, there's a sufix operator for conjugating a complex value:

'

Unary suffix operator for complex conjugation.

The ' operator is also used for conjugating complex vectors and transposing a matrix.

Integer properties

Integer values support the even and odd properties for easy testing of parity:

Austra
iff(e.toInt.even, "Truncated to 2", "Rounded to 3")

The math class

The math class groups methods and properties dealing with arithmetic operations. Most of these features come straight from the C#'s Math and Complex, but it also incorporate other functions that are used in statistics and probabilities.

Our math is special in that the class prefix is assumed when not present in a function or property call:

Austra
-- Write like this, if you are a sucker for pain.
math::
sin(math::pi/4) = math::sqrt(2)/2; -- Standard people use this style. sin(pi/4) = sqrt(2)/2

Why, for the love of Mike, have we sunken all those definition inside the math class? It is easy to explain with two points: we did not want to pollute the global name space with lots and lots of symbols, in the first place. Some mathematically-oriented language do just this: everything is a global function, so, at some point, you must come with very clever but cryptic names for your own stuff. Nonetheless, we can omit the class name for the most used names. The second point is related: somebody can shadow one of these global names, such i or max. In those cases, you still have the long and winding road of prefixing the shadowed name with its class name, and nothing is lost.

These are the methods or functions provided by this class. Most of them work both with integer, real and complex parameters:

abs

Absolute value

acos

The angle whose cosine is the specified parameter.

asin

The angle whose sine is the specified parameter.

atan(x), atan(x, y)

The angle whose tangent is the specified parameter.

The version with two parameters is equivalent to Atan2.

beta(x, y)

Biparametric Euler integral of the first kind.

cbrt

Cubic root.

complex

Creates a complex number from one or two real values.

cos

The cosine function.

cosh

The hyperbolic cosine function.

erf

The error function.

exp

The exponential function.

gamma

The gamma function: an extension of factorials for real numbers.

lnGamma

The natural logarithm of the gamma function.

log

The natural logarithm function.

log10

Base 10 logarithms.

max

The maximum of its two parameters. It also works with dates.

min

The minimum of its two parameters. It also works with dates.

ncdf

Normal cumulative distribution function.

polar

Creates a complex from its circular coordinates.

probit

The inverse of the cumulative of the standard normal distribution.

round(d)

Rounds a real to the nearest integer.

round(d, i)

Rounds a real to a number of decimals.

sign

Returns the sign of the argument.

sin

The sine function.

sinh

The hyperbolic sine function.

sqrt

The square root.

tan

The tangent function.

tanh

The hyperbolic tangent function.

trunc

Truncates a real value.

These are the properties (parameterless functions) and constants provided by math:

e

Euler's constant.

i

The imaginary unit.

maxInt

The maximum value that is representable in an integer.

maxReal

The maximum value that is representable in a real.

minInt

The minimum value that is representable in an integer.

minReal

The minimum value that is representable in a real.

nrandom

A random number from the standard normal distribution.

pearl

An Easter Egg. Just try me!

pi, π

Don't be irrational: be trascendent.

random

A random number from a uniform distribution between 0 and 1.

tau, τ

Twice π.

today

The current date.

Polynomials and solvers

These methods are also defined inside the math class, so they can be used without explicitly writing the class prefix:

solve

A simple Newton-Raphson solver. See below for details.

polyEval

Evaluates a polynomial given a real or complex argument.

polyDerivative

Evaluates the first derivative of a polynomial at a real or complex argument.

polySolve

Calculates all the roots of a polynomial.

The Newton-Raphson solver is a function accepting from three up to five arguments:

Austra
solve(x => sin(x) - 1, x => cos(x), 0, 1e-9, 100)

The first two arguments are lambda functions: one for the function we want to solve for a root, and the second for the first derivative of that function. Please note that solve does not verify that the lambda function and its derivative lambda match. The third argument is required, and represents the initial guess to start running the algorithm. Again, a bad guess may make the algorithm fail.

The fourth and fifth arguments can be omitted. The fourth parameter is the desired accuracy, and when omitted, it defaults to 1e-9. The last parameter is the maximum numbers of iterations, which by default is 100.

The polyEval function takes either a complex or a real as its first argument, and a list of coefficients, either in a single vector or as a list of real values, and evaluates the polynomial at the supplied value:

Austra
let x1 = complex(-1, sqrt(2)), x2 = x1';
-- 1, 2, 3 represents the polynomial x² + 2x + 3
polyEval(x1, 1, 2, 3);
-- Coefficients can be grouped in a vector.
polyEval(x2, [1, 2, 3]);

The inverse of polyEval is the polySolve function. It takes either a vector or a list of reals and considers them as the coefficients of a polynomial. The first value is the coefficient of the highest degree term. For instance, the vector [1, 2, 3, 4] stands for the polynomial x^3 + 2*x^2 + 3*x + 4. This function can throw an exception if it does not know how to handle a given polynomial, or when there are no available roots. The returned value is always a complex vector, even when all roots are real-valued. For instance:

Austra
polySolve(1, 2, 3)

You can check the accuracy of the answers from the solver using this trick:

Austra
let poly = [1, 2, 3] in
  polySolve(poly).all(c => abs(polyEval(c, poly)) <= 1e-15)

Of course, the accuracy of the roots may vary according to the polynomial.

A close relative of polyEval is polyDerivative, which calculates the derivative of a given polynomial at the specified argument:

Austra
let v = [1, 2, 3, 4];
polyEval(2, v) = 26;
polyDerivative(2, v) = 23

polyDerivative can be useful when finding a real root for a polynomial using the Newton-Raphson algorithm.

Dates

Dates in Austra are represented by the date type and stores the number of days since Jan 1st, 1900. Dates support these properties:

day

Gets the day of month, starting by 1.

dow

Gets the day of the week.

isLeap

Is the year from the date a leap one?

month

Gets the month of the date, starting with 1.

toInt

Converts the date to a signed integer.

year

Gets the year of the date.

These two methods allow adding either a positive or a negative number of months or years to a date:

addMonths

Adds a positive or negative number of months to a date.

addYears

Adds a positive or negative number of years to a date.

Adding or subtracting days from a date is achieved with these operators:

+

Adds a number of days to a date. The left operand must be a date.

-

Subtracts a number of days from a date. The left operand must be a date. It can also be used to find the difference in days between two dates.

Logical values

Logical values are represented by the bool data type. Variables and parameters from this type hold one of these two constants: either false or true.

Operators acting on logical values resembles more the good-old Pascal operators than the C/C++/C# one. It's a matter of personal preference, of course, but also of readability:

not

Logical negation.

and

Logical conjunction.

or

Logical disjunction.

The precedence of these operators is the standard one. Negation binds first, then conjunction, and finally disjunction.

Conditional expressions

Since AUSTRA is a functional language, it doesn't have "statements". However, it provides an if/then/else ternary operator, equivalent to the also included iff() function:

Austra
if aapl.mean < msft.mean then aapl.mean else msft.mean

Of course, the above expression is just a pedantic way to write min(aapl.mean, msft.mean). It can be also be expressed using iff() this way:

Austra
iff(aapl.mean < msft.mean, aapl.mean, msft.mean)

Most of the times, the more verbose ternary operator is easier to read. The ternary operator has another advantage: you can chain several conditions and responses using the elif keyword.

Austra
let x = random;
if x < 0.1 then "Too low!"
elif x < 0.5 then "A little low"
elif x < 0.9 then "A little high"
else "Too high!"

See Also