# Maths functions

Tip

`Fixed64` is the default variable data type used by the `etch` mathematics and machine learning libraries.

In the current version, and further to the common mathematical operations provided by the `etch` language already discussed here, the following functions are available.

## Absolute value

`abs()` returns the absolute value of all signed integer types.

``````function main()

// 8 bit signed integers
var int_8_bit = 1i8;
printLn(toString(abs(int_8_bit)));

var neg_int_8_bit = -1i8;
printLn(toString(abs(neg_int_8_bit)));

// 16 bit signed integers
var int_16_bit = 1i16;
printLn(toString(abs(int_8_bit)));

var neg_int_16_bit = -1i16;
printLn(toString(abs(neg_int_16_bit)));

// 32 bit signed integers
var int_32_bit = 1;
printLn(toString(abs(int_32_bit)));

var neg_int_32_bit = -1;
printLn(toString(abs(neg_int_32_bit)));

// 64 bit signed integers
var int_64_bit = 1i64;
printLn(toString(abs(int_64_bit)));

var neg_int_64_bit = -1i64;
printLn(toString(abs(neg_int_64_bit)));

endfunction
``````

And positive unsigned integer types.

``````function main()

// 8 bit unsigned integers
var int_8_bit = 1u8;
printLn(toString(abs(int_8_bit)));

// 16 bit unsigned integers
var int_16_bit = 1u16;
printLn(toString(abs(int_8_bit)));

// 32 bit unsigned integers
var int_32_bit = 1u32;
printLn(toString(abs(int_32_bit)));

// 64 bit unsigned integers
var int_64_bit = 1u64;
printLn(toString(abs(int_64_bit)));

endfunction
``````

And fixed point types.

``````function main()

// 32 bit fixed point
var fixed_32 = 1.0fp32;
printLn(toString(abs(fixed_32)));

var neg_fixed_32 = -1.0fp32;
printLn(toString(abs(neg_fixed_32)));

// 64 bit fixed point
var fixed_64 = 1.0fp64;
printLn(toString(abs(fixed_64)));

var neg_fixed_64 = -1.0fp64;
printLn(toString(abs(neg_fixed_64)));

// 128 bit fixed point
var fixed_128 = 1.0fp128;
printLn(toString(abs(fixed_128)));

var neg_fixed_128 = -1.0fp128;
printLn(toString(abs(neg_fixed_128)));
endfunction
``````

## Exponential function

The exponential function returns the value of `e` to the number given, `exp(x) = ex` where `e` is Euler's base of natural logarithms.

The exponential function is limited to fixed point variables.

``````function main()

var a = 2.0fp32;
var b = 3.0fp64;
var c = 4.0fp128;
printLn(toString(exp(a)));
printLn(toString(exp(b)));
printLn(toString(exp(c)));

endfunction
``````

### Range restrictions

`Fixed32` accuracy is limited within the range `[-10.3974, 10.3974]`.

`Fixed64` accuracy is limited within the range `[-21.48756260, 21.48756260]`.

`Fixed128` accuracy is limited within the range `[-43.6682723752765511, 43.6682723752765511]`.

Running the exponential function on numbers outside of this range produces unexpected results.

Warning

If the implementation of a function depends on `exp()` then accuracy is limited within a range dependent on the implementation.

Warning

For Fixed point types, take extra care because, even though the type has a reduced range, it has an increased accuracy within that range.

### Special cases

Scenario Result
`x` is `NaN` `e^x = NaN`
`x < MIN_EXP` `e^x = 0`
`x > MAX_EXP` `overflow_error exception`
`x == 1` `e^x = e`
`x == 0` `e^x = 1`
`x == -inf` `e^(-inf) = 0`
`x == +inf` `e^(+inf) = +inf`
`x < 0` `e^x = 1/e^(-x)`

### Errors for x ∈ (-10, 5)

• `Fixed32`: average: `0.000178116`, max: `0.00584819`
• `Fixed64`: average: `4.97318e-09`, max: `1.66689e-07`

## Power

The power function returns the value of the first parameter raised to the second.

The power function is limited to fixed point variables.

``````function main()

var a = 2.0fp64;
var b = 3.0fp64;
printLn(toString(pow(a, b)));

var c = 4.0fp32;
var d = 5.0fp32;
printLn(toString(pow(c, d)));

