Math
The math library adds methods directly to numeric types -- int, long, double, and complex. You call math operations on the values themselves rather than passing them to some static function.
Method-Based Design
Instead of the traditional static function call, I went with methods on values:
// Traditional style (also supported)
public int x;
formula a_x = Math.abs(x);
// Method style (preferred)
formula b_x = x.abs();
The method style is more concise and chains better. Both work, but I prefer the method form.
Maybe Type Support
A lot of math functions also work on maybe<T> types. This matters because some operations -- division being the obvious one -- can produce undefined results. Operating on maybe types lets you chain computations without constantly checking for errors:
maybe<double> result = 10 / 0; // Empty (division by zero)
maybe<double> valid = 10 / 2; // Contains 5.0
Type: int
Methods on 32-bit integer values.
abs()
Returns the absolute value.
int x = -42;
int absX = x.abs(); // 42
int y = 17;
int absY = y.abs(); // 17
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: int - The absolute value
Type: long
Methods on 64-bit integer values.
abs()
Returns the absolute value.
long x = -9223372036854775807L;
long absX = x.abs(); // 9223372036854775807L
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: long - The absolute value
Type: double and maybe
Methods on 64-bit floating point values.
abs()
Returns the absolute value.
double x = -3.14159;
double absX = x.abs(); // 3.14159
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: double - The absolute value
sqrt()
Returns the square root. Since the square root of a negative number is complex, this returns a complex type -- which I think is the right call rather than silently returning NaN.
double x = 16.0;
complex sqrtX = x.sqrt(); // @c(4.0, 0.0)
double negative = -4.0;
complex sqrtNeg = negative.sqrt(); // @c(0.0, 2.0)
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: complex - The square root (real or complex)
ceil()
Rounds up to the smallest integer greater than or equal to the number.
double x = 3.2;
double ceilX = x.ceil(); // 4.0
double y = -3.7;
double ceilY = y.ceil(); // -3.0
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: double - The ceiling value
With precision:
double x = 3.14159;
double ceilX = x.ceil(0.1); // 3.2
| Parameter | Type | Description |
|---|---|---|
| precision | double |
The precision to round to |
Returns: double - The ceiling value at the given precision
floor()
Rounds down to the largest integer less than or equal to the number.
double x = 3.7;
double floorX = x.floor(); // 3.0
double y = -3.2;
double floorY = y.floor(); // -4.0
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: double - The floor value
With precision:
double x = 3.14159;
double floorX = x.floor(0.1); // 3.1
| Parameter | Type | Description |
|---|---|---|
| precision | double |
The precision to round to |
Returns: double - The floor value at the given precision
round()
Rounds to the nearest integer.
double x = 3.4;
double roundX = x.round(); // 3.0
double y = 3.6;
double roundY = y.round(); // 4.0
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: double - The rounded value
With precision:
double x = 3.14159;
double roundX = x.round(0.01); // 3.14
| Parameter | Type | Description |
|---|---|---|
| precision | double |
The precision to round to |
Returns: double - The rounded value at the given precision
roundTo(digits)
Rounds to a specific number of decimal places. Slightly different flavor than round(precision) -- you specify the digit count instead of the precision value.
double pi = 3.14159265359;
double pi2 = pi.roundTo(2); // 3.14
double pi4 = pi.roundTo(4); // 3.1416
| Parameter | Type | Description |
|---|---|---|
| digits | int |
Number of decimal places |
Returns: double - The rounded value
Trigonometric Functions
These live on the Math class as static functions.
Math.sin(x)
Returns the sine of a value in radians.
maybe<double> result = Math.sin(3.14159 / 2); // ~1.0
| Parameter | Type | Description |
|---|---|---|
| x | double |
The angle in radians |
Returns: double - The sine of the angle
Math.cos(x)
Returns the cosine of a value in radians.
double result = Math.cos(0.0); // 1.0
| Parameter | Type | Description |
|---|---|---|
| x | double |
The angle in radians |
Returns: double - The cosine of the angle
Math.tan(x)
Returns the tangent of a value in radians.
maybe<double> result = Math.tan(3.14159 / 4); // ~1.0
| Parameter | Type | Description |
|---|---|---|
| x | double |
The angle in radians |
Returns: double - The tangent of the angle
Math.PI()
Returns pi. You know, 3.14159...
double pi = Math.PI(); // 3.141592653589793
Returns: double - The value of Pi
Math.sign(x)
Returns the sign of a number: -1, 0, or 1.
int s1 = Math.sign(42); // 1
int s2 = Math.sign(-42); // -1
int s3 = Math.sign(0); // 0
double s4 = Math.sign(3.14); // 1.0
| Parameter | Type | Description |
|---|---|---|
| x | int, long, double, or maybe variants |
The value to check |
Returns: Same type as input - The sign of the value
Math.min(a, b)
Returns the smaller of two values.
int smaller = Math.min(10, 20); // 10
double smaller2 = Math.min(3.14, 2.71); // 2.71
| Parameter | Type | Description |
|---|---|---|
| a | int, long, or double |
First value |
| b | int, long, or double |
Second value |
Returns: Same type as input - The smaller value
Math.intOf(x)
Converts a double to an integer, truncating toward zero.
maybe<int> i = Math.intOf(3.7); // 3
| Parameter | Type | Description |
|---|---|---|
| x | double |
The value to convert |
Returns: maybe<int> - The integer value
Math.gcd(a, b)
Returns the greatest common divisor of two integers.
int gcd1 = Math.gcd(20, 50); // 10
int gcd2 = Math.gcd(10, 13); // 1
| Parameter | Type | Description |
|---|---|---|
| a | int |
First integer |
| b | int |
Second integer |
Returns: int - The greatest common divisor
Type: complex and maybe
Methods on complex number values. I added complex numbers because square roots of negative numbers shouldn't be an error -- they should just be complex.
conj()
Returns the complex conjugate
. The conjugate of a + bi is a - bi.
complex z = 3.0 + 4.0 * @i; // 3 + 4i
complex conjZ = z.conj(); // 3 - 4i
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: complex - The complex conjugate
length()
Returns the magnitude of the complex number -- sqrt(a^2 + b^2) per the Pythagorean theorem.
complex z = 3.0 + 4.0 * @i;
double len = z.length(); // 5.0 (3-4-5 triangle)
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: double - The magnitude of the complex number
re()
Returns the real part.
complex z = 3.0 + 4.0 * @i; // 3 + 4i
double real = z.re(); // 3.0
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: double - The real component
im()
Returns the imaginary part.
complex z = 3.0 + 4.0 * @i; // 3 + 4i
double imag = z.im(); // 4.0
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: double - The imaginary component
Random Number Generation
Adama has built-in random number generation through the Random class. The random state is part of the document state, so it's deterministic during replay.
Random.genBoundInt(max)
Generates a random integer in the range [0, max).
int roll = Random.genBoundInt(6); // 0 to 5
| Parameter | Type | Description |
|---|---|---|
| max | int |
The exclusive upper bound |
Returns: int - A random integer in [0, max)
Random.genInt()
Generates a random 32-bit integer. Useful for shuffling.
int randomValue = Random.genInt();
Returns: int - A random integer
Here's a common pattern -- shuffling a table by assigning random ordering values:
record Card {
public int id;
public int ordering;
}
table<Card> deck;
procedure shuffle() {
(iterate deck).ordering = Random.genInt();
}
Method Summary Tables
Integer Types
| Type | Method | Description | Returns |
|---|---|---|---|
int |
abs() |
Absolute value | int |
long |
abs() |
Absolute value | long |
Floating Point
| Type | Method | Description | Returns |
|---|---|---|---|
double |
abs() |
Absolute value | double |
double |
sqrt() |
Square root | complex |
double |
ceil() |
Ceiling | double |
double |
ceil(precision) |
Ceiling at precision | double |
double |
floor() |
Floor | double |
double |
floor(precision) |
Floor at precision | double |
double |
round() |
Round to nearest integer | double |
double |
round(precision) |
Round at precision | double |
double |
roundTo(digits) |
Round to decimal places | double |
Complex Numbers
| Type | Method | Description | Returns |
|---|---|---|---|
complex |
conj() |
Complex conjugate | complex |
complex |
length() |
Magnitude | double |
complex |
re() |
Real part | double |
complex |
im() |
Imaginary part | double |
Trigonometric and Utility Functions
| Function | Description | Returns |
|---|---|---|
Math.sin(x) |
Sine of angle (radians) | double |
Math.cos(x) |
Cosine of angle (radians) | double |
Math.tan(x) |
Tangent of angle (radians) | double |
Math.PI() |
Mathematical constant Pi | double |
Math.sign(x) |
Sign of number (-1, 0, 1) | same as input |
Math.min(a, b) |
Smaller of two values | same as input |
Math.intOf(x) |
Convert double to int | maybe<int> |
Math.gcd(a, b) |
Greatest common divisor | int |
Random Generation
| Function | Description | Returns |
|---|---|---|
Random.genBoundInt(max) |
Generate random int in [0, max) | int |
Random.genInt() |
Generate random integer | int |
Division Safety
It is worth noting that division in Adama always returns maybe<T>. This handles division by zero at the type level rather than crashing at runtime:
procedure foo() {
int a = 10;
int b = 0;
maybe<double> result = a / b; // Empty (division by zero)
if (result as value) {
// Safe to use value here
}
}
This applies to both integer and floating-point division.