> For the complete documentation index, see [llms.txt](https://docs.membercounter.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.membercounter.app/counters-reference/math.md).

# Math

Perform math operations like addition, subtraction, multiplication, division, or modulus on a list of numbers.

The Math counter takes a list of numbers and reduces it to one number with a single arithmetic operation. Each entry can be a number you type or a [nested counter](/using-the-dashboard/nested-counters.md), so you can build values Discord does not give you directly, such as the percentage of members who are online.

**Availability:** every bot type. It makes no network requests, so it needs no API key and no environment variable when you [self-host](/self-hosting/configuration.md).

<figure><img src="https://1582170640-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lu2S5r7lKtu4IK5ucu9%2Fuploads%2Fgit-blob-8ea2fef425682a0656b090c9e27eaabeb6207232%2Fcounter-math-options.png?alt=media" alt="Math options"><figcaption><p>The Math counter panel: <strong>Operation type</strong> and <strong>Number list</strong></p></figcaption></figure>

## Options

| Option             | What it does                                                      | Notes                                                                                                                                                                                               |
| ------------------ | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Operation type** | Picks the operation applied to the whole **Number list**.         | Starts on **Addition**, so an untouched Math counter adds.                                                                                                                                          |
| **Number list**    | The operands, used from first to last in the order you list them. | Type a number in the **Add number...** row to append one, or pick a counter from the same box to nest it. Order matters for **Subtraction**, **Division** and **Modulo (Remainder of a division)**. |

Every row of **Number list** takes a nested counter, and that counter must return a number.

### Operation type values

| Value                                | Result                                                                                | With the list 100, 20, 5 |
| ------------------------------------ | ------------------------------------------------------------------------------------- | ------------------------ |
| **Addition**                         | Adds every entry.                                                                     | `125`                    |
| **Subtraction**                      | Subtracts each entry from the running result, from first to last.                     | `75`                     |
| **Multiplication**                   | Multiplies every entry.                                                               | `10000`                  |
| **Division**                         | Divides the running result by each entry, from first to last.                         | `1`                      |
| **Modulo (Remainder of a division)** | Keeps the remainder of dividing the running result by each entry, from first to last. | `0`                      |

## What it returns

A number.

* **Addition** and **Multiplication** start from a seed, so an empty **Number list** gives `0` and `1`.
* **Subtraction**, **Division** and **Modulo (Remainder of a division)** start from the first entry instead. A single entry comes back unchanged, and an empty list breaks the whole template.
* Every entry is read as a number first. A nested counter that returns text the bot cannot read as a number makes the counter fail.
* Dividing by `0` is not an error. It returns `Infinity`, shown as `∞` when compact notation is on.

## Formatting

Math returns a number, so the [Format settings](/using-the-dashboard/customizing-counters.md) apply to it. The bot reads them from the outermost counter of the chip and applies them once to the final value, and anything you leave unset falls back to the [Server settings](/using-the-dashboard/server-settings.md).

{% hint style="info" %}
**There is no rounding option.** A Math result keeps its full precision, so a division can come out as `42.857142857142854`. Setting **Use compact notation** to **Yes** is the only way to shorten it: it cuts the value to roughly two significant digits, so that result becomes `43`. It also abbreviates large numbers, so `1234` becomes `1.2K`.
{% endhint %}

## Refresh and caching

Math caches nothing. The bot works it out again on every channel update, every 10 minutes on the public bot and every 5 minutes on the other bot types. See [How counters update](/using-the-dashboard/how-counters-update.md).

Nested counters keep their own rules, so a value can still lag: [Reddit](/counters-reference/reddit.md), [Twitch](/counters-reference/twitch.md) and [YouTube](/counters-reference/youtube.md) serve a cached value, and [HTTP](/counters-reference/http.md) caches only when you set a **Lifetime (in seconds)**. Twitch and YouTube do not work on the public bot.

## Examples

{% tabs %}
{% tab title="Online percentage" %}
The most common use of Math: turn two member counts into one percentage.

1. Add a **Math** counter and set **Operation type** to **Multiplication**.
2. In its **Number list**, add a nested **Math** counter set to **Division**, then type `100` into the **Add number...** row.
3. Fill the nested division's **Number list** with two nested [Members](/counters-reference/members.md) counters: first one with **Filter by status** set to **Online + Idle + DND**, then one with no filters. Division works from first to last, so the online count goes first.
4. Open **Format settings** on the outer counter and set **Use compact notation** to **Yes**, so the long decimal is shortened.

With 1 of 2 members online, the division returns `0.5`, the multiplication turns that into `50`, and the channel shows `Online: 50%`.

<figure><img src="https://1582170640-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lu2S5r7lKtu4IK5ucu9%2Fuploads%2Fgit-blob-e07752a5e87f5aa9bfaee5cc157696b30f99801a%2Fcounter-math-example-online-percentage.png?alt=media" alt="Online percentage built from nested counters"><figcaption><p>A Multiplication of a nested Division and 100, with compact notation on. On the small test server 1 of 2 members is online, so the channel reads <code>Online: 50%</code></p></figcaption></figure>

The public bot cannot read member presences, so the online count behaves differently there. Read [Members](/counters-reference/members.md) before you build this one.
{% endtab %}

{% tab title="Humans only" %}
Subtract the bots from the total.

* **Operation type**: **Subtraction**
* **Number list**:
  1. A nested [Members](/counters-reference/members.md) counter with no filters.
  2. A nested **Members** counter with **Filter by account type** set to **Bot**.

With 120 members of which 8 are bots, the counter returns `112`.
{% endtab %}

{% tab title="Cleaning a value first" %}
Math only accepts numbers. When the value arrives as text, for example a price pulled out of an API by an [HTTP](/counters-reference/http.md) counter, put a [Replace](/counters-reference/replace.md) counter around it to clean it up and a [Number](/counters-reference/number.md) counter around that, then nest the result in **Number list**.
{% endtab %}
{% endtabs %}

## Errors

| What you see                                                        | What to do                                                                                                                                                                                                                     |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| The channel shows `ERROR!`                                          | The template failed. Open the channel in the dashboard and read the error below.                                                                                                                                               |
| **Failed to generate a final string from the evaluation.**          | Something in **Number list** is not a number. Check every row, wrap text-returning counters in [Number](/counters-reference/number.md), and strip separators and symbols with [Replace](/counters-reference/replace.md) first. |
| **The evaluation took too long and timed out.**                     | A counter took more than 60 seconds, usually a nested [Game](/counters-reference/game.md) counter whose server does not answer, or a long chain of nested requests. Simplify the nesting.                                      |
| **The result for the channel name is less than 2 characters long.** | A voice or category channel name needs at least 2 characters. Add text around the counter in the template, for example `Online:` before it.                                                                                    |

If it still fails, [Troubleshooting](/using-the-dashboard/troubleshooting.md) walks through the common causes, and you can ask on the [support server](https://membercounter.app/support).

<details>

<summary>Technical details</summary>

* Evaluator: `packages/services/src/DataSource/DataSourceEvaluator/evaluators/Math.ts`. Every entry goes through `Number()`, then one `reduce` over the list.
* `Subtraction`, `Division` and `Modulo` reduce with no initial value, so an empty list throws `Reduce of empty array with no initial value`.
* `operation` is stored as the `MathDataSourceOperation` enum: ADD `0`, SUBTRACT `1`, MULTIPLY `2`, DIVIDE `3`, MODULO `4`. The evaluator's `switch` shares its `default` with ADD, so an unset or unknown value adds.
* A `NaN` result raises the known error `FAILED_TO_RETURN_A_FINAL_STRING`. `Infinity` is not `NaN`, so it passes that check and is printed.
* On a failed template the update job writes the `jobs.updateChannels.computeError` string into the name or topic: `ERROR!` in en-US, translated in the other locales.
* Compact notation runs through `Intl.NumberFormat(locale, { notation: "compact" })`, and the custom-digit substitution runs only when `isTextLikeChannel(channelType)` is true.
* Global limits: 60 s per counter in the template, shared with everything nested inside it (`EVALUATION_TIMEOUT`), 50,000 tree-exploration iterations, and a final result that is trimmed and then cut to 1023 characters for a topic or 99 for a channel name, with the 2-character minimum (`EVALUATION_RESULT_FOR_CHANNEL_NAME_IS_LESS_THAN_2_CHARACTERS`) checked before the cut.
* Typing text into the **Add number...** row stores `NaN` with no guard, so it fails only at evaluation time; editing an existing row ignores a value that is not a number instead.
* No network access, no cache entry, no environment variable when self-hosting and no premium gating: the evaluator is identical in the FOSS and hosted repositories.

</details>
