Lua with calculator script - lua

I'm trying to create a calculator for my own use . I don't know how to make it so that when the user inputs e.g. 6 for the prompt lets the user type in 6 numbers. So if I wrote 7 , it would give me an option to write 7 numbers and then give me the answer, And if i wrote 8 it will let me write 8 numbers...
if choice == "2" then
os.execute( "cls" )
print("How many numbers?")
amountNo = io.read("*n")
if amountNo <= 2 then print("You cant have less than 2 numbers.")
elseif amountNo >= 14 then print("Can't calculate more than 14 numbers.")
elseif amountNo <= 14 and amountNo >= 2 then
amountNmb = amountNo
if amountNmb = 3 then print(" Number 1")
print("Type in the numbers seperating by commas.")
local nmb
print("The answer is..")

The io.read formats are a bit limiting.
If you want a comma-separated list to be typed, I suggested reading a whole line and then iterating through each value:
local line = io.input("*l")
local total = 0
-- capture a sequence of non-comma chars, which then might be followed by a comma
-- then repeat until there aren't any more
for item in line:gmatch("([^,]+),?") do
local value = tonumber(item)
-- will throw an error if item does not represent a number
total = total + value
end
print(total)
This doesn't limit the count of values to any particular value—even an empty list works. (It is flawed in that it allows the line to end with a comma, which is ignored.)

From what I understand, you want the following:
print "How many numbers?"
amountNo = io.read "*n"
if amountNo <= 2 then
print "You can't have less than 2 numbers."
elseif amountNo >= 14 then
print "Can't calculate more than 14 numbers."
else
local sum = 0
for i = 1, amountNo do
print( ('Enter number %s'):format(i) )
local nmb = io.read '*n'
sum = sum + nmb
end
print( ('The sum is: %s'):format(sum) )
end

If the user separates the numbers with commas, they don't need to state how many they want to add, you can just get them all with gmatch. Also with the right pattern you can ensure you only get numbers:
local line = io.input()
local total = 0
-- match any number of digits, skipping any non-digits
for item in line:gmatch("(%d+)") do
total = total + item
end
With input '4 , 6 , 1, 9,10, 34' (no quotes), then print(total) gives 64, the correct answer

Related

Reliable way of getting the exact decimals from any number

