Verse Wiki — the Verse handbook for Blueprint authors
EXTRA

Rounding to Any Number of Decimal Places: RoundToDecimalPlaces

"How do I keep a float to two decimal places?" is a perennial question on the official forums, and the standard answer from an Epic staffer is only five lines — five lines that happen to chain together everything from Lesson 9: Pow, the multiply-by-1.0 conversion, the might-not-go-through Round[] (square-bracket call), and gatekeeping the parameters. Let's take it apart line by line.

1. A Perennial Question

Nearly every creator who has built a scoreboard, floating damage numbers, or a leaderboard has stalled at the same spot: the computed float is 10.12345, but the UI should show only 10.123. In other engines that might be a ready-made "round to N places" node; but comb Verse's built-in function library and you won't find a ready-made "keep N decimal places" function either — only the three acquaintances from Lesson 9: Floor[], Ceil[], Round[], and they all round to whole numbers.

The forum question "How to round float to X decimal places" eventually got its canonical answer from Epic staffer Kurtis Schmidt. The idea itself is an old trick common to every language: scale the decimal up into an integer, round, then scale back down — to keep 3 decimal places, multiply by 10³ = 1000, round, then divide by 1000 again. The delightful part: landing this old trick in Verse forces every step through the type checkpoints this lesson covered, which makes these five lines superb review material.

2. Line by Line

round_utils.verse
# Adapted from Epic staffer Kurtis Schmidt's answer on the official forums (source at the end)
# For Round's behavior at .5, defer to the Verse API Reference
RoundToDecimalPlaces(Value:float, DecimalPlaces:int)<varies><decides>:float =
    DecimalPlaces >= 0
    Multiplier := Pow(10.0, DecimalPlaces * 1.0)
    Rounded := Round[Value * Multiplier] * 1.0
    Rounded / Multiplier

The signature: the function name carries the <decides> effect marker — it turns the whole function into a step that might not go through: call it with square brackets and plug it into a Branch node (if), same treatment as Floor[]. (The original post's signature also has <varies>, preserved verbatim here.)

Line one, DecimalPlaces >= 0: not a forgotten half-sentence — it's gatekeeping the parameter. Remember what Lesson 9 said — every comparison in Verse is a "does this wire go through?" check. Inside a function marked <decides>, if any single step fails to go through, the whole call fails to go through. So the rule that decimal places can't be negative gets enforced without placing a single Branch (if).

Line two, Pow(10.0, DecimalPlaces * 1.0): both of Pow's parameters are floats, and DecimalPlaces is an int — Verse won't swap your int for a float automatically, so it crosses the multiply-by-1.0 bridge. Keeping 3 places, Multiplier is 1000.0.

Line three, Round[Value * Multiplier] * 1.0: one line makes a round trip: Value * Multiplier scales 10.12345 up to 10123.45; Round[], called with square brackets (meaning it might not go through), rounds it to the int 10123 (if Value is NaN, or the scaled value exceeds int range, this step doesn't go through and the whole function doesn't either — exactly what we want); then multiplying by 1.0 converts back to float, ready for the next line's division.

Line four, Rounded / Multiplier: two floats dividing — float division never fails to go through, and out comes 10.123. No return written here: Verse returns implicitly — the result of the last expression in the function simply becomes this function's return value (as if the last node's output pin were wired straight into the Return pin, no dedicated Return node needed).

In use, it looks like this:

round_demo_device.verse
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/Diagnostics }

round_demo_device := class(creative_device):

    OnBegin<override>()<suspends>:void =
        if (Result := RoundToDecimalPlaces[10.12345, 3]):
            Print("Three places: {Result}")

Graph translation: a device whose Event BeginPlay calls the freshly written RoundToDecimalPlaces, keeping 10.12345 to 3 places. Since the function might not go through (square-bracket call), it must plug into a Branch node (if): only when it goes through does Print String show the result.

3. The Last Mile of Display

First, half a bucket of cold water: the Print String node above outputs Three places: 10.123000. Numerically it really is 10.123 now, but Lesson 9's old pothole remains — float-to-string always carries six decimal places, tail zeros still attached. So this function solves the “numeric precision” problem (say, snapping settlement amounts to the cent), not the “display formatting” problem. To make the UI genuinely show just three decimals, one more string-processing step is needed: the official community has a ready-made "Float to String with Decimal Places" snippet that assembles a float into a string with the specified decimal places — a perfect follow-up to this function.

Keep the two concerns separate — "what the number is" belongs to RoundToDecimalPlaces, "what the number looks like" belongs to string formatting — and a whole mess of UI number chaos untangles itself.

Why does line two write DecimalPlaces * 1.0 instead of passing DecimalPlaces to Pow directly?

Why is the call written RoundToDecimalPlaces[10.12345, 3] (square brackets)?

Sources

Compiled from the Epic Developer Forums and an official community snippet: How to round float to X decimal places (Epic Developer Forums) ↗ · Float to String with Decimal Places (official community snippet) ↗