How do I shorten this numbers?

So this is my number Abbreviation Module…

``````local AbbreviateNumber = {}

local abbreviations = {
K = 4,
M = 7,
B = 10,
T = 13,
QD = 16,
QT = 19,
SXT = 22,
SEPT = 25,
OCT = 28,
NON = 31,
DEC = 34,
UDEC = 37,
DDEC = 40
}

function AbbreviateNumber.Abbreviate(Number)

local Text = tostring(math.floor(Number + 0.5)) -- rounds to nearest whole number

-- We can find the numbers of characters in a text by doing #Text , where "Text" is the text you are using
if #Text > 4 then
Text = Text:sub(1, #Text-4)
for Letter, Number in pairs(abbreviations) do
if Number <= #Text and Number+3 > #Text then
if Number == #Text then Number = #Text-1 end
Text = Text:sub(1, #Text-Number) -- We get the digits that we need in order to shorten the text
Text = Text .. Letter .. "+" -- This will be the shortened version
break
end
end
end

return Text
end

return AbbreviateNumber
``````

Small numbers (under e+15 is fine) but when I call that function and told it to abbreviate lets say , 9e+306 .
My module return string that is so far off. I think the problem is because my module is calculating the text length.

``````local m = require(game.ReplicatedFirst.Abriviate)

local value = 9e+306

local storedValue = value ~= 0 and math.floor(math.log(value) / math.log(1.0000001)) or 0 ---- (FOR DATASTORE)

local retrievedValue = storedValue ~= 0 and (1.0000001^storedValue) or 0 ---- (FOR INGAME)

print(m.Abbreviate(retrievedValue))
``````

that is a server script calling that module tu abbreviate retrievedValue.
It returns 8QD+ which is so far off.

Can someone help me figure this out?

2 Likes

You could try getting the number of digits with `math.floor(math.log10(Number))` instead, not sure if that’s your problem or not.

Edit: also `tostring` will give you the actual `"9e306"` string, which is not what you want.

1 Like

You’re using numbers that Lua cannot represent because they’re so large. The highest you can go is around `4.5e15` according to this:

There are “bignum” libraries that let you use bigger numbers.

1 Like

You can represent up to 1.7e308 in roblox technically, but the integers stop being completely represented around where you said.

To use BigNums, DO NOT use any intvalues/numbervalues. Instead, you could use a stringvalue, turn it to a number using tonumber() and abbreviate it.
Here’s more about strings.
or
Use a remotefunction from client that’s requesting player stats each 1/30th second( while true do with a wait()) and abbreviate it.

First method will permit you to use .Changed so I recommend you doing it.

1 Like

This problem was interesting so I had a go. The trick is to use the number and do math, rather than trying to work with strings. Removed the loops too

``````local abbreviations = {
"K", -- 4 digits
"M", -- 7 digits
"B", -- 10 digits
"T", -- 13 digits
"QD", -- 16 digits
"QT", -- 19 digits
"SXT", -- 22 digits
"SEPT", -- 25 digits
"OCT", -- 28 digits
"NON", -- 31 digits
"DEC", -- 34 digits
"UDEC", -- 37 digits
"DDEC", -- 40 digits
}

local function Abbreviate(x)
if x < 1000 then
return tostring(x)
end

local digits = math.floor(math.log10(x)) + 1
local index = math.min(#abbreviations, math.floor((digits - 1) / 3))
local front = x / math.pow(10, index * 3)

return string.format("%i%s+", front, abbreviations[index])
end
``````
Results
``````print(Abbreviate(9e2)) --> 900
print(Abbreviate(9e3)) --> 9K+
print(Abbreviate(9e4)) --> 90K+
print(Abbreviate(9e5)) --> 900K+
print(Abbreviate(9e6)) --> 9M+
print(Abbreviate(9e8)) --> 900M+
print(Abbreviate(9e12)) --> 9T+
print(Abbreviate(9e15)) --> 9QD+
print(Abbreviate(9e16)) --> 90QD+
print(Abbreviate(9e17)) --> 900QD+
print(Abbreviate(9e18)) --> 9QT+
print(Abbreviate(9e19)) --> 90QT+
print(Abbreviate(9e20)) --> 900QT+
print(Abbreviate(9e23)) --> 900SXT+
print(Abbreviate(9e26)) --> 900SEPT+
print(Abbreviate(9e29)) --> 900OCT+
print(Abbreviate(9e32)) --> 900NON+
print(Abbreviate(9e35)) --> 900DEC+
print(Abbreviate(9e38)) --> 899UDEC+ (floating point precision whatcha gonna do)
print(Abbreviate(9e39)) --> 9DDEC+
print(Abbreviate(9e41)) --> 900DDEC+
print(Abbreviate(9e42)) --> 9000DDEC+
print(Abbreviate(9e43)) --> 90000DDEC+
print(Abbreviate(9e44)) --> 900000DDEC+
``````
17 Likes

Really nice function. Could you remake the function where you can also have decimal places
For example
Decimal places : 1
5500 → 5.5k
15500 → 15.5k
Decimal places : 3
5520 → 5.520k
15500 → 15.500k

Not as elegant as it could be, but here’s a quick solution:

``````local abbreviations = {
"K", -- 4 digits
"M", -- 7 digits
"B", -- 10 digits
"T", -- 13 digits
"QD", -- 16 digits
"QT", -- 19 digits
"SXT", -- 22 digits
"SEPT", -- 25 digits
"OCT", -- 28 digits
"NON", -- 31 digits
"DEC", -- 34 digits
"UDEC", -- 37 digits
"DDEC", -- 40 digits
}

local function Abbreviate(x, decimals)
if decimals == nil then decimals = 0 end
local visible = nil
local suffix = nil
if x < 1000 then
visible = x * math.pow(10, decimals)
suffix = ""
else
local digits = math.floor(math.log10(x)) + 1
local index = math.min(#abbreviations, math.floor((digits - 1) / 3))
visible = x / math.pow(10, index * 3 - decimals)
suffix = abbreviations[index] .. "+"
end
local front = visible / math.pow(10, decimals)
local back = visible % math.pow(10, decimals)

if decimals > 0 then
return string.format("%i.%0." .. tostring(decimals) .. "i%s", front, back, suffix)
else
return string.format("%i%s", front, suffix)
end
end
``````
Results
``````-- tests
function test(x, decimals, expected)
local res = Abbreviate(x, decimals)
print(tostring(x), "to " .. tostring(decimals) .. " places ->", res)
assert(res == expected)
end

test(0, nil, "0")
test(0, 4, "0.0000")
test(1001, 2, "1.00K+")
test(1001, 3, "1.001K+")
test(100234, 2, "100.23K+")
test(1002345678, 2, "1.00B+")
test(1.23456789e35, nil, "123DEC+")
test(1.23456789e35, 2, "123.45DEC+")
test(1.23456789e44, 2, "123456.78DDEC+")

--[[ results:
0   to nil places ->    0
0   to 4 places ->  0.0000
1001    to 2 places ->  1.00K+
1001    to 3 places ->  1.001K+
100234  to 2 places ->  100.23K+
1002345678  to 2 places ->  1.00B+
1.23456789e+35  to nil places ->    123DEC+
1.23456789e+35  to 2 places ->  123.45DEC+
1.23456789e+44  to 2 places ->  123456.78DDEC+
]]
``````
7 Likes

I modified this in order to remove some of the decimals if its not needed:

``````local abbreviations = {
"K", -- 4 digits
"M", -- 7 digits
"B", -- 10 digits
"T", -- 13 digits
"QD", -- 16 digits
"QT", -- 19 digits
"SXT", -- 22 digits
"SEPT", -- 25 digits
"OCT", -- 28 digits
"NON", -- 31 digits
"DEC", -- 34 digits
"UDEC", -- 37 digits
"DDEC", -- 40 digits
}

local function _backend(x, decimals)
if decimals == nil then decimals = 0 end
local digits = math.floor(math.log10(x)) + 1
local index = math.min(#abbreviations, math.floor((digits - 1) / 3))
local visible = x / math.pow(10, index * 3 - decimals)
local suffix = abbreviations[index] .. "+"

local front = visible / math.pow(10, decimals)
local back = visible % math.pow(10, decimals)

if decimals > 0 and back > 0 then
return string.format("%i.%0." .. tostring(decimals) .. "i%s", front, back, suffix)
else
return string.format("%i%s", front, suffix)
end
end

local function Abbreviate(x, decemals)
if x < 1000 then
return tostring(x)
end

return _backend(x, (decemals or 2))
end
``````

(TESTS)

``````Abbreviate(0, 4) -- returns "0"
Abbreviate(1000, 2) -- returns "1K+"
Abbreviate(1001, 2) -- returns "1.00K+"
Abbreviate(1001, 3) -- returns "1.001K+"
``````

I’m not sure which discrepancies you’re referring to—that is not how I intended the function to work, you can see what I intended the results to be in the `> Results` part.

I like your modification, it’s just trying to do something different.

1 Like

There is already a really good module for this made by @berezaa for Miner’s Haven, which was open sourced a few years ago

1 Like

Thank you so much for this! This was exactly what I was looking for!

2 Likes

hi, I put your script in my ranking but I don’t like it, do you know why?

i know a lot time gone but what did u want to do with it?