This is awesome, thanks so much for the warning this time. External services like RTrack could suffer from a change like this, luckily I don’t think there will be any problems as RTracks ids are always stored as 2^53.
No, it won’t. That’s not how datastores, or for that fact, lua works.
No, they’re on a different system and have already gone above 32 bit. There was an announcement about this quite a while back.
Wait a minute,
I was messing around in studio and trying to fix an old game
I was going to make a verification thing where it does
local EEE = p.UserId + p.UserId / 4
and it does it both clientside and serverside.
This would mean my system would not work on 32bit devices if I am correct
It would have to deal with numbers over the 32bit integer limit which would screw over my newest iPad.
Will this mess up systems like I am talking about with this update?
why the crazy oddly specific number of 2147483648?
Because computers work in a binary way (0 and 1s), it’s a 2 number-based system meaning that you only have the option to pick either 0 or 1. Roblox’s UserID worked as a 32-bit system meaning that it can compute up to 32 0s or 1s at once. And because binary operates differently than the decimal number system (which is a 10 number system), we can convert those bits into real numbers, giving you the exact number which is 2147483647.
Was there any reason to store IDs in signed ints in the first place? I can’t imagine that many people having negative user IDs.
because it is 2 to the power of 31 and computers like multiples of 8
Again, if you’re doing this in Lua, you won’t have any issues.
This would break even more things, and would not work in the case of username switches, and will require approximately 8x the storage requirements for user ids.
And have no way to determine who’s who? Right.
I wouldn’t be happy if I registered a new account that was banned from popular games, and developers ouldn’t be happy that users are just getting data from old members, and I don’t think the previous ID owner would be happy if I could see their Premium purchase history and payment details.
Roblox will test this by creating new accounts with those IDs.
And so this means we are not going to run out of usernames? really nice sytem tho. but i dont think roblox servers can handle this kinda high rate of accounts.
Maybe you can start purging inactive users and obvious spam/alt accounts that are just there to hog/save usernames. This would also open up more usernames for others to take as it is annoying seeing an inactive account have the username you really wanted. By inactive I mean made in 2011 and not touched since.
Curious, how would one store negative numbers for the ids? I could definitely see letters being helpful, as it would make it nearly impossible to run out of ids.
Players under 13 should use their mom or dads email address account, or if their parents allow them to have their own, they should do that
Children under 13 can’t have their own email accounts. It’s literally against the ToS of every single website, not to mention possibly being against COPPA and could land the parents in hot water.
All Lua numbers are standard IEEE 754 double precision floating point numbers, which you can read more about here. As others have stated, these can store every positive integer up to 2^53. It can precisely represent higher numbers as well (integers only), but there are gaps between them. After 2^53, every other integer can be represented precisely. After 2 ^ 54, we can represent every 4th integer, then every 8th integer after 2^55, and so on.
Doubles (Binary64’s) have 64 bits of data they can use to represent numbers, broken into 3 categories:
Here’s our pattern with the relevant data (exponent bits are the important bits here):
integer group | space between nums | exponent bits | total ints |
---|---|---|---|
2^51…2^52 - 1 | 0.5 | 10000110010 | 1 * 2^52 - 1 |
2^52…2^53 - 1 | 1 | 10000110011 | 2 * 2^52 - 1 |
2^53…2^54 - 1 | 2 | 10000110100 | 3 * 2^52 - 1 |
2^54…2^55 - 1 | 4 | 10000110101 | 4 * 2^52 - 1 |
2^55…2^56 - 1 | 8 | 10000110110 | 5 * 2^52 - 1 |
2^56…2^57 - 1 | 16 | 10000110111 | 6 * 2^52 - 1 |
2^57…2^58 - 1 | 32 | 10000111000 | 7 * 2^52 - 1 |
2^58…2^59 - 1 | 64 | 10000111001 | 8 * 2^52 - 1 |
2^59…2^60 - 1 | 128 | 10000111010 | 9 * 2^52 - 1 |
If you noticed the pattern, you can write an equation to relate the 2^integer to the space between integers by f(i) = ceil(2 ^ (i - 52))
where i
is a positive integer. You’ll also notice the exponent number is just incrementing by 1 with each step. This pattern will continue until it reaches 11111111111. To get the distance between this destination and, let’s say, 2^52 (pick any of them), which has 10000110011
in the exponent, we can just (binary) subtract: 11111111111 - 10000110011
, which gives us 1111001100
or 972
in decimal. We can then add 972 + 52
to get our total 2^i
value of 2^1024
being the number represented by 11111111111
in the exponent bits.
following | space between ints | exponent bits |
---|---|---|
2^1024 | 2 ^ (1024 - 52), approx. 3.99e+292 | 11111111111 |
However, in this case, IEEE 754 reserves numbers with all 1’s in the exponent bits for Infinity and NaN values. Hence:
> print(2^1024)
inf
> print(2^1023) -- the highest power of 2 representable by a double
8.9884656743116e+307
That means the highest possible integer we can represent is going to be the number directly below infinity. I.e. 2 ^ 1024 - 2 ^ (1023 - 52), which gives us ~1.797693134862316e+308. In binary, this looks like:
sign | exponent | fraction |
---|---|---|
0 | 11111111110 | 1111111111111111111111111111111111111111111111111111 |
And that’s the highest integer (directly under infinity) that can be represented by doubles.
To calculate how many positive integers (1 and up) can be precisely represented, we just do (1024 - 52 + 1) * 2^52 - 1
to get ~4.38e18, i.e. over 4 quintillion!
Now, the problem with this answer is that a lot of these numbers are too high to be converted to signed 64 bit integers, which can only go up to 2^63 - 1. Even still, limiting ourselves to numbers below 2^63 is given by (63 - 52 + 1) * 2^52 - 1
, which equals ~5.4e16 or 54 quadrillion.
For those of you scared that they had to raise the limit and are now simply “pushing back the problem”, keep in mind that there is an equal distance between the number of users it takes to break 32 bits and the user that fills 33 bits. And it will take twice as many accounts after that to fill 34 bits, 4 times as many to break 35, and so on until it takes 2^20 (about a million) times the number of accounts that exist right now to get from 52 bit to 53 bit integers, at which point we could have to start skipping every other id as I explained above. If they use the id-skipping method for UserId’s between [2^53, 2^64], then we could fill 2^31 UserId’s 25 million times!
Suffice to say, there will be plenty of time to upgrade double-precision numbers to quad-precision numbers in the time it takes to get to that point. Unless, of course, aliens come by and hook us up to the intergalactic outernet and Roblox becomes super popular across the galaxy in a matter of months. That would be quite a shock to the platform.
Thanks for reading! I used baseconvert.com/ieee-754-floating-point for a binary visualizer for double precision floating point numbers.
Guests had negative user IDs when they were around.
Hi, @TobotRobot.
It is slightly off topic but I would like to mention that over time UserIds could become a problem for DataStore with UserIds over 50 characters and MessagingService with many long UserIds that are over 1000 characters when combined.
(this shouldn’t be a problem for while though)
The smallest 50 digit UserId (the first number above 1e49 that is precisely representable by double precision floating points) is given by:
let x = 1e49,
let y = floor(log_2(x)),
answer: 2^y + ceil((x - 2^y) / 2^(y - 52)) * 2^(y - 52)
Simplified:
2^162 + ceil((1e49 - 2^162) / 2^110) * 2^110
10000000000000000762976984109188700329496497094656
(above 2^112)
According to my math, that happens to be around the five hundred quadrillionth representable positive integer (5e17 > 2^58). We’d have to fill our old threshold of 2^31 UserId’s 234 million times to get there!
Although if we constrain our UserId’s to only go as high as the highest representable number below 2^63 for signed 64 bit integers (which for doubles is 2^63 - 1024), that’s 9223372036854774784
, which is 19 characters long. This constraint is applicable in Lua, e.g. when using string.format
with “%d”.
-- Note that between [2^62, 2^63] we can only exactly represent every 1024
-- Thus this is the highest number that we can map to a signed 64 bit integer
print(string.format("%d", 2^63 - 1024)) --> 9223372036854774784
-- The next number overflows!
print(string.format("%d", 2^63)) --> -9223372036854775808
We’d have to fill our old threshold of 2^31 UserId’s 25 million times! Trust me, it’s going to take a while!
This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.