I'm having problem returning spesific amount of decimal numbers from this function, i would like it to get that info from "dec" argument, but i'm stuck with this right now.
Edit: Made it work with the edited version bellow but isn't there a better way?
local function remove_decimal(t, dec)
if type(dec) == "number" then
for key, num in pairs(type(t) == "table" and t or {}) do
if type(num) == "number" then
local num_to_string = tostring(num)
local mod, d = math.modf(num)
-- find only decimal numbers
local num_dec = num_to_string:sub(#tostring(mod) + (mod == 0 and num < 0 and 3 or 2))
if dec <= #num_dec then
-- return amount of deciamls in the num by dec
local r = d < 0 and "-0." or "0."
local r2 = r .. num_dec:sub(1, dec)
t[key] = mod + tonumber(r2)
end
end
end
end
return t
end
By passing the function bellow i want a result like this:
result[1] > 0.12
result[2] > -0.12
result[3] > 123.45
result[4] > -1.23
local result = remove_decimal({0.123, -0.123, 123.456, -1.234}, 2)
print(result[1])
print(result[2])
print(result[3])
print(result[4])
I tried this but it seems to only work with one integer numbers and if number is 12.34 instead of 1.34 e.g, the decimal place will be removed and become 12.3. Using other methods
local d = dec + (num < 0 and 2 or 1)
local r = tonumber(num_to_string:sub(1, -#num_to_string - d)) or 0
A good approach is to find the position of the decimal point (the dot, .) and then extract a substring starting from the first character to the dot's position plus how many digits you want:
local function truncate(number, dec)
local strnum = tostring(number)
local i, j = string.find(strnum, '%.')
if not i then
return number
end
local strtrn = string.sub(strnum, 1, i+dec)
return tonumber(strtrn)
end
Call it like this:
print(truncate(123.456, 2))
print(truncate(1234567, 2))
123.45
1234567
To bulk-truncate a set of numbers:
local function truncate_all(t, dec)
for key, value in pairs(t) do
t[key] = truncate(t[key], dec)
end
return t
end
Usage:
local result = truncate_all({0.123, -0.123, 123.456, -1.234}, 2)
for key, value in pairs(result) do
print(key, value)
end
1 0.12
2 -0.12
3 123.45
4 -1.23
One could use the function string.format which is similar to the printf functions from C language. If one use the format "%.2f" the resulting string will contain 2 decimals, if one use "%.3f" the resulting string will be contain 3 decimals, etc. The idea is to dynamically create the format "%.XXXf" corresponding to the number of decimal needed by the function. Then call the function string.format with the newly created format string to generate the string "123.XXX". The last step would be to convert back the string to a number with the function tonumber.
Note that if one want the special character % to be preserved when string.format is called, you need to write %%.
function KeepDecimals (Number, DecimalCount)
local FloatFormat = string.format("%%.%df", DecimalCount)
local String = string.format(FloatFormat, Number)
return tonumber(String)
end
The behavior seems close to what the OP is looking for:
for Count = 1, 5 do
print(KeepDecimals(1.123456789, Count))
end
This code should print the following:
1.1
1.12
1.123
1.1235
1.12346
Regarding the initial code, it's quite straight-forward to integrate the provided solution. Note that I renamed the function to keep_decimal because in my understanding, the function will keep the requested number of decimals, and discard the rest.
function keep_decimal (Table, Count)
local NewTable = {}
local NewIndex = 1
for Index = 1, #Table do
NewTable[NewIndex] = KeepDecimal(Table[Index], Count)
NewIndex = NewIndex + 1
end
return NewTable
end
Obviously, the code could be tested easily, simply by copy and pasting into a Lua interpreter.
Result = keep_decimal({0.123, -0.123, 123.456, -1.234}, 2)
for Index = 1, #Result do
print(Result[Index])
end
This should print the following:
0.12
-0.12
123.46
-1.23
Edit due to the clarification of the need of truncate:
function Truncate (Number, Digits)
local Divider = Digits * 10
local TruncatedValue = math.floor(Number * Divider) / Divider
return TruncatedValue
end
On my computer, the code is working as expected:
> Truncate(123.456, 2)
123.45

Lua - Analysing values in a text file

I’m writing power (watts) values to a text file in order to extract information I can use.
4.7
4.7
4.8
5.2
5.1
4.6
4.6
4.6
Currently I have the following code to give me the average, but I’d like to add to it so it tells me more such as, what was the highest value, the lowest value, the most frequent value, and if at all possible if there are any ‘0’ values recorded (* - if possible with that last one it would be good to ignore them..)
local ctr = 0
local sum = 0
for _ in io.lines"/www/EnergyPlug-b.txt" do
ctr = ctr + 1
end
print(ctr)
for line in io.lines"/www/EnergyPlug-b.txt" do
sum = sum + line
end
print(sum)
average = sum / ctr
print(average)
I did explore creating a Lua table via table.insert() off of the first io.lines section, like the following, but I’m not sure how good it is?
local rows = {}
-- go over the file line by line
for line in io.lines("/www/EnergyPlug-b.txt") do
-- if line matches ?.? then insert into table
local value = line:match("%d%p%d") -- 1.5
--print(value)
table.insert(rows, value)
end
local arraymax = math.max(unpack(rows))
local arraymin = math.min(unpack(rows))
print (arraymax) -- ?.?
print (arraymin) -- ?.?
If the above is suitable, how best should I go about identifying the items/values i mentioned at the very start ?
In the first snippet there is no reason to have a separate loop for ctr and sum. You can do it in one loop.
Your second snipped is ok. unpack is limited so this won't work for many thousand values.
You have to traverse the table anyway to get the other values so you can determin min and max in that loop too without that size limit.
local value = line:match("%d%p%d") if there are only those numbers in that file you can skip the pattern matching here.
The calculations are pretty straigt forward. I'm not sure what you're struggling with here.
local min = math.huge -- use a value that is definitely bigger than any value
local max = -math.huge -- use a value that is definitely smaller than any value
local counts = {} -- an emtpy table we'll use to count how often each value occurs
local numIngored = 0 -- how many 0 values have we ignored?
for line in io.lines(yourFileName) do
-- convert string to a number
local value = tonumber(line)
-- if we take the value into account
if value ~= 0.0 then
-- update min and max values
min = value < min and value or min
max = value > max and value or max
-- update counts
counts[value] = counts[value] and counts[value] + 1 or 1
else
-- count ignored values
numIgnored = numIgnored + 1
end
end
I'll leave it up to you to get the most frequent values from counts
Thanks to #piglet and using other SO posts, here is what I ended up with..
local min = math.huge -- use a value that is definitely bigger than any value
local max = -math.huge -- use a value that is definitely smaller than any value
local ctr = 0
local valtotal = 0
local counts = {} -- an emtpy table we'll use to count how often each value occurs
local numIngored = 0 -- how many 0 values have we ignored?
for line in io.lines("/www/EnergyPlug-b.txt") do
-- convert string to a number
local value = tonumber(line)
-- if we take the value into account
if value ~= 0.0 then
ctr = ctr + 1
valtotal = valtotal + value
-- update min and max values
min = value < min and value or min
max = value > max and value or max
-- update counts
counts[value] = counts[value] and counts[value] + 1 or 1
else
-- count ignored values
numIgnored = numIgnored + 1
end
end
print("----Table print out -----")
for k, v in pairs(counts) do
print(k,v)
end
print("---------------------------")
print("Lowest value recorded = " ..min)
print("Highest value recorded = " ..max)
print("Average value recorded = " ..round2(valtotal / ctr, 1))
print("Number of values recorded = " ..ctr)
print("---------------------------")
local max_val, key1 = -math.huge
for k, v in pairs(counts) do
if v > max_val then
max_val, key1 = v, k
end
end
local min_val, key2 = math.huge
for k1, v1 in pairs(counts) do
if v1 < min_val or v1 == min_val then
min_val, key2 = v1, k1
end
end
local min_qty, max_qty = 0, 0
local min_str, max_str = "", ""
for k2, v2 in pairs(counts) do
if v2 == min_val then
min_qty = min_qty + 1
min_str = min_str .. " " .. k2
elseif v2 == max_val then
max_qty = max_qty + 1
max_str = max_str .. " " .. k2
end
end
if min_qty == 1 then
print("Least recorded value was = " ..key2.. " recorded "..min_val.." times")
else
print("Least recorded values were = " ..min_str.. " each recorded "..min_val.." time")
end
if max_qty == 1 then
print("Most recorded value was = " ..key1.. " recorded "..max_val.." times")
else
print("Least recorded values were = " ..max_str.. " each recorded "..max_val.." time")
end
print("---------------------------")

Minimum Change Maker Returning Optimal Solution and No Solution

I need Help adding a if clause to my Change Maker, so that if say I have denominations of coins that can't equal the input coin value. For Example I have Coins worth 2,4,6 and I have a Value of 1. I Want it to return Change Not Possible I tried adding a clause to it below but when I test it I get 1.#INF
I also am curious how I can find the optimal coin solution, So on top of saying the minimum number of coins it returns the optimal coin setup if there is one.
function ChangeMaking(D,n)
--[[
//Applies dynamic programming to find the minimum number of coins
//of denominations d1< d2 < . . . < dm where d1 = 1 that add up to a
//given amount n
//Input: Positive integer n and array D[1..m] of increasing positive
// integers indicating the coin denominations where D[1]= 1
//Output: The minimum number of coins that add up to n
]]
F = {} -- F is List Array of Coins
m = tablelength(D)
F[0] = 0
for i =1,n do
temp = math.huge
j = 1
while j <= m and i >= D[j] do
temp = math.min(F[ i - D[j] ], temp)
j = j + 1
end
F[i] = temp + 1
end
--I wanted to Catch the failed Solution here but I return 1.#INF instead
--if F[n] <= 0 and F[n] == 1.#INF then print("No Change Possible") return end
return F[n]
end
function main()
--[[
//Prints a Greeting, Asks for Denominations separated by spaces.
// Iterates through the input and assigns values to table
// Table is then input into ChangeMaker, and a while loop takes an n value for user input.
// User Enters 0 to end the Loop
]]
io.write("Hello Welcome the to Change Maker - LUA Edition\nEnter a series of change denominations, separated by spaces: ")
input = io.read()
deno = {}
for num in input:gmatch("%d+") do table.insert(deno,tonumber(num)) end
local i = 1
while i ~= 0 do
io.write("Please Enter Total for Change Maker, When Finished Enter 0 to Exit: ")
input2 = io.read("*n")
if input2 ~= 0 then io.write("\nMinimum # of Coins: " .. ChangeMaking(deno,input2).."\n") end
if input2 == 0 then i=0 print("0 Entered, Exiting Change Maker") end
end
end
function tablelength(T)
--[[
//Function for grabbing the total length of a table.
]]
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
main()

Lua multiple inputs in table

I'm new to lua and I have this assignment and one of the questions I'm really stumped on is asking:
"A program that asks the user repeatedly for students' scores, will stop when the user enters a score of 999 then the program should calculate and display the number of scores entered, highest score, lowest score, and the average score. Make sure to display an error message if a score less than zero or more than 100 is entered by user. "
I've been at this all week long and still can't figure out what to do and its due at 11:59pm est. Any insight and direction would be great.
-How do I input multiple values in a growing table scores = {}? Where the size is given by the number of inputs for variable s after the user enters 999 and ends the repeat loop. This is actually my BIGGEST problem.
My Code:
local scores = {}, avg
repeat
io.write("Enter score(s)")
local s = tonumber(io.read()) --input and convert data type
print(s, type(s)) --s value, check input type
if(s < 0 or s > 100) then
print("Error.")
end
until (s == 999)
for i = 0, #s, 1 do
sum = 0
if s then
sum = sum + s
end
end
-- -----------------------------------------------------------Attemps to find a way to put s values in scores table-----------------------------------------------------------------------------------------
--[[scores[#scores+1] = s ----Attempt 1
print (scores)
for i = 0, #s, 1 do ----Attempt 2
scores{s} = s[i]
print (i, scores) --tried a multitude of different ways and
--kept getting the same number printed once or memory location of last entered number
end
for i, s in ipairs (scores) do --Attempt 3
print (i, s)
end
for i = 0, #s, 1 do
sum = 0
if s then
sum = sum + s
end
end --]]
-- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
--[[function average(myTable)
local sum = 0
for i in scores do
sum = sum + i
end
return (sum / #scores)
end
print ("The number of values in the table"..#scores)
print ("The average of the scores is "..average(s))
print ("The max value in the table is "..math.max(s))
print ("The minimum value in the table is "..math.min(s))
table.maxn(scores), table.minn(scores)
--]]
io.write("Please press enter to continue")
io.read()

Explain why unpack() returns different results in Lua

The following script finds prime numbers in a range from 1 to 13.
When I explicitly iterate over the table that contains the results I can see that the script works as expected. However, if I use unpack() function on the table only the first 3 numbers get printed out.
From docs: unpack is "a special function with multiple returns. It receives an array and returns as results all elements from the array, starting from index 1".
Why is it not working in the script below?
t = {}
for i=1, 13 do t[i] = i end
primes = {}
for idx, n in ipairs(t) do
local isprime = true
for i=2, n-1 do
if n%i == 0 then
isprime = false
break
end
end
if isprime then
primes[idx] = n
end
end
print('loop printing:')
for i in pairs(primes) do
print(i)
end
print('unpack:')
print(unpack(primes))
Running
$ lua5.3 primes.lua
loop printing:
1
2
3
5
7
13
11
unpack:
1 2 3
Change
primes[idx] = n
to
primes[#primes+1] = n
The reason is that idx is not sequential as not every number is a prime.

Resources