BigNum¶
A BigNum with Fractions implementation for big-integer calculations, optimized for DataStore storage and networking.
local BigNum = Resources:LoadLibrary("BigNum") print(BigNum.new("1025123") ^ BigNum.new("9")) --> 1250212389547080859766804627957328989496357747253559363
The BigNum library utilizes Lua's doubles to hold place values, called "radix" (similar to digits but in a different base). Each double represents a single "radix" of the BigNum. By default, the BigNum library instantiates BigNums with 32 radix (256 bytes) to do calculations. This is big enough for numbers as large as 7.76e230
(see BigNum:GetRange()
). If you need integers higher than that, simply pass in how many doubles it should allocate.
-- Explicitly allocate 128 doubles (1024 bytes) for each BigNum print(BigNum.new("8", 128) ^ BigNum.new("900", 128))
Otherwise, you can externally set the default number of allocated radix:
BigNum:SetDefaultRadix(64)
The library also ships with a data type called BigNumFractions, which can be used for exact calculations with Fractions.
Library API¶
BigNum.new¶
BigNum BigNum.new(string Base10Number [, integer Radix])
Returns a new BigNum with the allocated number of Radix (defaults to 32)
BigNum.fromString64¶
BigNum BigNum.fromString64(string Base64String)
Meant to instantiate BigNums from strings returned via the toString64
method.
BigNum.newFraction¶
BigNumFraction BigNum.newFraction(BigNum Numerator, BigNum Denominator)
Instantiates a new Fraction in the form (Numerator / Denominator)
BigNum:GetRange¶
string BigNum:GetRange(integer Radix)
Returns a string representation of approximately how large of integers can be represented with a given number of Radix
print(BigNum:GetRange(128)) --> +/- 2.90e924
BigNum:SetDefaultRadix¶
void BigNum:SetDefaultRadix(integer DefaultRadix)
Sets the default number of Radix allocated for each number (default is 32)
BigNum API¶
These are the methods which operate on BigNums themselves.
BigNum:toString64¶
string BigNum:toString64()
Returns a string-base64 encoding of the BigNum, which can be reproduced using BigNum.fromString64
BigNum:toConstantForm¶
void BigNum:toConstantForm(integer NumberOfDoublesPerLine = 16)
Creates a file (or on Roblox, a script in the Lighting) with a constant representation of the BigNum. This is useful for directly instantiating BigNums with Big values which would take a lot of processing at run-time to convert from a base10 string to the internal representation.
Looks like this:
local CONSTANT_NUMBER = BigNum.new{ 0, 0, 154059, 3375645, 903522, 1038360, 13086355, 12524895, 10900259, 11967773, 5580376, 3468437, 579970, 6766011, 8397479, 8219103, 8206478, 4226184, 11579046, 8128945, 3969135, 407937, 10824426, 1462231, 7523964, 16399268, 11691710, 13651477, 10604193, 2791442, 9280589, 5604105 }
BigNum:stringify¶
string BigNum:stringify()
Returns a representation of the internal format of how BigNums are stored in their array.
BigNumFraction API¶
BigNumFraction:Reduce¶
BigNumFraction BigNumFraction:Reduce()
Reduces the Fraction and returns it.
BigNumFraction:toScientificNotation¶
string BigNumFraction:toScientificNotation(integer NumDigitsAfterDecimalPoint = 2)
Returns a string representation of the Fraction in scientific notation with the given number of digits after the decimal. If there aren't enough digits to format it will just return the unformatted string.
Demo¶
Here the library is used to calculate the Birthday problem.
local BigNum = Resources:LoadLibrary("BigNum") local _1 = BigNum.newFraction("1", "1") local DaysInYear = BigNum.new("365") local function BirthdayProblem(NumPeople) local Chance = BigNum.newFraction(DaysInYear, DaysInYear) for i = 2, NumPeople do Chance = Chance * BigNum.newFraction(DaysInYear + (1 - i), DaysInYear) end return _1 - Chance end print(BirthdayProblem(70):toScientificNotation(6)) --> 2.291582e179 / 2.293509e179
Writing Optimal Code with BigNum¶
Sometimes, you will need to perform a massive calculation which might take up too much time to calculate on Roblox without having the thread scheduler cut you off.
What follows is a list of what this library is optimized for and what this library is slow at.
Optimized for:
-
Any code given to you via the
toConstantForm
method -
Encoding/Decoding for DataStores/Replication using
toString64
andfromString64
Runs slowly:
-
Printing massive numbers (in Base 10) a lot (Never use GetRange at run-time!)
-
Creating BigNums from a Base10String at run-time (toConstantForm is recommended)
-
Using more Radix than the library can be performant with. In my tests, 32 radix approaches native speeds, with going too far above 128 leading to unstability in intensive calculations
Probably asked Questions¶
What if I want to know what's after the decimal point?
Use Fractions!
How does this library work?
It uses a modified version of two's-complement numbers (but in base 2^24).
Why are calculations done in base 2^24?
Because the highest integer representable by a double is 2^53. 2^24 is the nicest high number which won't result in the internal calculations reaching higher than 2^53. Multiplying two numbers with the highest radix and the highest previous value can result in: (2^24 - 1)(2^24 - 1) + (2^24 - 1)