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?
Preforming Decimals to Numbers?
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
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
Change line 4
Haha thanks accidentally put k instead of M
It shows way to many decimals. Is there anyway to make it just 1 decimal? 1.7k not 1.748k?
You could make a rounding function, which is a bit challenging.
Hold on updating edit
actually do it yourself im tired lol
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.

3 comments
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?
Oops, you're right. Let me check string formatting rules
EDIT: I included a new "shortenDecimal" which includes the logic for whole-numbers!