var e = 2.0fp128;
var f = 3.0fp128;
printLn(toString(pow(e, f)));

endfunction
``````

Warn

The `pow()` implementation depends on `exp()` so the range is limited. The implementation is as follows:

```````x^y = exp(y * log(x));`
``````

### Special cases

Scenario Result
`x` or `y` is `NaN` `pow(x, y) = NaN`
`x == 0`, `y == 0` `pow(x, y) = NaN`
`x == 0`, `y != 0` `pow(x, y) = 0`
`x any`, `y == 0` `pow(x, y) = 1`
`x < 0`, `y non int` `pow(x, y) = NaN`
`x +/-inf` `pow(x, y) =`
`x < 0`, `y int` `pow(x, y) = \prod_1^y x`

### Errors for x ∈ (0, 100), y ∈ (0, 10.5)

• `Fixed32`: average: `1.49365e-06`, max: `3.04673e-05`
• `Fixed64`: average: `8.45537e-12`, max: `8.70098e-10`

### Errors for x ∈ (-10, 10), y ∈ (-4, 4)

• `Fixed32`: average: `3.9093e-06`, max: `9.15527e-06`
• `Fixed64`: average: `7.71863e-11`, max: `2.25216e-10`

## Random (non deterministic)

You can currently generate non-deterministic, random, signed and unsigned integers (not 8 bit types), and floats.

The beginning value of the range must be less than the end value.

``````function main()

//var randUInt8 = rand(0u8, 1000u8); // error: unable to find matching function for 'Rand'
//printLn(toString(randUInt8));

// unpermitted range
// var rand_test = rand(100u16, 0u16); // runtime error: Invalid argument: rand(a, b) must satisfy a < b

var randUInt16 = rand(0u16, 1000u16);
printLn(toString(randUInt16));

var randUInt32 = rand(0u32, 1000u32);
printLn(toString(randUInt32));

var randUInt64 = rand(0u64, 1000u64);
printLn(toString(randUInt64));

// var randInt8 = rand(0u8, 1000u8);
// printLn(toString(randInt8));

var randInt16 = rand(0i16, 1000i16);
printLn(toString(randInt16));

var randInt32 = rand(0i32, 1000i32);
printLn(toString(randInt32));

var randInt64 = rand(0i64, 1000i64);
printLn(toString(randInt64));

var randFixed32 = rand(0.0fp32, 1000.0fp32);
printLn(toString(randFixed32));

var randFixed64 = rand(0.0fp64, 1000.0fp64);
printLn(toString(randFixed64));

endfunction
``````

## Square root

The square root of a number is found with the `sqrt()` function.

The square root function is limited to fixed point variables.

``````function main()

var a = 4.0fp32;
var b = 49.0fp64;
var c = 49.0fp128;
printLn(toString(sqrt(a)));
printLn(toString(sqrt(b)));
printLn(toString(sqrt(c)));

endfunction
``````

### Special cases

Scenario Result
`x` is `NaN` `sqrt(NaN) = NaN`
`x == 1` `sqrt(x) = 1`
`x == 0` `sqrt(x) = 0`
`x < 0` `sqrt(x) = NaN`
`x == +inf` `sqrt(+inf) = +inf`

### Errors for x ∈ (0, 5)

• `Fixed32`: average: `0.000863796`, max: `0.00368993`
• `Fixed64`: average: `3.71316e-10`, max: `1.56033e-09`

## Trigonometry

### `Sin`, `Cos`, and `Tan`

``````function main()

var x = 1.0fp64;
printLn("sin of 1");
printLn(toString(sin(x)));

x = 0.5fp64;
printLn("sin of 0.5");
printLn(toString(sin(x)));

x = 0.0fp64;
printLn("sin of 0");
printLn(toString(sin(x)));

x = 1.0fp64;
printLn("cos of 1");
printLn(toString(cos(x)));

x = 0.5fp64;
printLn("cos of 0.5");
printLn(toString(cos(x)));

x = 0.0fp64;
printLn("cos of 0");
printLn(toString(cos(x)));

x = 1.0fp64;
printLn("tan of 1");
printLn(toString(tan(x)));

x = 0.5fp64;
printLn("tan of 0.5");
printLn(toString(tan(x)));

x = 0.0fp64;
printLn("tan of 0");
printLn(toString(tan(x)));

endfunction
``````

#### `Sin` special cases

