Skip to content

UXNumberFormatter

UXNumberFormatter turns an integer into the string a column needs: 1234567 into 1,234,567, the cents value 129900 into $1,299.00, 42 into 42%.

#use <UXKit> // or #import "UXNumberFormatter.xc"
UXNumberFormatter* f = UXNumberFormatter.decimal();
f.format(1234567); // 1,234,567
UXNumberFormatter* money = UXNumberFormatter.currency((u8*)"$");
money.formatFixed(129900, 2); // $1,299.00

There is no floating point. A fractional value is passed as an integer scaled by a power of ten, together with how many decimal places that represents:

f.formatFixed(129900, 2); // 1,299.00 — 129900 cents
f.formatFixed(425, 1); // 42.5
f.formatFixed(5, 2); // 0.05 — padded, not truncated

You pass cents, not dollars. Careful money code works this way, and it also makes the output identical on every backend, including ones with no FPU where double is not available.

The formatter never rounds: the value you give it is the value it prints.

new UXNumberFormatter(); // already groups: 1,234,567
f.setGrouping(false); // 1234567

A plain formatter is therefore new plus setGrouping(false). decimal() is the same as a fresh formatter, and exists because it reads better at a call site.

Separators are settable. This is the extent of locale support:

UXNumberFormatter* euro = UXNumberFormatter.currency((u8*)"EUR ");
euro.setGroupSeparator((u8)'.');
euro.setDecimalSeparator((u8)',');
euro.formatFixed(129900, 2); // EUR 1.299,00

Groups are always three digits, so the Indian lakh/crore grouping (12,34,567) is not expressible. Like the English-only month names in UXDateFormatter, this is an intended limit.

The prefix and suffix are literal text, so one class covers currency, percentages and units:

f.setPrefix((u8*)"$"); // $1,299.00
f.setSuffix((u8*)"%"); // 42%
f.setSuffix((u8*)" px"); // 640 px

format · formatFixed · setPrefix · setSuffix · setGrouping · setGroupSeparator · setDecimalSeparator · decimal · currency · percent

u8* format(i32 value)

An integer with no decimal part. Equivalent to formatFixed with 0.

u8* formatFixed(i32 value, i32 decimals)

value scaled by 10^decimals. The fractional digits are zero-padded to decimals, so 5 with 2 is 0.05 rather than 0.5.

Each call returns a fresh buffer.

void setPrefix(u8* p)

Kept, not copied. Pass a literal or a UXStr.dup.

void setSuffix(u8* s)

Same ownership rule.

void setGrouping(bool on)

true restores ,; false turns grouping off. Use setGroupSeparator to choose a different separator; setGrouping(true) resets it to a comma.

void setGroupSeparator(u8 c)

One byte. 0 means no grouping, which is what setGrouping(false) sets.

void setDecimalSeparator(u8 c)
static UXNumberFormatter* decimal(void)

Grouped, no prefix or suffix.

static UXNumberFormatter* currency(u8* symbol)

Grouped, with the symbol as prefix. Pass "$", "£", or "EUR " with its own space. The symbol is placed verbatim, so you control the spacing.

static UXNumberFormatter* percent(void)

A % suffix.

ungrouped: 1234567 default: 1,234,567
money: $1,299.00 negative: $-1,299.00
euro: EUR 1.299,00
pct: 42% one dp: 42.5%
edges: 0 999 0.05

The program is website/site/examples/uxkit/dates.xc; the doc-examples gate compiles it, and this is its output.

  • A plain class (not an Object subclass)