How to Save numbers over 9.223 Quintillion to OrderedDataStore?

but why would you want people to have numbers or values that aren’t integers?
or does your game require such precision in saving certain values to keys in a table for example?
edit–or values like 9.2223 quintillion
from another post -

just for instance,when youve got too large of a string
and in OrderedDatastores your value must be an integer
You should only use an Ordered DataStore for ranking systems as they are inefficient because they only store integers which will require a lot of requests to get each piece of data.

I’m not sure how many players you’re showing in the top leaderboard, but I’m going to assume 100 (because it’s simple).

Here’s what I’m thinking: When a player has the number updated, it will be saved in the ODS. If this player is the top player, the server should fetch all top 100 entries. With these entries, it should check if any of them are closing up to the max-number. If they are closing up, it should divide all the entries by a set number, and update them. Now, you’ve fixed the problem of dividing it.

But, what if someone else gets their number increased? (I will be talking about the number as money from this point…). If you were to insert someone in the “top ODS”, you don’t know what to divide their money on? There’s a simple fix for this. Whenever you divide the top players’ money, you should save the number to divide it with in the database.

Moving on to how this works:


Example 1, reaching the limit

Let’s say you have 3 players in your leaderboard, which will look something like this
image

They are now approaching the max number, which is 10,000,000. The server should now divide all numbers with a number, for example 1,000,000. This would result in the players getting the following money:
image

But wow, they just lost all their money! No, because if you save the number you divided the money on, you know what to multiply the numbers with in order to display them.


Example 2, new player reaches the leaderboard

Now, let’s say we still have the 3 same players in our table, with the money divided:
image

And, let’s assume Joanna just got 8,300,000,000 money. The server will then divide the money by the number saved in the database. This will make the number become 8300. Now, she’s #3 in the leaderboard and it’s easy.

EDIT: Yes, there is an issue with this method. Stupid decimals. But one step at a time.

The best solution for you, would be to simply use an external database service where you can easily sort the top values!

2 Likes

What I did was use a bit of math to get around it.

local value = 9.99e50
local storedValue = value ~= 0 and math.floor(math.log(value) / math.log(1.0000001)) or 0

print(storedValue) -> -- 1174308450
local value = ...
local retrievedValue = value ~= 0 and (1.0000001^value) or 0

print(retrievedValue) -- 9.9899995470475e+50

The idea is that you shrink the number and stretch it again afterwards, this WILL cause a loss in precision. But with huge numbers that are most likely rounded for leaderboards anyways that’s not an issue. The larger the number you’re trying to store the less precise it’ll be. So for smaller numbers it’ll be accurate.

You perform the first math operation and save the value to the DataStore, then when you load the value you perform the second math operation. Sorting will still work for this because the numbers still represent the original value correctly.

Also make sure not to pass 0 into the equation, or you’ll get a “division by 0” error. Hence why I used a ternary operator to make sure it’s not 0. Since 0 can just be stored and loaded as 0.

54 Likes

or as @1TheNoobestNoob has illustrated my point, but not noticed that

but as @Dysche mentioned , larger numbers for higher-level players rounded on the leaderboard shouldn’t have to matter either.

Just a thought, would you be able to use 0x numbers and binary?
I’m not certain if it’ll be ordered but it’s something you could try.

Wouldn’t work, theres no real way to get around it without either losing the sorting ability, precision or hitting the max value.

Interesting what kind of black magic is this?!

so you are certain that it can be used with OrderedDataStore?

ps (couldn’t careless about precision)

Yes, I use it for my games. Works perfectly. You can try it yourself by just putting in random numbers and manually sorting them to get an idea of how it works.

I figured out this answer with the help of some clever people in the Hidden Developers Discord server. I ran into the same issue a few weeks ago.

3 Likes

Thank you!

sounds very promising!

sadly I don’t know how to use an external database service

the method is also complex but seems like fun to work on but I’ll try Dysche’s method

1 Like

But that’s what we want,we’ll have to lose precision of the values,but that precision could be taken back with dividing/scaling numbers with a very large value before it is sent as a string, unless he’s not doing that in which case I don’t see a work around for the precision/sorting/cap problem

