Skip to content

BigValue

The object a Scribe.Big field hands back from Get. It is an object rather than a number because the point of the field is a value that has outgrown one: a mantissa and an exponent, carrying about 15 significant digits at any magnitude. There is no public constructor, so you get one from a big field and write one back through that field.

It supports +, -, *, /, unary - and tostring. Each binary operator takes a number, a numeric string like "1.5e100", or another big value on either side, so essence + 5 and 5 + essence both work. Any other operand errors naming its type, and dividing by zero errors rather than handing back an infinity that no save would survive.

Comparisons need a big on both sides

Luau picks < and <= by metatable identity, so Get() < 2000 throws. == is consulted only when both sides are tables, so Get() == 5 is silently false rather than an error. Compare two big values directly, or convert with ToNumber first.

Methods are called with a colon, essence:Short(), so the signatures below drop the implicit self. The Big Numbers guide covers the rest.

Methods

:Pow

BigValue:Pow(n: number)  BigValue

Raises the value to the power n and returns a new big. x:Pow(0) is 1 for every x, zero included.

data.Essence.Set(data.Essence.Get():Pow(2))   -- square the balance

n must be a non-negative integer no larger than 2^53. Anything else errors, so Pow(2.5), Pow(-3) and Pow(math.huge) raise instead of returning a plausible wrong answer; for a negative power, divide by the positive one. A result past the exponent ceiling saturates, exactly as * does.

Prefer it to a chain of Multiply calls whenever the result has to rank. Pow rounds once at the end where a chain rounds at every step; the measured difference is in the Big Numbers guide.

:Log10

BigValue:Log10()  number

The base-10 logarithm, as a plain number. E is its exact integer part and this adds the fraction, which makes it the cheap way to turn a magnitude into a tier:

local tier = math.floor(data.Essence.Get():Log10() / 3)

Total and unguarded, matching what the same call on a plain number does: zero gives -inf and a negative value gives nan, so a fresh 0 balance needs no special case at the call site. Precision decays as the value grows, from about 17 significant digits at 1e0 to 10 at 1e1000000 and none near the exponent ceiling, so read E when you need the integer part exactly.

:Short

BigValue:Short(decimals: number?)  string

The display form. Uses a letter suffix while there is one and falls back to scientific notation once it runs out, so 1500 is "1.50K", 1e40 is "10.00DDc" and 1.5e100 is "1.5e100". A negative value keeps its sign.

data.Essence.Observe(function(essence)
    essenceLabel.Text = essence:Short()
end)

decimals defaults to 2 and rounds rather than truncates, so Short(0) on 1500 gives "2K". The full suffix table is in the Big Numbers guide.

:ToNumber

BigValue:ToNumber()  number

The value as a plain Luau number. Lossy on purpose: digits past the 53rd bit are gone, and anything past 1.8e308 saturates to math.huge.

This is how you test a big against a constant, since < and == both need a big on the other side:

if data.Essence.Get():ToNumber() >= price then
    data.Essence.Decrement(price)
end

A read, not a round trip. Writing the result back through the field rounds the balance to what a double can hold, which is the ceiling the field exists to escape.

Fields

.M

property
BigValue.M: number

The mantissa: exactly 0, or in [1, 10) carrying the value's sign and its ~15 significant digits. 1.5e100 has M = 1.5.

Read it, do not write it. Get builds a fresh object on every call, detached from the stored form, so assigning to M changes a copy nothing will save.

.E

property
BigValue.E: number

The exponent: the exact integer part of the base-10 logarithm. 1.5e100 has E = 100, and zero has E = 0. Use it rather than Log10 when you need that integer exactly at any magnitude.

It caps at 2^52, the largest exponent the wire encoding can carry back, and a value that would exceed it saturates there rather than storing an infinity the save could not round-trip. Assigning to it is the same no-op as assigning to M.