> For the complete documentation index, see [llms.txt](https://guide.cronuszen.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://guide.cronuszen.com/gpcscripting/gpc-script-guide/reference/additional-built-ins/trigonometry-functions.md).

# Trigonometry functions

GPC has no floating-point type. These six built-ins are the integer equivalents of the usual trigonometric functions: instead of returning a float, they work in a fixed-point domain scaled by 10000. That scaling is what separates them from the float-based versions elsewhere — and the reason the ranges below matter more than the maths itself, which is standard trigonometry.

| Built-in       | Parameter | Static limit           | Input meaning   | Returns                          |
| -------------- | --------- | ---------------------- | --------------- | -------------------------------- |
| `sin(degrees)` | `degrees` | `0..360`               | integer degrees | sin × 10000                      |
| `cos(degrees)` | `degrees` | `0..360`               | integer degrees | cos × 10000                      |
| `tan(degrees)` | `degrees` | `0..360`               | integer degrees | tan × 10000, clamped at 90°/270° |
| `asin(value)`  | `value`   | `-10000..10000`        | value × 10000   | degrees                          |
| `acos(value)`  | `value`   | `-10000..10000`        | value × 10000   | degrees                          |
| `atan2(y, x)`  | `y`, `x`  | `VALUE_MIN..VALUE_MAX` | unscaled int    | degrees, `-180..180`             |

Note the direction of the scaling: `sin`, `cos`, and `tan` take plain degrees and return a scaled value. `asin` and `acos` do the reverse — they take a scaled value and return plain degrees. `atan2` takes two unscaled integers.

***

`sin` and `cos` are the pair used most in controller work: circular motion, smooth oscillation, vector rotation, and converting an angle and radius into X/Y components. Both are documented in full below.

### `sin`

**Compiler category:** `Math Functions`\
**Backing opcode:** `sin`

Returns the sine of an angle. In controller work, `sin()` commonly supplies the vertical component of circular movement or produces a smooth back-and-forth wave.

#### Syntax

```gpc
result = sin(degrees);
```

#### Parameters

| Parameter | Accepted value                                                              |
| --------- | --------------------------------------------------------------------------- |
| `degrees` | An integer angle in whole degrees. The documented static range is `0..360`. |

On verified current firmware, runtime angles wrap correctly — `sin(361)` behaves like `sin(1)`, and negative runtime angles work correctly.

#### Returns

An integer from `-10000` to `10000`. This is the real sine value multiplied by 10000.

| Expression | Returned value | Real value |
| ---------- | -------------: | ---------: |
| `sin(0)`   |              0 |     0.0000 |
| `sin(30)`  |           5000 |     0.5000 |
| `sin(45)`  |           7071 |     0.7071 |
| `sin(90)`  |          10000 |     1.0000 |
| `sin(180)` |              0 |     0.0000 |
| `sin(270)` |         -10000 |    -1.0000 |
| `sin(360)` |              0 |     0.0000 |

#### Example

```gpc
int sine_value;

init {
    sine_value = sin(30);   // 5000
}
```

The result is 5000 because the actual sine of 30 degrees is 0.5, and GPC represents it as 0.5 \* 10000.

#### Scaling an effect

```gpc
int angle;
int strength = 2500;
int vertical_offset;

main {
    vertical_offset = sin(angle) * strength / 10000;
}
```

With a strength of 2500, the resulting offset ranges from -2500 to 2500.

{% hint style="warning" %}
**Preserve fixed-point precision.** Multiply first and divide last. Integer division truncates, so `sin(angle) / 10000 * strength` destroys nearly all useful precision.
{% endhint %}

***

### `cos`

**Compiler category:** `Math Functions`\
**Backing opcode:** `cos`

Returns the cosine of an angle. `cos()` is commonly paired with `sin()` to supply the horizontal component of circular movement or rotated vectors.

#### Syntax

```gpc
result = cos(degrees);
```

#### Parameters

| Parameter | Accepted value                                                              |
| --------- | --------------------------------------------------------------------------- |
| `degrees` | An integer angle in whole degrees. The documented static range is `0..360`. |

On verified current firmware, runtime angles wrap correctly.

#### Returns

An integer from `-10000` to `10000`. This is the real cosine value multiplied by 10000.

| Expression | Returned value | Real value |
| ---------- | -------------: | ---------: |
| `cos(0)`   |          10000 |     1.0000 |
| `cos(30)`  |           8660 |     0.8660 |
| `cos(45)`  |           7071 |     0.7071 |
| `cos(90)`  |              0 |     0.0000 |
| `cos(180)` |         -10000 |    -1.0000 |
| `cos(270)` |              0 |     0.0000 |
| `cos(360)` |          10000 |     1.0000 |

#### Example

```gpc
int cosine_value;

init {
    cosine_value = cos(60);   // 5000
}
```

#### Scaling an effect

```gpc
int angle;
int strength = 2500;
int horizontal_offset;

main {
    horizontal_offset = cos(angle) * strength / 10000;
}
```

With a strength of 2500, the resulting offset ranges from -2500 to 2500.

***

### Using `sin` and `cos` together

For a point on a circle, cosine normally supplies X and sine supplies Y:

```gpc
x = cos(angle) * radius / 10000;
y = sin(angle) * radius / 10000;
```

| Angle | X from `cos` | Y from `sin` | Direction |
| ----: | ------------ | ------------ | --------- |
|     0 | positive     | 0            | Right     |
|    90 | 0            | positive     | Down      |
|   180 | negative     | 0            | Left      |
|   270 | 0            | negative     | Up        |

Controller Y axes normally use positive values for down and negative values for up. If you want traditional mathematical angles where 90 degrees points upward, invert Y:

```gpc
x = cos(angle) * radius / 10000;
y = (0 - sin(angle)) * radius / 10000;
```

### Example: circular right-stick movement

{% code title="circular-stick-movement.gpc" lineNumbers="true" %}

```gpc
define TRIG_SCALE = 10000;
define ORBIT_RADIUS = 2000;

int angle;
int orbit_x;
int orbit_y;

main {
    angle = angle + 1;
    if(angle >= 360) {
        angle = angle - 360;
    }

    orbit_x = cos(angle) * ORBIT_RADIUS / TRIG_SCALE;
    orbit_y = sin(angle) * ORBIT_RADIUS / TRIG_SCALE;

    // Convert -10000..10000 working values to -100..100.
    set_val(PS5_RX, orbit_x / 100);
    set_val(PS5_RY, orbit_y / 100);
}
```

{% endcode %}

This moves the right stick around a circle with a radius of 20 percent. Its speed depends on the VM interval. If the real-world speed must remain constant when the VM rate changes, advance the angle using elapsed time from `get_rtime()`.

{% hint style="success" %}
**High-resolution output.** The trig results are already in the ±10000 domain, and the modern analog output stage accepts that domain natively:

```gpc
set_val(ANALOG_RX, orbit_x);
set_val(ANALOG_RY, orbit_y);
```

This skips the divide-by-100 conversion and its quantization to 1-percent steps (100x finer resolution). The `PS5_RX` form above is shown for clarity on the standard ±100 axes; prefer `ANALOG_RX`/`ANALOG_RY` when smoothness matters.
{% endhint %}

### Example: smooth back-and-forth movement

{% code title="smooth-wave.gpc" lineNumbers="true" %}

```gpc
define WAVE_STRENGTH = 1500;

int angle;
int wave;

main {
    angle = angle + 1;
    if(angle >= 360) angle = angle - 360;

    wave = sin(angle) * WAVE_STRENGTH / 10000;
    set_val(TRACE_1, wave);
}
```

{% endcode %}

The value moves smoothly from 0 to 1500, through 0 to -1500, and back to 0 without abrupt direction changes.

{% hint style="info" %}
**Expected compile lint.** Writing values beyond ±100 to a trace emits the compiler's "maximum is 100" warning. That warning is advisory lint, not a clamp — `TRACE_1` through `TRACE_3` carry full 32-bit values (`TRACE_4` through `TRACE_6` are 16-bit), so this example displays the true ±1500 wave. Expect the warning and do not "fix" it by rescaling.
{% endhint %}

### Example: rotating an existing vector

```gpc
rotated_x = (x * cos(angle) - y * sin(angle)) / 10000;
rotated_y = (x * sin(angle) + y * cos(angle)) / 10000;
```

For large inputs, check both intermediate products and their sum or difference. The final result may be small while an intermediate expression still exceeds the signed 32-bit range.

### Important notes and common mistakes

* The functions use integer degrees. Fractional angles such as 12.5 degrees cannot be passed directly.
* The return value is fixed-point data scaled by 10000, not an ordinary controller percentage.
* A result of 10000 means 1.0, 5000 means 0.5, and -10000 means -1.0.
* Multiply by the desired radius or strength before dividing by 10000.
* A radius of 10000 is safe with these results because 10000 \* 10000 is within signed 32-bit range. Larger custom scales require a fresh overflow check.
* Runtime angles wrap on verified current firmware, but periodically keeping a long-running accumulator near `0..359` prevents eventual integer overflow.
* These are newer firmware-backed functions. A current Zen firmware and compatible Zen Studio Live compiler are required.
* When several systems write the same stick axes, the last output writer wins. Place the intended final stick output after earlier transformations.

{% hint style="success" %}
**Quick formula.** To turn an angle and strength into a controller-space vector, use `x = cos(angle) * strength / 10000` and `y = sin(angle) * strength / 10000`. Invert Y when your angle convention treats upward as positive.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://guide.cronuszen.com/gpcscripting/gpc-script-guide/reference/additional-built-ins/trigonometry-functions.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
