Wiki 9Minecraft Wiki 9Minecraft

Scoreboard Operations and Math in Functions

Use /scoreboard players operation to run integer math, copy values, and compare scores.

5Sections
4Code examples
3Known errors

The /scoreboard players operation command lets you add, subtract, multiply, divide, and compare two scoreboard values directly inside a mcfunction file. While simple score changes only need add or remove with a fixed number, operations are what you reach for when both values are dynamic—such as subtracting a variable shop price from a player's wallet, finding the highest score in a lobby, or converting raw tick counters into minutes and seconds.

Syntax and the Nine Operators

Every scoreboard operation takes two target-and-objective pairs and an operator between them. The full command shape is /scoreboard players operation <targetName> <targetObjective> <operation> <selector> <objective>. In almost all operators, the left side (<targetName> and <targetObjective>) is the destination that gets overwritten, while the right side (<selector> and <objective>) is read-only. The sole exception is the swap operator, which modifies both sides at once.

Because Bedrock scoreboards only store 32-bit signed integers, every result is a whole number between -2,147,483,648 and 2,147,483,647. There are no decimals or floating-point values in scoreboard math. If an addition or multiplication exceeds the maximum limit, the integer overflows and wraps around into negative numbers. Similarly, division discards any remainder rather than rounding to the nearest whole number.

Both the target and the source can be real entities selected with @p, @a, @e, or @s, or they can be fake players—arbitrary strings of text that hold scores without needing an entity in the world. If a target or source does not have a score on the specified objective yet, the operation initializes it to 0 before running the math.

OperatorWhat it doesNotes
=AssignmentCopies the right-hand score into the left-hand target, overwriting the old value.
+=AdditionAdds the right-hand score to the left-hand score and stores the sum on the left.
-=SubtractionSubtracts the right-hand score from the left-hand score and stores the difference on the left.
*=MultiplicationMultiplies the left-hand score by the right-hand score. Watch out for 32-bit overflow on large numbers.
/=Integer DivisionDivides the left-hand score by the right-hand score and drops the remainder. Division by zero fails safely with an error.
%=ModuloDivides the left-hand score by the right-hand score and stores only the remainder on the left.
><SwapExchanges the two scores. The left target gets the right score, and the right target gets the left score.
<MinimumCompares both scores and sets the left-hand score to whichever value is smaller.
>MaximumCompares both scores and sets the left-hand score to whichever value is larger.

Fake Players, Constants, and Temporary Registers

You cannot type a raw number on the right side of an operation; the syntax strictly requires a selector or player name followed by an objective. While /scoreboard players add and remove accept literal numbers, multiplication, division, modulo, and clamping do not. To multiply a score by 10 or divide by 20, you must store those numbers on fake players ahead of time.

A standard practice in behaviour packs is to create a dedicated objective—often named math or const—and initialize your constant fake players inside a setup function. Prefixing fake player names with a symbol like # or . (for example, #ten or #ticks_per_sec) prevents them from colliding with real Xbox Live gamertags, which cannot contain those characters. More importantly, names starting with # are conventionally used to keep fake players from cluttering the sidebar display if you ever set that objective to show on screen.

