Number addition in Lua - avoiding negative values - math

This is not hardcore math but I simply cannot find the correct function to make this in a smooth way.
Lets say I have 3 values. Cost1 Cost2 Cost3. Each have a value, I want to add them together into a final number, TotalCost.
Cost1+Cost2+Cost3 = TotalCost
Problem is, if any of Cost1/2/3 is negative, I want to make that a ZERO, ie;
Cost1 = -100
Cost2 = 50
Cost3 = 150
Cost1+Cost2+Cost3 = TotalCost
equals
0 + 50 + 150 = 200
I know I have seen something with like (X*Math.Floor * 100) / 100 , to do just this, if im not completly mistaken.
Would be greatly apreciated if anyone could answer. I know its a basic question but I simply couldent figure out how (with a smart way that is) with the Math. functions.
Im coding in Lua: http://lua-users.org/wiki/MathLibraryTutorial

Possibly the shortest way to do this is math.max(x,0). So your expression would be:
math.max(Cost1,0) + math.max(Cost2,0) + math.max(Cost3,0)
Of course, you could also make a function out of it -- and you probably should, if you're going to use it for more than a one-liner.

The most straight-forward way is to use if statements to test if a number is negative.
This is another way:
function my_sum(...)
sum = 0
for k, v in ipairs{...} do
sum = sum + (v > 0 and v or 0)
end
return sum
end
print(my_sum(-50, 50, 100)) -- 150
The expression v > 0 and v or 0 has a value of v if v > 0 is true, 0 otherwise.

Just write exactly what you said in Lua instead of English:
(Cost1 > 0 and Cost1 or 0) + (Cost2 > 0 and Cost2 or 0) + (Cost3 > 0 and Cost3 or 0)

You can simply do something like this:
local value1 = 100
local value2 = -200
local value3 = 200
local value4 = (value1 > 0 and value1 or 0) + (value2 > 0 and value2 or 0) + (value3 > 0 and value3 or 0)
The nicest way would be to implement a function that sums up non-negative values
function sumOfPositives(tableOfValues)
local sum = 0
for i,v in ipairs(tableOfValues) do
sum = sum + v > 0 and v or 0
end
return sum
end
This way you can do it for any number of values.
If you prefer to just enter the values without having them in a table you can do what Yu Hao suggested and use the ... argument.

Related

Is it possible to find a few common multiples of a list of numbers, without them having to be integers?

I don't even know if something like this is possible, but:
Let us say we have three numbers:
A = 6
B = 7.5
C = 24
I would like to find a few evenly spaced common multiples of these numbers between 0 and 2.
So the requirement is: one_of_these_numbers / common_multiple = an_integer (or almost an integer with a particular tolerance)
For example, a good result would be [0.1 , 0.5 , 1 , 1.5]
I have no idea if this is possible, because one can not iterate through a range of floats, but is there a smart way to do it?
I am using python, but a solution could be represented in any language of your preference.
Thank you for your help!
While I was writing my question, I actually came up with an idea for the solution.
To find common divisors using code, we have to work with integers.
My solution is to multiply all numbers by a factor = 1, 10, 100, ...
so that we can act as if they are integers, find their integer common divisors, and then redivide them by the factor to get a result.
Better explained in code:
a = 6
b = 7.5
c = 24
# Find a few possible divisors between 0 and 2 so that all numbers are divisible
by div.
# We define a function that finds all divisors in a range of numbers, supposing
all numbers are integers.
def find_common_divisors(numbers, range_start, range_end):
results = []
for i in range(range_start + 1, range_end + 1):
if all([e % i == 0 for e in numbers]):
results.append(i)
return results
def main():
nums = [a, b, c]
range_start = 0
range_end = 2
factor = 1
results = [1]
while factor < 11:
nums_i = [e * factor for e in nums]
range_end_i = range_end * factor
results += [e / factor for e in find_common_divisors(nums_i, range_start, range_end_i)]
factor *= 10
print(sorted(set(results)))
if __name__ == '__main__':
main()
For these particular numbers, I get the output:
[0.1, 0.3, 0.5, 1, 1.5]
If we need more results, we can adjust while factor < 11: to a higher number than 11 like 101.
I am curious to see if I made any mistake in my code.
Happy to hear some feedback.
Thank you!

