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+
]]