Equally important is the concept of a temporary register. Because +=, -=, *=, /=, and %= overwrite the left-hand score, running math directly on a player's primary stat destroys the original number. If you need to calculate a damage bonus based on a player's strength without changing their actual strength stat, you first copy the stat into a temporary score (like #temp on the math objective) using the = operator, and then run your arithmetic on #temp.

BP/functions/math/init.mcfunction
# Create the utility objective for constants and scratchpad math
scoreboard objectives add math dummy
scoreboard objectives add timer dummy

# Define immutable constants using '#' prefix so they never match a real player
scoreboard players set #zero math 0
scoreboard players set #two math 2
scoreboard players set #ten math 10
scoreboard players set #twenty math 20
scoreboard players set #sixty math 60
scoreboard players set #one_hundred math 100

Scaling, Percentages, and Division Order

Integer division truncates toward zero: 7 divided by 2 becomes 3, and 19 divided by 20 becomes 0. This catches many creators off guard when calculating percentages or scaling stats. If a player has 45 health out of 60 and you try to find their health percentage by dividing 45 by 60 first, the operation 45 /= 60 yields 0. Multiplying that 0 by 100 afterward still leaves you with 0.

To preserve precision in integer math, always multiply before you divide. Taking the same 45 health, if you multiply by 100 first, your working register holds 4500. Dividing 4500 by 60 then yields 75, giving you the exact whole-number percentage.

The function below demonstrates how to convert a raw tick counter into minutes and seconds for a custom HUD display, as well as how to apply a 15% tax to a transaction using temporary registers so the player's base variables stay intact until the final deduction.

BP/functions/math/convert_time_and_tax.mcfunction
# Assume @s has a 'ticks_left' score (e.g. 2540 ticks = 127 seconds = 2m 07s)
# Step 1: Copy raw ticks to a temp register and convert to total seconds
scoreboard players operation #total_sec math = @s ticks_left
scoreboard players operation #total_sec math /= #twenty math

# Step 2: Extract minutes (total_sec / 60) and remaining seconds (total_sec % 60)
scoreboard players operation @s display_min = #total_sec math
scoreboard players operation @s display_min /= #sixty math

scoreboard players operation @s display_sec = #total_sec math
scoreboard players operation @s display_sec %= #sixty math

# --- Percentage Example: Deduct 15% tax from @s 'gold' ---
# Multiply by 15 BEFORE dividing by 100 so small gold amounts don't round to 0 prematurely
scoreboard players set #tax_rate math 15
scoreboard players operation #tax_amount math = @s gold
scoreboard players operation #tax_amount math *= #tax_rate math
scoreboard players operation #tax_amount math /= #one_hundred math

# Subtract the calculated tax from the player's actual gold
scoreboard players operation @s gold -= #tax_amount math

Clamping Values and Finding the Highest Score

The < (minimum) and > (maximum) operators are shortcuts that save you from writing multiple /execute if score chains. Their symbols can feel backwards at first when used for clamping. To cap a score so it never exceeds a ceiling (say, 100 mana), you use the < operator against a constant of 100. Because < picks the smaller of the two numbers, any mana value above 100 is pulled down to 100, while anything below 100 stays as it is. Conversely, to enforce a floor so a score never drops below 0, you use the > operator against a constant of 0, which picks the larger number.

The > operator is also the standard way to find the highest score across all players in a match. When you use a multi-target selector like @a on the right side of an operation, Bedrock evaluates the operation against every matched player one by one. By resetting a fake player (#high_score) to 0 and running scoreboard players operation #high_score game > @a game, the command compares #high_score against every player in the world and keeps the highest value it encounters.

Once #high_score holds the winning number, you can find the specific player or players who achieved it by pairing /execute as @a with an if score comparison.

BP/functions/game/clamp_and_winner.mcfunction
# Clamp @s 'mana' between 0 and 'max_mana'
# '>' sets left to the LARGER value (enforces minimum floor of 0)
scoreboard players operation @s mana > #zero math
# '<' sets left to the SMALLER value (enforces maximum ceiling of max_mana)
scoreboard players operation @s mana < @s max_mana

# Find the highest 'kills' score among all online players
scoreboard players set #high_kills math 0
scoreboard players operation #high_kills math > @a kills

# Tag everyone who tied for the highest score (as long as high_kills is at least 1)
execute as @a if score @s kills = #high_kills math if score #high_kills math matches 1.. run tag @s add round_winner

Running Scoreboard Math Automatically on Tick

For operations like mana clamping or timer conversions to feel responsive, they need to run every game tick without manual command blocks. In a behaviour pack, you register your recurring mcfunction inside BP/functions/tick.json. Every function path listed in the values array is executed by the server 20 times per second.

Keep your one-time constant initialization (such as setting #twenty and #one_hundred) out of your ticking function, or guard it with a scoreboard check so you are not wasting command execution budget rewriting static numbers every tick. If you do run per-player math inside a tick function, branch out from a single execute as @a at the root of the function so @s bindings remain unambiguous across all your scoreboard operations.

BP/functions/tick.json
{
  "values": [
    "math/tick_timers"
  ]
}

Which versions this applies to

Applies to all modern Minecraft Bedrock versions (1.19.50+ for the current /execute if score syntax shown alongside the operations). No experimental toggles are required.

When it does not work

What you seeWhyThe fix
Division or percentage math always outputs 0 even when the starting score is positive.You divided a smaller integer by a larger integer before multiplying (for example, dividing a current stat by a max stat to get a ratio), which truncates the decimal result down to 0.Reverse the order of operations: multiply the working score by your scalar (such as 100 for percentages) first, and run the /= operation last.
Command log returns 'No targets matched selector' or the operation silently skips a player during a function.The selector used in the operation (@p or @s) did not resolve to an entity in that execution context, or you used an offline real player's name with a selector filter instead of a plain fake player name.Ensure the function is called via 'execute as <target> run function ...' when using @s, and use plain text strings (like #temp) without target selector brackets for fake players.
Command outputs an error stating the objective was not found, or scores reset unexpectedly.The math objective or the constant fake players (#twenty, #one_hundred) were never initialized in the world, so the right-hand side of the operation defaults to 0. For /= and %=, a right-hand value of 0 causes the command to abort due to division by zero.Run your initialization function once on world load to create the dummy objectives and set all constant scores before any ticking functions execute.

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.