OrderedDataStore only accepts integer values, so the whole string idea wouldn’t work really. I’m assuming OP is trying to create a global leaderboard system so using normal DataStores wouldn’t work.

1 Like

So something like this?

Can you explain how math.log and math.log10 works for future reference?

Thank you, you are a saint!

Where have you been an hour ago?! :cold_sweat:

You could also store the integers in a similar format to floating points. Use the first 7 digits for the exponent, and the last 10 digits for the first 10 digits of the number being stored.

For example, the number
000000501234567890
Would represent the value
1,234,567,890 x 10^50
This is sorted correctly, as the exponent is listed first. Any number with a higher exponent will be greater than a number with a smaller one, and if the exponents are the same, the digits of the number are compared.

The advantage over Dysche’s method here is that it’s clear how many digits we have to work with (10,000,010), and we get exact precision for the displayed digits, though either system will work.


Edit: Thinking about it more, this option will also allow you to store the largest numbers for any given level of precision.
While Dysche’s representation provides more than enough digits for any reasonable situation (several million digit long numbers), it stores more information than is necessary (partially accurate information about unused placevalues). The floating point representation has exactly one representation for every value (within the given precision), and all possible representations correspond to a value, giving the maximum possible number of values for a given length representation.

For the level of precision he used (accurately storing the first 6~ digits), he could store 10,000,000x fewer digits than a floating point representation.
This is all useless trivia, but perhaps someone will want to store a value with 15 quintillion digits in an ordered datastore one day.

8 Likes

Yeah, that’d work as far as I can tell.

The log function is basically an inverse exponent, so you’re getting the original exponent back from the value. For example: 2^6 = 64, log2(64) = 6
Log10 is basically the log function for base 10. Like log(10, n) or 10^n inversed.

The number following log in lua basically stands for the base. You could also do log(x, y) in lua.

(This might seem like a too-simple explanation to the real mathheads reading this but this is a simplification.)

4 Likes

You save my life xD

I can finally have a leaderboard for my sim


local function Update()
    local success, err = pcall(function()
        
        local isAscending = false -- Top to bottom
        local Amount = 5 -- How many players you want
        local pages = WinsLeaderboard:GetSortedAsync(isAscending, Amount)
        local topAmount = pages:GetCurrentPage()
        

        for i,ImageLabel in pairs(Items:GetChildren()) do
            if ImageLabel:IsA("ImageLabel") then
                ImageLabel:Destroy()
            end
        end
        
        for rank, data in ipairs(topAmount) do
            local PlayerName = data.key
            local Gems = data.value
            local retrievedValue = Gems ~= 0 and (1.0000001^Gems) or 0

            print(retrievedValue) 
            
        end
    end)
end

function LeaderboardService:Start()
    while true do
        for _, player in pairs(game.Players:GetPlayers()) do
            local value = player.leaderstats.Gems.Value
            local storedValue = value ~= 0 and math.floor(math.log(value) / math.log(1.0000001)) or 0
            
            WinsLeaderboard:SetAsync(player.UserId, storedValue)
        end
        Update()

        

        wait(120)
    end
end

Sorry if its been a year, for some reason this still won’t work.

1 Like

NEVER MIND. THIS WORKED PERFECTLY. Thank You :D. Just a type for leaderstats.

Also if so why does other softwares have numbers exceeding that value? Almost every modern computor have an 64 bit processor and those processors would not be able to handle a roblox application in128 bit. So there are solution else that number would not be able to be saved used and displayed on computors which it can

Sorry to bump… but how would this work with smaller numbers?? If I store say 3, and try this I get

local value = 3
local retrievedValue = value ~= 0 and (1.0000001^value) or 0

print(retrievedValue)  -  Studio
 1.0000003000000302  -  Edit

and trying with larger numbers just results in inf…

  > local value = 1000000000000000000000
local retrievedValue = value ~= 0 and (1.0000001^value) or 0

print(retrievedValue)  -  Studio
  inf  -  Edit
1 Like

why would you want to deal with numbers this big to begin with