Large numbers messing up? - lua

Sorry about the bad title, I couldn't think of anything better. So I was making a function to shorten numbers(1000 to 1k) and here it is.
local letters = {
"K",
"M", --I'm too lazy to put more
"B",
"QD",
"QN",
}
local nums = {}
for q=1,#letters do
local dig = (q*3)+1
local letter = 1*(10^(dig-1))
table.insert(nums,#nums+1,letter)
end
function shorten(num)
local len = tostring(num):len()
print(len)
if len>=4 then
for q=1,#letters do
local dig = (q*3)+1 --digits the letter is
if len <= dig+2 then
local toDo = math.floor(num/nums[q])
print(nums[q])
local newNum = toDo..letters[q]
return newNum
end
end
end
end
print(shorten(178900000000000))
And this prints.
10 --the length, and the real length of it is 15
1000000000 --the one to divide it
178900B --shortened num
I take one zero off of the print(shorten()) and it works fine. And I'm assuming the numbers are too big, or maybe there's a problem with the code. Thank you for reading this.

tostring gives the human-readable string representation, and for a big number like in your example, it uses scientific notation:
print(tostring(178900000000000))
In Lua 5.2 or lower, the result if 1.789e+14. In Lua 5.3, because of the newly introduced integer subtype, the result is 178900000000000 as expected, but it would still be broken for even bigger integers.

Related

What is the fastest way to go through an array / table with numeric indices?

If i have an array with numbered indices in lua and need to go through every entry at least once, is it faster to use a numeric for loop or a generic for loop?
Semantical Difference
for i = 1, #t do end
is not the same as
for i, v in ipairs(t) do end
the latter does not rely on #t and respects the __ipairs metamethod (although this is deprecated and the __index and __newindex metamethods should be used instead).
Assuming no metamethods are set, ipairs will simply loop until it encounters a nil value. It is thus roughly equivalent to the following loop:
local i, v = 1, t[v]
while v ~= nil do --[[loop body here]] i = i + 1; v = t[i] end
This means there are two things it doesn't have to do:
It does not determine the length. It won't call a __len metamethod if set. This might theoretically result in a better performance for lists which reside in the hash part (where Lua has to determine the length through a search). It could also improve performance in cases where the __len metamethod does costly counting.
It does not have to loop over nil values. The numeric for loop on the other hand might loop over arbitrarily many nil values due to how the length operator is defined: For a table {[1] = 1, [1e9] = 1}, both 1 and 1e9 are valid values for the length. This also means it's unclear what it does, as the exact length value is unspecified.
The latter point in particular means that in pathological cases, the numeric for loop could be arbitrarily slower. It also allows for mistakes, such as looping over (possibly long) strings instead of tables, and won't trigger an error:
local str = "hello world"
for i = 1, #str do local v = str[i] end
will loop over only nil values (as it indexes the string metatable) but throw no error.
I also consider ipairs to be more readable as it makes the intent clear.
Performance Difference
For non-pathological cases (lists residing in the list part, no "holes" (nil values), no odd metatables), the numeric for loop can be expected to run marginally faster, as it does not incur the call overhead of the for generic loop you'd be using with ipairs. This ought to be benchmarked on different Lua implementations though:
PUC Lua 5.1 to 5.4
LuaJIT 2.1.0
In practice, the costs of looping will often be negligible compared to the cost of the operations performed within the loop body. Results may vary depending on other factors such as operating system or hardware.
Rudimentary Benchmarks
print(jit and jit.version or _VERSION)
-- Fill list with 100 million consecutive integer values
a = {}
for i = 1, 1e8 do a[i] = i end
local function bench(name, func)
func() -- "warmup"
local t = os.clock()
for _ = 1, 10 do func() end
print(name, os.clock() - t, "s")
end
bench("numeric", function()
for i = 1, #a do
local v = a[i]
end
end)
bench("ipairs", function()
for i, v in ipairs(a) do end
end)
Conducted on a Linux machine.
Lua 5.1
numeric 54.312082 s
ipairs 63.579478 s
Lua 5.2
numeric 20.482682 s
ipairs 32.757554 s
Lua 5.3
numeric 14.81573 s
ipairs 23.121844 s
Lua 5.4
numeric 11.684143 s
ipairs 24.455616 s
Finally, LuaJIT:
LuaJIT 2.1.0-beta3
numeric 0.567874 s
ipairs 0.70047 s
Conclusion: Use LuaJIT if possible and stop worrying about micro-optimizations such as ipairs vs. numeric for (even though the latter may be slightly faster). Something as simple as an assert(i == v) will already cost as much as the loop itself (even if assert is local).
In this exact case it would be faster to use a numeric for loop. But not by much and in my testing it is more prone to load differences on my system.
Numeric Loop
a = {} -- new array
for i = 1, 10000000 do
a[i] = 10000000 + i
end
local startNumLoop = os.time(os.date("!*t"))
for i = 1, #a, 1 do
local value = a[i]
end
local stopNumLoop = os.time(os.date("!*t"))
local numloop = stopNumLoop - startNumLoop
print(os.clock())
Result: 1.379 - 1.499
Generic Loop
a = {} -- new array
for i = 1, 10000000 do
a[i] = 10000000 + i
end
local startGenLoop = os.time(os.date("!*t"))
for index, value in ipairs(a) do
end
local stopGenLoop = os.time(os.date("!*t"))
local genLoop = stopGenLoop- startGenLoop
print(os.clock())
Result: 1.568 - 1.662
Tested with lua 5.3.6 win32 binarys from lua.org
This was just a question i had where i didn't find the answer fast enough. If it is in fact a duplicate feel free to mark it so. :)
Especially for loops where is necessary to remove/change the current key/value pair i prefer the fast countdown method...
for i = #tab, 1, -1 do
if (tab[i].x > x) then
table.remove(tab, i) -- See comments
end
end
...for example in LÖVE [love2d] between two frames.

Convert Table Elements to Integers

I'm trying to create a list of integers, similar to python where one would say
x = input("Enter String").split() # 1 2 3 5
x = list(map(int,x)) # Converts x = "1","2",3","5" to x = 1,2,3,5
Here's my code asking for the input, then splitting the input into a table, i need help converting the contents of the table to integers as they're being referenced later in a function, and i'm getting a string vs integer comparison error. I've tried changing the split for-loop to take a number but that doesn't work, I'm familiar with a python conversion but not with Lua so I'm looking for some guidance in converting my table or handling this better.
function main()
print("Hello Welcome the to Change Maker - LUA Edition")
print("Enter a series of change denominations, separated by spaces")
input = io.read()
deno = {}
for word in input:gmatch("%w+") do table.insert(deno,word) end
end
--Would This Work?:
--for num in input:gmatch("%d+") do table.insert(deno,num) end
Just convert your number-strings to numbers using tonumber
local number = tonumber("1")
So
for num in input:gmatch("%d+") do table.insert(deno,tonumber(num)) end
Should do the trick

Find all upper/lower/mixed combinations of a string

I need this for a game server using Lua..
I would like to be able to save all combinations of a name
into a string that can then be used with:
if exists (string)
example:
ABC_-123
aBC_-123
AbC_-123
ABc_-123
abC_-123
etc
in the game only numbers, letters and _ - . can be used as names.
(A_B-C, A-B.C, AB_8 ... etc)
I understand the logic I just don't know how to code it:D
0-Lower
1-Upper
then
000
001
etc
You can use recursive generator. The first parameter contains left part of the string generated so far, and the second parameter is the remaining right part of the original string.
function combinations(s1, s2)
if s2:len() > 0 then
local c = s2:sub(1, 1)
local l = c:lower()
local u = c:upper()
if l == u then
combinations(s1 .. c, s2:sub(2))
else
combinations(s1 .. l, s2:sub(2))
combinations(s1 .. u, s2:sub(2))
end
else
print(s1)
end
end
So the function is called in this way.
combinations("", "ABC_-123")
You only have to store intermediate results instead of printing them.
If you are interested only in the exists function then you don't need all combinations.
local stored_string = "ABC_-123"
function exists(tested_string)
return stored_string:lower() == tested_string:lower()
end
You simply compare the stored string and the tested string in case-insensitive way.
It can be easily tested:
assert(exists("abC_-123"))
assert(not exists("abd_-123"))
How to do this?
There's native function in Lua to generate all permutations of a string, but here are a few things that may prove useful.
Substrings
Probably the simplest solution, but also the least flexible. Rather than combinations, you can check if a substring exists within a given string.
if str:find(substr) then
--code
end
If this solves your problem, I highly reccomend it.
Get all permutations
A more expensive, but still a working solution. This accomplishes nearly exactly what you asked.
function GetScrambles(str, tab2)
local tab = {}
for i = 1,#str do
table.insert(tab, str:sub(i, i))
end
local tab2 = tab2 or {}
local scrambles = {}
for i = 0, Count(tab)-1 do
local permutation = ""
local a = Count(tab)
for j = 1, #tab do
tab2[j] = tab[j]
end
for j = #tab, 1, -1 do
a = a / j
b = math.floor((i/a)%j) + 1
permutation = permutation .. tab2[b]
tab2[b] = tab2[j]
end
table.insert(scrambles, permutation)
end
return scrambles
end
What you asked
Basically this would be exactly what you originally asked for. It's the same as the above code, except with every substring of the string.
function GetAllSubstrings(str)
local substrings = {}
for i = 1,#str do
for ii = i,#str do
substrings[#substrings+1]=str:sub(ii)
end
end
return substrings
end
Capitals
You'd basically have to, with every permutation, make every possible combination of capitals with it.
This shouldn't be too difficult, I'm sure you can code it :)
Are you joking?
After this you should probably be wondering. Is all of this really necessary? It seems like a bit much!
The answer to this lies in what you are doing. Do you really need all the combinations of the given characters? I don't think so. You say you need it for case insensitivity in the comments... But did you know you could simply convert it into lower/upper case? It's very simple
local str = "hELlO"
print(str:lower())
print(str:upper())
This is HOW you should store names, otherwise you should leave it case sensitive.
You decide
Now YOU pick what you're going to do. Whichever direction you pick, I wish you the best of luck!

How does math.random work with exponents work in Lua?

I am trying to get a random 16 digit number in Lua. What I have written isn't working out for me when logically it should. How does math.random work with exponents?
This is what I keep getting.
> return math.random(10^15, 10^16)
> -1637272360
If you want to have a 16 digit number, try generating them this way:
local fmt = "%d%07d%08d"
local random = math.random
local num = fmt:format(random(1, 9), random(0, 10^7), random(0, 10^8))
and then keep the variable num in string type. As a number, it converts the values to exponential form(because of the very large; in your case > 10^14; exponential value) or otherwise, you can store them as a(n) Hex string?

Lua base converter

I need a base converter function for Lua. I need to convert from base 10 to base 2,3,4,5,6,7,8,9,10,11...36 how can i to this?
In the string to number direction, the function tonumber() takes an optional second argument that specifies the base to use, which may range from 2 to 36 with the obvious meaning for digits in bases greater than 10.
In the number to string direction, this can be done slightly more efficiently than Nikolaus's answer by something like this:
local floor,insert = math.floor, table.insert
function basen(n,b)
n = floor(n)
if not b or b == 10 then return tostring(n) end
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local t = {}
local sign = ""
if n < 0 then
sign = "-"
n = -n
end
repeat
local d = (n % b) + 1
n = floor(n / b)
insert(t, 1, digits:sub(d,d))
until n == 0
return sign .. table.concat(t,"")
end
This creates fewer garbage strings to collect by using table.concat() instead of repeated calls to the string concatenation operator ... Although it makes little practical difference for strings this small, this idiom should be learned because otherwise building a buffer in a loop with the concatenation operator will actually tend to O(n2) performance while table.concat() has been designed to do substantially better.
There is an unanswered question as to whether it is more efficient to push the digits on a stack in the table t with calls to table.insert(t,1,digit), or to append them to the end with t[#t+1]=digit, followed by a call to string.reverse() to put the digits in the right order. I'll leave the benchmarking to the student. Note that although the code I pasted here does run and appears to get correct answers, there may other opportunities to tune it further.
For example, the common case of base 10 is culled off and handled with the built in tostring() function. But similar culls can be done for bases 8 and 16 which have conversion specifiers for string.format() ("%o" and "%x", respectively).
Also, neither Nikolaus's solution nor mine handle non-integers particularly well. I emphasize that here by forcing the value n to an integer with math.floor() at the beginning.
Correctly converting a general floating point value to any base (even base 10) is fraught with subtleties, which I leave as an exercise to the reader.
you can use a loop to convert an integer into a string containting the required base. for bases below 10 use the following code, if you need a base larger than that you need to add a line that mapps the result of x % base to a character (usign an array for example)
x = 1234
r = ""
base = 8
while x > 0 do
r = "" .. (x % base ) .. r
x = math.floor(x / base)
end
print( r );

Resources