Error in for loop - attempt to select less than one element in integerOneIndex

I'm trying to translate a C routine from an old sound synthesis program into R, but have indexing issues which I'm struggling to understand (I'm a beginner when it comes to using loops).
The routine creates an exponential lookup table - the vector exptab:
# Define parameters
sinetabsize <- 8192
prop <- 0.8
BP <- 10
BD <- -5
BA <- -1
# Create output vector
exptab <- vector("double", sinetabsize)
# Loop
while(abs(BD) > 0.00001){
BY = (exp(BP) -1) / (exp(BP*prop)-1)
if (BY > 2){
BS = -1
}
else{
BS = 1
}
if (BA != BS){
BD = BD * -0.5
BA = BS
BP = BP + BD
}
if (BP <= 0){
BP = 0.001
}
BQ = 1 / (exp(BP) - 1)
incr = 1 / sinetabsize
x = 0
stabsize = sinetabsize + 1
for (i in (1:(stabsize-1))){
x = x + incr
exptab [[sinetabsize-i]] = 1 - (BQ * (exp(BP * x) - 1))
}
}
Running the code gives the error:
Error in exptab[[sinetabsize - i]] <- 1 - (BQ * (exp(BP * x) - 1)) :
attempt to select less than one element in integerOneIndex
Which, I understand from looking at other posts, indicates an indexing problem. But, I'm finding it difficult to work out the exact issue.
I suspect the error may lie in my translation. The original C code for the last few lines is:
for (i=1; i < stabsize;i++){
x += incr;
exptab[sinetabsize-i] = 1.0 - (float) (BQ*(exp(BP*x) - 1.0));
}
I had thought the R code for (i in (1:(stabsize-1))) was equivalent to the C code for (i=1; i< stabsize;i++) (i.e. the initial value of i is i = 1, the test is whether i < stabsize, and the increment is +1). But now I'm not so sure.
Any suggestions as to where I'm going wrong would be greatly appreciated!
As you say, array indexing in R starts at 1. In C it starts at zero. I reckon that's your problem. Can sinetabsize-i ever get to zero?

Subtraction operation using only increment, loop, assign, zero

I am trying to build up subtraction, addition, division, multiplication and other operations using only following ones:
incr(x) - Once this function is called it will assign x + 1 to x
assign(x, y) - This function will assign the value of y to x (x = y)
zero(x) - This function will assign 0 to x (x = 0)
loop X { } - operations written within brackets will be executed X times
Using following rules it is straight forward to implement addition (add) like this:
ADD (x, y) {
loop X {
y = incr (y)
}
return y
}
However, I'm struggling to implement subtraction. I think that all the other needed operations could be completed using subtraction.
Any hint will be very appreciated.
Stephen Cole Kleene devised a way to perform integer subtraction using integer addition. However, it assumes that you cannot have negative integers. For example:
0 - 1 = 0
1 - 1 = 0
2 - 1 = 1
3 - 1 = 2
4 - 1 = 3
5 - 2 = 3
6 - 3 = 3
6 - 4 = 2
6 - 5 = 1
6 - 6 = 0
6 - 7 = 0
In your question, you implemented the addition operation using the increment operation.
Similarly, you can implement the subtraction operation using the decrement operation as follows:
sub(x, y) {
loop y
{ x = decr(x) }
return x
}
Now, all we need to do is implement the decrement operation.
This is where the genuis of Kleene shines:
decr(x) {
y = 0
z = 0
loop x {
y = z
z = incr(z)
}
return y
}
Here we've used all the four operations. This is how it works:
We have two base cases, y (the base case for 0) and z (the base case for 1):
y = 0 - 1 = 0
z = 1 - 1 = 0
Hence, we initialize them both to 0.
When x is 0 we run the loop 0 times (i.e. never) and then we simply return y = 0.
When x is 1 then we run the loop once, assign y = z and then simply return y = z = 0.
Notice that every time we run the loop y holds the result of the current iteration while z holds the result of the next iteration. This is the reason why we require two base cases. The decrement function is not a continuous function. It is a piecewise function:
decr(0) = 0
decr(n + 1) = n
Kleene realized this when he went to the dentist and the dentist extracted two of his teeth. He was frustrated while trying to solve this very problem and when the dentist extracted two of his teeth he realized that he required two base cases.

Python: a type error

So here is my situation. Ive been trying to make a advanced calculator in python 3.4, one where you can just type something like this. '1 + 1', and it would then give you the answer of '2'. Now i will explain how my calculator is supposed to work. So you start by entering a maths equation, then it counts the words you entered based on the spaces. It does this so it knows how long some future loops need to be. Then it splits up everything that you entered. It splits it up into str's and int's but its all still in the same variable and it's all still in order. The thing i'm having trouble with is when it is meant to actually do the calculations.
here is all of my code-
# This is the part were they enter the maths equation
print("-------------------------")
print("Enter the maths equation")
user_input = input("Equation: ")
# This is were it counts all of the words
data_count = user_input.split(" ")
count = data_count.__len__()
# Here is were is splits it into str's and int's
n1 = 0
data = []
if n1 <= count:
for x in user_input.split():
try:
data.append(int(x))
except ValueError:
data.append(x)
n1 += 1
# And this is were it actually calculates everything
number1 = 0
number2 = 0
n1 = 0
x = 0
answer = 0
while n1 <= count:
#The code below checks if it is a number
if data[n1] < 0 or data[n1] > 0:
if x == 0:
number1 = data[n1]
elif x == 1:
number2 = data[n1]
elif data[n1] is "+":
if x == 0:
answer += number1
elif x == 1:
answer += number2
n1 += 1
x += 1
if x > 1:
x = 0
print("Answer =", answer)
but during the calculation it messes up and gives me and error
error-
if data[n1] < 0 or data[n1] > 0:
TypeError: unorderable types: str() < int()
can anyone see what i am doing wrong here?
Thanks
When you are comparing a string and an integer, this problem comes.
Python doesn't guess, it throws an error.
To fix this, simply call int() to convert your string to an integer:
int(input(...))
So, corrected statement should be:
if int(data[n1]) < 0 or int(data[n1]) > 0:

Repeat a loop until it satisfies a specific condition

Anybody can help me on this? Suppose the "p" is totally exogenous and following a uniform distribution. Then I want to generate "z", which is a TRUE(=1) or FALSE(=0) dummy, and has the property that the summation of each three elements (1-3, 4-6, 7-9,..., 58-60) in "z" should be greater than 0.
For example, if I get a "z" like {1 0 0 1 1 0 0 0 0 0 1 0...}, I hope to repeat the loop again ( since sum(z[7:9])=0 ) to draw a different "error" until I get a new "z" like {1 1 0 0 0 1 0 1 0 1 0 0...} where all summations for each three elements are greater than 0. The code I use is as follows. Where am I wrong?
set.seed(005)
p<-runif(60, 0, 1)
for (i in 1:20) {
repeat {
error= -0.2*log((1/runif(60, 0, 1))-1) # a random component
z=(p<0.5+error) # TRUE/FALSE condition
z=replace(z, z==TRUE, 1) # replace z to 1 if z is true, else z=0
if (sum(z[(3*i-2):(3*i)])>0) {break}
}
}
Your for loop generates a new z for every i. I don't think that's what you're trying to do. From what I can understand, you're trying to generate a new z and then use a for loop with the counter i to check for sums of three consecutive elements. If so, then you need to have one loop to generate new zs, and then another one inside this loop which checks for the sum of three consecutive elements.
I think this does what you want. But when I run it it seems unlikely that you will get a satisfactory z soon.
set.seed(005)
p<-runif(60, 0, 1)
invalidentriesexist =1
while(invalidentriesexist == 1) {
error = -0.2*log((1/runif(60, 0, 1))-1) # a random component
z=(p<0.5+error) # TRUE/FALSE condition
z=replace(z, z==TRUE, 1) # replace z to 1 if z is true, else z=0
z=replace(z, z==FALSE, 0) # replace z to 1 if z is true, else z=0
invalidentriesexist = 0
i = 1
while ( i <=20 & invalidentriesexist == 0 ) {
invalidentriesexist = 0
if (sum(z[((3*i)-2):(3*i)])==0) {invalidentriesexist = 1}
cat(i,'\n')
cat(invalidentriesexist,'\n')
cat(paste(z,collapse = ","),'\n')
cat(z[((3*i)-2):(3*i)],'\n\n')
i = i + 1
}
}

Resources