Scenario Result
`x` is `NaN` `sin(x) = NaN`
`x` is `+/-inf` `sin(x) = NaN`
`x == 0` `sin(x) = 0`
`x < 0` `sin(x) = -sin(-x)`

#### Errors for x ∈ (-100 _ `Pi`/2, 100 _ `Pi`/2)

• `Fixed32`: average: `0.000552292`, max: `0.108399`
• `Fixed64`: average: `4.52891e-09`, max: `1.38022e-06`

#### `Cos` special cases

Scenario Result
`x` is `NaN` `cos(x) = NaN`
`x == +/-inf` `cos(x) = NaN`
`x == 0` `cos(x) = 1`

#### Errors for x ∈ (-100 _ `Pi`/2, 100 _ `Pi`/2)

• `Fixed32`: average: `0.000552292`, max: `0.108399`
• `Fixed64`: average: `4.52891e-09`, max: `1.38022e-06`

#### `Tan` special cases

Scenario Result
`x` is `NaN` `tan(NaN) = NaN`
`x == 1` `tan(x) = 1`
`x == 0` `tan(x) = 0`
`x < 0` `tan(x) = NaN`
`x == +inf` `tan(+inf) = +inf`

#### Errors for x ∈ (-Pi/2 + 0.01, Pi/2 - 0.01)

• `Fixed32`: average: `0.000552292`, max: `0.108399`
• `Fixed32`: average: `4.52891e-09`, max: `1.38022e-06`

### `ArcSin`, `ArcCos`, and `ArcTan`

``````function main()

var x = 1.0fp64;
printLn("asin of 1");
printLn(toString(asin(x)));

x = 0.5fp64;
printLn("asin of 0.5");
printLn(toString(asin(x)));

x = 0.0fp64;
printLn("asin of 0");
printLn(toString(asin(x)));

x = 1.0fp64;
printLn("acos of 1");
printLn(toString(acos(x)));

x = 0.5fp64;
printLn("acos of 0.5");
printLn(toString(acos(x)));

x = 0.0fp64;
printLn("acos of 0");
printLn(toString(acos(x)));

x = 1.0fp64;
printLn("atan of 1");
printLn(toString(atan(x)));

x = 0.5fp64;
printLn("atan of 0.5");
printLn(toString(atan(x)));

x = 0.0fp64;
printLn("atan of 0");
printLn(toString(atan(x)));

endfunction
``````

#### `ASin` special cases

Scenario Result
`x` is `NaN` `asin(x) = NaN`
`x` is `+/-inf` `asin(x) = NaN`
`|x| > 1` `asin(x) = NaN`
`x < 0` `asin(x) = -asin(-x)`

#### Errors for x ∈ (-1, 1)

• `Fixed32`: average: `1.76928e-05`, max: `0.000294807`
• `Fixed64`: average: `2.62396e-10`, max: `1.87484e-09`

#### `ACos` special cases

Scenario Result
`x` is `NaN` `acos(x) = NaN`
`x` is `+/-inf` `acos(x) = NaN`
`|x| > 1` `acos(x) = NaN`

#### Errors for x ∈ (-1, 1)

• `Fixed32`: average: `1.94115e-05`, max: `0.000305612`
• `Fixed64`: average: `2.65666e-10`, max: `1.78974e-09`

#### `ATan` special cases

Scenario Result
`x` is `NaN` `atan(x) = NaN`
`x` is `+/-inf` `atan(x) = +/- Pi/2`
`x < 0` `atan(x) = -atan(-x)`
`x > 1` `atan(x) = Pi/2 - Atan(1/x)`

#### Errors for x ∈ (-5, 5)

• `Fixed32`: average: `9.41805e-06`, max: `3.11978e-05`
• `Fixed64`: average: `9.69576e-10`, max: `2.84322e-08`

### Hyperbolic `Sin`, `Cos`, and `Tan`

``````function main()

var x = 1.0fp64;
printLn("sinh of 1");
printLn(toString(sinh(x)));

x = 0.5fp64;
printLn("sinh of 0.5");
printLn(toString(sinh(x)));

x = 0.0fp64;
printLn("sinh of 0");
printLn(toString(sinh(x)));

x = 1.0fp64;
printLn("cosh of 1");
printLn(toString(cosh(x)));

x = 0.5fp64;
printLn("cosh of 0.5");
printLn(toString(cosh(x)));

