# Operators

## Precedence

Same as in C++.

|     Priority     | Operations                           |
|:----------------:|--------------------------------------|
| **Highest**<br>0 | power, not, calls, indexing, dot,... |
|        1         | `%` `*` `/`                          |
|        2         | `+` `-`                              |
|        3         | bit shifts `<<` `>>`                 |
|        4         | `<=>` (1)                            |
|        5         | `<=` `>=` `<` `>`                    |
|        6         | `==` `!=`                            |
|        7         | bitwise and `&`                      |
|        8         | bitwise xor `^`                      |
|        9         | bitwise or `\|`                      |
|        10        | `&&`                                 |
|  11<br/>lowest   | `\|\|`                               |

Bitwise operators
: available only for `Int` values. For mixed `Int`/`Real` numeric expressions, bitwise operators are not defined.

Bitwise NOT `~x`
: unary operator that inverts all bits of a 64‑bit signed integer (`Int`). It follows two's‑complement rules, so
  `~x` is numerically equal to `-(x + 1)`. Examples: `~0 == -1`, `~1 == -2`, `~(-1) == 0`.

Examples:

```
5 & 3    // -> 1
5 | 3    // -> 7
5 ^ 3    // -> 6
~0       // -> -1
1 << 3   // -> 8
8 >> 3   // -> 1
```

Notes:
- Shifts operate on 64-bit signed integers (`Int` is 64-bit). Right shift `>>` is arithmetic (sign-propagating).
- Shift count is masked to the range 0..63, similar to the JVM/Kotlin behavior (e.g., `1 << 65` equals `1 << 1`).

(1)
: Shuttle operator: `a <=> b` returns 0 if a == b, negative Int if a < b and positive Int otherwise. It is necessary to
override shuttle operator to make a class comparable.

## Operators

`+ - * / % `: if both operand is `Int`, calculates as int. Otherwise, as real:

    // integer division:
    3 / 2
    >>> 1

but:

    3 / 2.0
    >>> 1.5

## Round and range

The following functions return the argument unchanged if it is `Int`.

For `Decimal`:
- `floor(x)`, `ceil(x)`, and `round(x)` currently use exact decimal operations
- the result stays `Decimal`

For `Real`, the result is a transformed `Real`.

| name           | description                                            |
|----------------|--------------------------------------------------------|
| floor(x)       | Computes the largest integer value not greater than x  |
| ceil(x)        | Computes the least integer value value not less than x |
| round(x)       | Rounds x                                               |
| x.roundToInt() | shortcut to `round(x).toInt()`                         |

## Lyng math functions

Decimal note:
- all scalar math helpers accept `Decimal`
- `abs(x)` stays exact for `Decimal`
- `pow(x, y)` is exact for `Decimal` when `y` is an integral exponent
- the remaining `Decimal` cases currently use a temporary bridge:
  `Decimal -> Real -> host math -> Decimal`
- this is temporary; native decimal implementations are planned

| name      | meaning                                              |
|-----------|------------------------------------------------------|
| sin(x)    | sine                                                 |
| cos(x)    | cosine                                               |
| tan(x)    | tangent                                              |
| asin(x)   | $sin^{-1}(x)$                                          |
| acos(x)   | $cos^{-1}(x)$                                          |
| atan(x)   | $tg^{-1}(x)$                                           |
| sinh(x)   | hyperbolic sine                                      |
| cosh(x)   | hyperbolic cosine                                    |
| tanh(x)   | hyperbolic tangent                                   |
| asinh(x)  | $sinh^{-1}(x)$                                         |
| acosh(x)  | $cosh^{-1}(x)$                                         |
| atanh(x)  | $tgh^{-1}(x)$                                          |
| ln(x)     | $ln(x)$, $ log_e(x) $                                |
| exp(x)    | $e^x$                                                |
| log10(x)  | $log_{10}(x)$                                        |
| pow(x, y) | ${x^y}$                                              |
| sqrt(x)   | $ \sqrt {x}$                                         |
| abs(x)    | absolute value of x. Int if x is Int, Decimal if x is Decimal, Real otherwise |
| clamp(x, range) | limit x to be inside range boundaries          |

For example:

    assert( sin(π/2) == 1.0)
    assert( cos(π/2) < 0.000001)
    assert( abs(ln(exp(1))) - 1 < 0.00001)

    // abs() keeps the argument type:
    assert( abs(-1) is Int)
    assert( abs(-2.21) == 2.21 )

    import lyng.decimal

    // Decimal-aware math works too. Some functions are exact, some still bridge through Real temporarily:
    assert( (abs("-2.5".d) as Decimal).toStringExpanded() == "2.5" )
    assert( (floor("2.9".d) as Decimal).toStringExpanded() == "2" )
    assert( sin("0.5".d) is Decimal )

    // clamp() limits value to the range:
    assert( clamp(15, 0..10) == 10 )
    assert( clamp(-5, 0..10) == 0 )
    assert( 5.clamp(0..10) == 5 )
    >>> void

## Linear algebra: `lyng.matrix`

For vectors and dense matrices, import `lyng.matrix`:

```lyng
import lyng.matrix
```

It provides:

- `Vector`
- `Matrix`
- `vector(values)`
- `matrix(rows)`

Core operations include:

- matrix addition and subtraction
- matrix-matrix multiplication
- matrix-vector multiplication
- transpose
- determinant
- inverse
- linear solve
- vector dot, norm, normalize, cross, outer product

Example:

```lyng
import lyng.matrix

val a: Matrix = matrix([[1, 2, 3], [4, 5, 6]])
val b: Matrix = matrix([[7, 8], [9, 10], [11, 12]])
val product: Matrix = a * b
assertEquals([[58.0, 64.0], [139.0, 154.0]], product.toList())
```

Matrices also support two-axis bracket indexing and slicing:

```lyng
import lyng.matrix

val m: Matrix = matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
assertEquals(6.0, m[1, 2])
val sub: Matrix = m[0..1, 1..2]
assertEquals([[2.0, 3.0], [5.0, 6.0]], sub.toList())
```

See [Matrix](Matrix.md) for the full API.

## Random values

Lyng stdlib provides a global random singleton and deterministic seeded generators:

| name                     | meaning |
|--------------------------|---------|
| Random.nextInt()         | random `Int` from full platform range |
| Random.nextFloat()       | random `Real` in `[0,1)` |
| Random.next(range)       | random value from the given finite range |
| Random.seeded(seed)      | creates deterministic generator |
| SeededRandom.nextInt()   | deterministic random `Int` |
| SeededRandom.nextFloat() | deterministic random `Real` in `[0,1)` |
| SeededRandom.next(range) | deterministic random value from range |

Examples:

    val rng = Random.seeded(1234)
    assert( rng.next(1..10) in 1..10 )
    assert( rng.next('a'..<'f') in 'a'..<'f' )
    assert( rng.next(0.0..<1.0) >= 0.0 )
    assert( rng.next(0.0..<1.0) < 1.0 )
    >>> void

## Scientific constant

| name                 | meaning      |
|----------------------|--------------|
| `Math.PI: Real` or π | 3.1415926... |
|                      |              |
|                      |              |
|                      |              |
