Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Preforming Decimals to Numbers?

Asked by 8 years ago

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

Log in to vote
2
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
8 years ago

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
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? peoplemove12 148 — 8y
0
Oops, you're right. Let me check string formatting rules BlueTaslem 18071 — 8y
0
EDIT: I included a new "shortenDecimal" which includes the logic for whole-numbers! BlueTaslem 18071 — 8y
Ad
Log in to vote
1
Answered by
KoreanBBQ 301 Moderation Voter
8 years ago

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
0
Change line 4 funyun 958 — 8y
0
Haha thanks accidentally put k instead of M KoreanBBQ 301 — 8y
0
It shows way to many decimals. Is there anyway to make it just 1 decimal? 1.7k not 1.748k? peoplemove12 148 — 8y
0
You could make a rounding function, which is a bit challenging. funyun 958 — 8y
View all comments (3 more)
0
Hold on updating edit KoreanBBQ 301 — 8y
0
actually do it yourself im tired lol KoreanBBQ 301 — 8y
0
This is backwards. BlueTaslem 18071 — 8y
Log in to vote
0
Answered by
funyun 958 Moderation Voter
8 years ago

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

Answer this question