x = 0.0fp64;
printLn("cosh of 0");
printLn(toString(cosh(x)));

x = 1.0fp64;
printLn("tanh of 1");
printLn(toString(tanh(x)));

x = 0.5fp64;
printLn("tanh of 0.5");
printLn(toString(tanh(x)));

x = 0.0fp64;
printLn("tanh of 0");
printLn(toString(tanh(x)));

endfunction
``````

Warn

The `sinh()` implementation depends on `exp()` so the range is limited. The implementation is as follows:

```````sinh(x) = (e^x - e^(-x)) / 2`
``````

#### `SinH` special cases

Scenario Result
`x` is `NaN` `sinh(x) = NaN`
`x` is `+/-inf` `sinh(x) = +/-inf`

#### Errors for x ∈ (-5, 5)

• `Fixed32`: average: `6.63577e-05`, max: `0.000479903`
• `Fixed64`: average: `7.39076e-09`, max: `7.90546e-08`

#### `CosH` special cases

Scenario Result
`x` is `NaN` `cosh(x) = NaN`
`x` is `+/-inf` `cosh(x) = +inf`

Warn

The `cosh()` implementation depends on `exp()` so the range is limited. The implementation is as follows:

```````cosh(x) = (e^x + e^(-x)) / 2`
``````

#### Errors for x ∈ (-5, 5)

• `Fixed32`: average: `6.92127e-05`, max: `0.000487532`
• `Fixed64`: average: `7.30786e-09`, max: `7.89509e-08`

#### `TanH` special cases

Scenario Result
`x` is `NaN` `tanh(x) = NaN`
`x` is `+/-inf` `tanh(x) = +/-1`

Warn

The `tanh()` implementation depends on `exp()` so the range is limited. The implementation is as follows:

```````tanh(x) = (e^x - e^(-x)) / (e^x + e^(-x))`
``````

#### Errors for x ∈ (-3, 3)

• `Fixed32`: average: `1.25046e-05`, max: `7.0897e-05`
• `Fixed64`: average: `1.7648e-10`, max: `1.19186e-09`

### Hyperbolic `ArcSin`, `ArcCos`, and `ArcTan`

``````function main()

var x = 1.0fp64;
printLn("asinh of 1");
printLn(toString(asinh(x)));

x = 0.5fp64;
printLn("asinh of 0.5");
printLn(toString(asinh(x)));

x = 0.0fp64;
printLn("asinh of 0");
printLn(toString(asinh(x)));

x = 1.0fp64;
printLn("acosh of 1");
printLn(toString(acosh(x)));

x = 0.5fp64;
printLn("acosh of 0.5");
printLn(toString(acosh(x)));

x = 0.0fp64;
printLn("acosh of 0");
printLn(toString(acosh(x)));

x = 1.0fp64;
printLn("atanh of 1");
printLn(toString(atanh(x)));

x = 0.5fp64;
printLn("atanh of 0.5");
printLn(toString(atanh(x)));

x = 0.0fp64;
printLn("atanh of 0");
printLn(toString(atanh(x)));

endfunction
``````

#### `ArcSin` special cases

Scenario Result
`x` is `NaN` `asinh(x) = NaN`
`x` is `+/-inf` `asinh(x) = +/-inf`

#### Errors for x ∈ (-3, 3)

• `Fixed32`: average: `5.59257e-05`, max: `0.00063489`
• `Fixed64`: average: `3.49254e-09`, max: `2.62839e-08`

#### `ArcCos` special cases

Scenario Result
`x` is `NaN` `acosh(x) = NaN`
`x` is `+inf` `acosh(x) = +inf`
`x < 1` `acosh(x) = NaN`

#### Errors for x ∈ (1, 3)

• `Fixed32`: average: `8.53834e-06`, max: `6.62567e-05`

#### Errors for x ∈ (1, 5)

• `Fixed64`: average: `2.37609e-09`, max: `2.28507e-08`

#### `ArcTan` special cases

Scenario Result
`x` is `NaN` `atanh(x) = NaN`
`x` is `+/-inf` `atanh(x) = NaN`

#### Errors for x ∈ (-1, 1)

• `Fixed32`: average: `2.08502e-05`, max: `0.000954267`
• `Fixed64`: average: `1.47673e-09`, max: `1.98984e-07`