Most efficient way of converting a number in scientific notation into a Suffix and back?

I am trying to convert a number into a suffix as well as being able to unpack a suffix.
Example : 1 * 10^6 -> 1M
Example: 1B -> 10^9

The only knowledge I currently know is using if and elseif statements (which would be highly inefficient and unclean) to pack it into a suffix, but I have no clue on how I would be able to unpack a suffix.

Every post is Appreciated! :slightly_smiling_face:

2 Likes

Maybe something like this?

local Suffixes = {"K", "M", "B", "T", "Q"}

local function GetSuffix(Input)
    local Base, Exponent = string.match(Input, "(%d+)^(%d+)") -- get the seperate numbers
    Base, Exponent = tonumber(Base), tonumber(Exponent)
    if not Base or not Exponent then return end

    local Index = math.floor(Number / 3) -- get the size of the number it is (hundred, thousand, million, etc.)
    return (Base/10)..Suffixes[Index] -- return the result
end

print(GetSuffix("10^6")) -- 10M

My code is untested btw lol

To do it the other way, you’d simply reverse the operations. i.e. Multiply base by 10, get the exponent

6 Likes

Updated Post: January 2nd, 2021

@VitalWinter made a pretty good suggestion, so I’ve rewritten the code to introduce this and made some additional improvements:

local suffixes = {"K", "M", "B", "T", "Q"} -- numbers don't go higher than 'Q' in Lua.

local function toSuffixString(n)
	local i = math.floor(math.log(n, 1e3))
	local v = math.pow(10, i * 3)
	return ("%.1f"):format(n / v):gsub("%.?0+$", "") .. (suffixes[i] or "")
end

Then, if you want to convert back:

local function fromSuffixString(s)
	local n, suffix = string.match(s, "(.*)(%a)$")
	if n and suffix then
		local i = table.find(suffixes, suffix) or 0
		return tonumber(n) * math.pow(10, i * 3)
	end
	return tonumber(s)
end

Original Post: September 12th, 2018

Personally I would do the following for converting a number to a string with a suffix.

local suffixes = {"K", "M", "B", "T", "Q", "Qu", "S", "Se", "O", "N", "D"}

local function toSuffixString(n)
	for i = #suffixes, 1, -1 do
		local v = math.pow(10, i * 3)
		if n >= v then
			return ("%.0f"):format(n / v) .. suffixes[i]
		end
	end
	return tostring(n)
end

While to do the reverse you could do something such as

local function fromSuffixString(s)
	local v, suffix = s:match("(%d+)(.*)")
	for i = 1, #suffixes do
		if suffixes[i] == suffix then
			return tonumber(v) * math.pow(10, i * 3)
		end
	end
	return tonumber(v)
end
46 Likes

Thanks for the quick replies!

Oops clicked Send by accident way too early.

I’ve tested your code to see which one would help.

@woot3 yours seems to have worked but when I tried inputting 1500000 (1.5 Million), it came out as 2 million. I don’t want to be confusing players so decimals would be fine in this case.

1 Like

If you change the following line

return ("%.0f"):format(n / v) .. suffixes[i]

to the following then you’ll be able to show numbers to 1 decimal place.

return ("%.1f"):format(n / v) .. suffixes[i]

Generally I think it’s a good idea to round your numbers at some point to keep your strings short.

6 Likes

Also please make sure you do NOT do the converting from suffix form part (at least if you are trying to actually store or read data accurately). I am pretty sure you will not need it because of the rounding, but just as a precaution you do not want to have a constant 1.1B because you cannot round up fast enough before you leave.

2 Likes

Pretty sure I fixed it now, it was an issue with string.match. FYI you should learn to debug stuff like this yourself so we only have to show you what you need to do – that’s kind of what programming is about anyway (problem solving) :slight_smile:

2 Likes

Instead of iterating through suffixes, you could check if a suffix exists at this index:

math.floor(math.log(n,1000))
1 Like

How would I do that for a gui? This is the code I have in my gui:

script.Parent.Text = game.Players.LocalPlayer.leaderstats.Cash.Value

while true do

wait(0.1)

script.Parent.Text = game.Players.LocalPlayer.leaderstats.Cash.Value

end

Try something like

local suffixes = {"K", "M", "B", "T", "Q", "Qu", "S", "Se", "O", "N", "D"}

local function toSuffixString(n)
	for i = #suffixes, 1, -1 do
		local v = math.pow(10, i * 3)
		if n >= v then
			return ("%.0f"):format(n / v) .. suffixes[i]
		end
	end
	return tostring(n)
end

script.Parent.Text = toSuffixString(game.Players.LocalPlayer.leaderstats.Cash.Value)

and also don’t use

because it can be optimised more with the code below that only runs whenever a change is made to the cash value

game.Players.LocalPlayer.leaderstats.Cash.Changed:Connect(function()
   script.Parent.Text = toSuffixString(game.Players.LocalPlayer.leaderstats.Cash.Value)
end)
2 Likes

That’s pretty sensible. There are definitely some other things which could be improved so I’ll update the code.

local suffixes = {"K", "M", "B", "T", "Q"} -- numbers don't go higher than 'Q' in Lua.

local function toSuffixString(n)
	local i = math.floor(math.log(n, 1e3))
	local v = math.pow(10, i * 3)
	return ("%.1f"):format(n / v):gsub("%.?0+$", "") .. (suffixes[i] or "")
end

This version rounds to one decimal place and removes trailing zeros after the decimal point which should result in better looking numbers.

Here’s the updated counterpart:

local function fromSuffixString(s)
	local n, suffix = string.match(s, "(.*)(%a)$")
	if n and suffix then
		local i = table.find(suffixes, suffix) or 0
		return tonumber(n) * math.pow(10, i * 3)
	end
	return tonumber(s)
end
1 Like

Hey, I know this is an old topic, but I’m having a small issue.

toSuffixString(1157)

would return “1.2K” instead of “1.1K”. Is there a way I can change this?

the usage of %.1f rounds the decimal automatically, in that case it went up

you can replace

("%.1f"):format(n / v)

with

("%f"):format(math.floor(n / v * 10) / 10)

this lets you do the rounding yourself, but only by rounding down

2 Likes