Making large numbers readable

I’ve written a function that is supposed to shorten numbers starting from thousands with suffixes like k, m ,b, t. When I give 1000 as a argument, it outputs 10k which is incorrect. My brain is not functioning correctly as it is late in the night for me, I would appreciate if someone could tell me where my math went wrong.

local function a(n)
	local suffixes = {"k","m","b","t","qd","qt"}
	n = tostring(n)
	local digits = #n
	print(digits)
	if digits - 1 >= 3 then
		local suffix_num = math.floor((digits-1)/3)
		return tostring(math.floor(tonumber(n)/(10^(digits-3))/10))..suffixes[suffix_num]
	end
end
5 Likes
return tostring(math.floor(tonumber(n)/(10^(suffix_num*3))))..suffixes[suffix_num]

You need to divide by 10^(suffix_num*3).
For example:
1000, suffix 1, divide by 10^3 => 1
23456789, suffix 2, divide by 10^6 => 23

3 Likes

Oh, sorry, I was meant to also say that it was supposed to be to one decimal place.

Then divide by 10^(suffix*3-1) inside the floor, and divide by an additional 10 outside the floor.

return tostring(math.floor(tonumber(n)/(10^(suffix_num*3-1)))/10)..suffixes[suffix_num]
3 Likes

Here’s another, slightly more flexible way of doing it. It also allows you to have decimals and suffixes, to have e.g. 5.31 M, giving the user slightly more information.

function floorTo(n, to)
    return math.floor(n/to)*to
end

function formatNumberSuffixes(n)
    local expSuffixes = {{-3, 'm'}, {-2, 'c'}, {0, ''}, {3, 'k'}, {6, 'M'}, {9, 'B'}}
    local lowestExponent = -6
    local highgestExponent = math.floor(math.log(n, 10))
    
    local suffix, exponent, prevExponent = '', lowestExponent, lowestExponent
    for _, expSuffix in pairs(expSuffixes) do
        if expSuffix[1] <= highgestExponent then
            prevExponent = exponent
            exponent = expSuffix[1]
            suffix = expSuffix[2]
        end
    end
    
    local nSignificant = floorTo(n, 10^prevExponent)
    local formatted = tostring( nSignificant / (10^(exponent)) )
    
    repeat
        local lastChar = formatted:sub(formatted:len())
        if lastChar == '0' or lastChar == '.' then
            formatted = formatted:sub(1, formatted:len()-1)
        end
    until lastChar ~= '0' and lastChar ~='.'
    return formatted .. " " .. suffix
end

And a snippet for testing it

for exp = -3, 10 do
    local n = 10^exp
    if exp > 0 then
        n = n + floorTo(math.random()*10^exp, 10^-1)
    elseif exp < 0 then
        n = n + floorTo(math.random()*10^exp, 10^(exp-2))
    end
    local nFormatted = formatNumberSuffixes(n)   
    print(n .. " m =>", nFormatted .. "m")
end

To be clear it’s not better than the earlier reply, I just wanted to play around with the idea and this is what I got.

Also, if you want to work really big numbers (> 2^32) you’ll need to find a bignum library for Lua.