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 :slight_smile:

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 :smile:

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?:sob: