Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Preforming Decimals to Numbers?

Is it possible to get the numbers over 1k, 10k, 100k, 1M, and so on to have decimals and be coded more efficient instead of 'if value > 1000 then text = "1k"'. Also having decimals as in 1.1k and 101k?

3 answers

This is a similar problem to writing the decimal in exponential notation. How would we do that?

We can get the number of digits on (positive) numbers using math.log10:

math.log10(1) -- 0
math.log10(2) -- 0.30102999566398
math.log10(9.99) -- 0.99956548822598
math.log(10) -- 1
math.log(11) -- 1.04139
math.log(150) -- 2.17609

The number of digits is the whole-number-part of the base-10 log. We can get the whole-number-part with math.floor

Thus the exponential part would be exp = 10^math.floor( math.log10(n) ). The fractional part would be n / exp:

function exponential(n)
	local power = math.floor( math.log10(n) )
	local exp = 10 ^ power
	return (n / exp) .. "e" .. power
end

print(exponential(101000))
-- 1.01e5

But what if we want to limit the number of digits that will be after the exponent? E.g., math.pi will produce 3.1415926535898e0. We just need to format the n / exp part using string.format:

function exponential(n)
	local power = math.floor( math.log10(n) )
	local exp = 10 ^ power
	return string.format("%.1f", n / exp) .. "e" .. power
end

print(exponential(math.pi))
-- 3.1e0

EDIT: A problem is exponential(1). It'll respond 1.0e0 rather than 1e0. I don't think Lua has this exactly built-in, so we have to do it ourself. Luckily, it's not too bad:

function shortenDecimal(n)
	if n == math.floor(n) then -- no fractional part
		return tostring(n)
	else
		return string.format("%.1f", n)
	end
end

function exponential(n)
	local power = math.floor( math.log10(n) )
	local exp = 10 ^ power
	return shortenDecimal(n / exp) .. "e" .. power
end

This is close to what we want.

If the power is 3, we would just want to show "k" instead of "e3". If it was 6, we would want "M", etc.

But if the power is 4, we want to adjust to be 3 -- 10.1k instead of 1.01e4 (note the extra digit before the decimal). We can get this pretty easily using % (mod) -- remainder after division.

Mod is frequently used to "trim off" "extra" amounts. Since we only want clean multiples of three...

power - power % 3 will cut off the extra:

function formatted(n)
	local power = math.floor( math.log10(n) )
	power = power - power % 3
	local exp = 10 ^ power
	return shortenDecimal(n / exp) .. "e" .. power
end

print(formatted(123456)) -- 123.5e3

Finally, we need to show something instead of e3. We could either use power / 3 + 1 to get a list:

number power list index
1 0 1
1000 3 2
1000000 6 3
function formatted(n)
	local names = {"", "k", "M", "B", "T"}
	local power = math.floor( math.log10(n) )
	power = power - power % 3
	local exp = 10 ^ power
	return shortenDecimal(n / exp) .. names[power / 3 + 1]
end

print(formatted(123456))
-- 123.5k

We could also have used a dictionary:

function formatted(n)
	local name = {[0] = "", [3] = "k", [6] = "M", [9] = "B", [12] = "T"}
	local power = math.floor( math.log10(n) )
	power = power - power % 3
	local exp = 10 ^ power
	return shortenDecimal(n / exp) .. named[power]
end

3 comments

1

Wow, this is some amazing put together math. What about 0? If I have a value of 50 or 100. It shows up as 50.0 or 100.0?

0

Oops, you're right. Let me check string formatting rules

0

EDIT: I included a new "shortenDecimal" which includes the logic for whole-numbers!

You could easily do that with dividing.

Just do:

if number>1000 then
text=tostring(number/1000).."k"
elseif number>10^6 then
text=tostring(number/10^6).."M"
end

7 comments

0

Change line 4

0

Haha thanks accidentally put k instead of M

0

It shows way to many decimals. Is there anyway to make it just 1 decimal? 1.7k not 1.748k?

0

You could make a rounding function, which is a bit challenging.

0

Hold on updating edit

0

actually do it yourself im tired lol

0

This is backwards.

Following KoreanBBQ's answer, I made a rounding function. It doesn't work as intended when deaing with negative numbers, but otherwise it's pretty stable.

number = 123456789
text = ""

function round(number, places)
	if number == math.floor(number) or places < 1 or places ~= math.floor(places) then return number end
	
	local whole, fractional = math.modf(number)
	fractional = tostring(fractional)
	
	local changing = string.sub(fractional, places + 2, places + 2)
	changing = tonumber(changing)
	
	local nextnumber = string.sub(fractional, places + 3, places + 3)
	nextnumber = tonumber(nextnumber)
	
	if nextnumber >= 5 then
		changing = changing + 1
	end
	
	changing = tostring(changing)
	
	fractional = string.sub(fractional, 1, places + 2)
	fractional = string.gsub(fractional, string.sub(fractional, places + 2, places + 2), changing)
	fractional = tonumber(fractional)
	
	return whole + fractional
end


if number > 1000 and number < 10^6 then
	text = round(number/1000, 1).."k"
elseif number > 10^6 then
	text = round(number/10^6, 1).."M"
end

This discussion is preserved as it was. New answers, comments, and votes are closed.