Python - Iterate over while loop to compile an average runtime of program - python-3.x

So I want to preface this by saying one of the biggest problems with this I'm assuming is the return section of this code. With that being said, exactly what I'm trying to do is based off of my previous question for this code which was answered in two different ways, one said to be faster than the other. I wanted to see just how much faster myself by comparing the numbers. The problem I am now having though is that I would like to iterate over this function X amount of times, take the runtimes for each of those executions of the code, compile them, and create an average so I can then do the same with the other proposed solution, and compare the two. The main answer or help I'm currently looking for is getting this to iterate so I can have X different runtimes available to be seen. After that I will try to figure out how to compile them on my own, unless someone would be kind enough to help me through this entire process in one go.
import time
start_time = time.time()
def fibonacci():
previous_num, result = 0, 1
user = 1000
iterations = 10
while len(str(result)) < user:
while iterations != 0:
iterations -= 1
previous_num, result = result, previous_num + result
print(iterations)
return result
print(fibonacci())
print("--- %s seconds ---" % (time.time() - start_time))

Related

How to make multiple objects work at same time?

I have been using Python to control some instruments, which I created a Class for. I have multiple instruments of the same kind, so my script has multiple instances of the same class.
Let's say the class is Arm, and it has methods move_left, move_right and reset. Right now I have script like this:
arm1 = Arm()
arm2 = Arm()
arm1.move_left()
arm2.move_left()
arm1.move_right()
arm2.move_right()
arm1.reset()
arm2.reset()
It's completely in serial. I have to wait for arm1 to finish move_left, then start arm2 to move_left. This is very inefficient. I would like arm1 and arm2 to move at the same time. They don't have to be exact same time, because arm1 and arm2 are quite independent and there's not much synchronization requirement. I just don't want to waste time in the serialization in the code.
I've done some searching and learned a little about threading, but what I found is all about putting a function in a Thread target, which doesn't really apply to my situation here.
One way to approach the problem would be to implement a state machine. That is, instead of defining the problem through commands like move_left() and move_right(), instead you can have some variables that represent the final position that you want each arm to end up at, and a second set of variables that represent the current position of the arm. Then at each time-step, you simply move the arms by a small amount towards their target-destination.
Here's a very simple toy program to demonstrate the idea. Note that it moves each "arm" by no more than 0.1 units every 100mS time-step (you can of course use any time-step and maximum-movement values you want instead):
import time
class Robot:
def __init__(self):
self._leftArmCurrentPos = 0.0
self._leftArmTargetPos = 0.0
self._rightArmCurrentPos = 0.0
self._rightArmTargetPos = 0.0
def setLeftArmTargetPos(self, newPos):
self._leftArmTargetPos = newPos
def setRightArmTargetPos(self, newPos):
self._rightArmTargetPos = newPos
# Returns the closest value to (deltaVal) in the range [-0.1, +0.1]
def clamp(self, deltaVal):
aLittleBit = 0.1 # or however much you want
if (deltaVal > aLittleBit):
return aLittleBit
elif (deltaVal < -aLittleBit):
return -aLittleBit
else:
return deltaVal
def moveArmsTowardsTargetPositions(self):
leftArmDelta = self.clamp(self._leftArmTargetPos - self._leftArmCurrentPos)
if (leftArmDelta != 0.0):
self._leftArmCurrentPos += leftArmDelta
print("Moved left arm by %f towards %f, new left arm pos is %f" % (leftArmDelta, self._leftArmTargetPos, self._leftArmCurrentPos))
rightArmDelta = self.clamp(self._rightArmTargetPos - self._rightArmCurrentPos)
if (rightArmDelta != 0.0):
self._rightArmCurrentPos += rightArmDelta
print("Moved right arm by %f towards %f, new right arm pos is %f" % (rightArmDelta, self._rightArmTargetPos, self._rightArmCurrentPos))
if __name__ == "__main__":
r = Robot()
r.setLeftArmTargetPos(10.0)
r.setRightArmTargetPos(-3.0)
while True:
r.moveArmsTowardsTargetPositions()
time.sleep(0.1)
A nice side-effect of this approach is that you if change your mind at any time about where you want the arms to be, you can simply call setLeftArmTargetPos() or setRightArmTargetPos() to give the arms new/different destination values, and they will immediately start moving from (wherever they currently are at) towards the new target positions -- there's no need to wait for them to arrive at the old destinations first.

Python 3 - calculate total in if else function using for loop

If anybody can give me some hints to point me in the right direction so I can solve it myself that would be great.
I am trying to calculate the total and average income depending on number of employee's. Do I have to make another list or iterate the current list (list1) to solve.
def get_input():
Name = input("Enter a name: ")
Hours = float(input("Enter hours worked: "))
Rate = float(input("Enter hourly rate: "))
return Name, Hours, Rate
def calc_pay(Hours, Rate):
if Hours > 40:
overtime = (40 * Rate) + (Hours - 40) * (Rate * 1.5)
print(list1[0], "should be paid", overtime)
else:
no_overtime = (Hours * Rate)
print(list1[0], "should be paid", no_overtime)
return Hours, Rate
x = int(input("Enter the number of employees: "))
for i in range(x):
list1 = list(get_input())
calc_pay(list1[1], list1[2])
i += 1
If you want to keep track of the total pay for all the employees, you probably need to make two major changes to your code.
The first is to change calc_pay to return the calculated pay amount instead of only printing it (the current return value is pretty useless, since the caller already has those values). You may want to skip printing in the function (since calculating the value and returning it is the function's main job) and let that get done by the caller, if necessary.
The second change is to add the pay values together in your top level code. You could either append the pay values to a list and add them up at the end (with sum), or you could just keep track of a running total and add each employee's pay to it after you compute it.
There are a few other minor things I'd probably change in your code if I was writing it, but they're not problems with its correctness, just style issues.
The first is variable names. Python has a guide, PEP 8 that makes a bunch of suggestions about coding style. It's only an official rule for the Python code that's part of the standard library, but many other Python programmers use it loosely as a baseline style for all Python projects. It recommends using lowercase_names_with_underscores for most variable and function names, and reserving CapitalizedNames for classes. So I'd use name, hours and rate instead of the capitalized versions of those names. I'd also strongly recommend that you use meaningful names instead of generic names like x. Some short names like i and x can be useful in some situations (like coordinates and indexes), but I'd avoid using them for any non-generic purpose. You also don't seem to be using your i variable for anything useful, so it might make sense to rename it _, which suggests that it's not going to be used. I'd use num_employees or something similar instead of x. The name list1 is also bad, but I suggest doing away with that list entirely below. Variable names with numbers in them are often a bad idea. If you're using a lot of numbered names together (e.g. list1, list2, list3, etc.), you probably should be putting your values in a single list instead (a list of lists) instead of the numbered variables. If you just have a few, they should just have more specific names (e.g. employee_data instead of list1).
My second suggestion is about handling the return value from get_input. You can unpack the tuple of values returned by the function into separate variables, rather than putting them into a list. Just put the names separated by commas on the left side of the = operator:
name, hours, rate = get_input()
calc_pay(hours, rate)
My last minor suggestion is about avoiding repetition in your code. A well known programming suggestion is "Don't Repeat Yourself" (often abbreviated DRY), since repeated (especially copy/pasted) code is hard to modify later and sometimes harbors subtle bugs. Your calc_pay function has a repeated print line that could easily be moved outside of the if/else block so that it doesn't need to be repeated. Just have both branches of the conditional code write the computed pay to the same variable name (instead of different names) and then use that single variable in the print line (and a return line if you follow my suggested fix above for the main issue of your question).
Thanks for the help people. Here was the answer
payList = []
num_of_emps = int(input("Enter number of employees: "))
for i in range(num_of_emps):
name, hours, rate = get_input()
pay = calc_pay(hours, rate)
payList.append(pay)
total = sum(payList)
avg = total / num_of_emps
print("The total amount to be paid is $", format(total, ",.2f"), sep="")
print("\nThe average employee is paid $", format(avg, ",.2f"), sep="")
Enter objects mass, then calculate its weight.
If the object weighs more than 500.
Else the object weighs less than 100.
Use formula: weight = mass x 9.8

Python 3.x Homework help. Sequential number guessing game.

We are supposed to make a number guessing game where depending on what difficulty the player chooses the game generates 4 or 5 numbers and the player is given all but the last, which they have to guess in 3 tries. The numbers have to be equal distances apart, and the numbers have to be within the 1 - 100 range.
So far I know what it will look like roughly.
def guesses:
function for accumulating tries as long as guesses_taken < 3
let user retry, or congratulate and offer to replay
def game_easy:
code for number generation, step value, etc
guesses()
def game_hard:
same code as easy mode, with the appropriate changes
guesses()
For the random numbers, all I have so far is this
guess_init = rand.int (1,100)
step = rand.int (1,20)
guess_init = guess_init + step
and just having it loop and add the step 4 or 5 times respectively.
Where I'm stuck is 1. How to ensure that none of the numbers generated exceed 100 (so it can't be a step of 1 starting at 98), and 2. how to print all but the last number generated.
What I was thinking was assigning the last number generated to a variable that the player input must match. But I was also thinking that if "guess_init" has ran through the loop, then it will already be holding the value of the last number and all Ill have to check is that user input == guess_init.
In your Case you should read the random section from the Python Standard Library. Especially this is relevant:
random.randrange(start, stop[, step])
Return a randomly selected element from range(start, stop, step). This is equivalent to choice(range(start, stop, step)), but doesn’t actually build a range object.

Python 3: 'multiprocessing' and 'time' module incompatibility?

I use a multiprocessing.Pool().imap_unordered(...) to perform some tasks in parallel and measure the time it takes by calculating the difference of time.time() before and after starting the pool tasks.
However, it returns wrong results! When I watch my wall clock while the program runs, it tells me a run time of around 5 seconds. But the program itself outputs a run time of only 0.1 seconds.
I also have a variant of this code without any multiprocessing which takes double the time, but outputs the correct run times.
Here is my code:
if __name__ == "__main__":
n = int(input("How many grids to create? "))
use_multiprocessing = None
while use_multiprocessing is None:
answer = input("Use multiprocessing to speed things up? (Y/n) ").strip().lower()
if len(answer) == 1 and answer in "yn":
use_multiprocessing = True if answer == "y" else False
t0 = time.time()
if use_multiprocessing:
processes = cpu_count()
worker_pool = Pool(processes)
print("Creating {} sudokus using {} processes. Please wait...".format(n, processes))
sudokus = worker_pool.imap_unordered(create_sudoku, range(n), n // processes + 1)
else:
progress_bar, progress_bar_length = 0, 10
sudokus = []
print("Creating {} sudokus".format(n), end="", flush=True)
for i in range(n):
p = int((i / n) * progress_bar_length)
if p > progress_bar:
print("." * (p-progress_bar), end="", flush=True)
progress_bar = p
new_sudoku = create_sudoku()
sudokus.append(new_sudoku)
t = time.time() - t0
l = len(list(sudokus))
print("\nSuccessfully created {} grids in {:.6f}s (average {:.3f}ms per grid)!".format(
l, t, 1000*t/l
))
And here an example run, which took around 5-6 seconds in reality (after entering the number of grids to create and whether to use multiprocessing, of course):
How many grids to create? 100000
Use multiprocessing to speed things up? (Y/n) y
Creating 100000 sudokus using 4 processes. Please wait...
Successfully created 100000 grids in 0.122141s (average 0.001ms per grid)!
Process finished with exit code 0
Are multiprocessing and time.time() incompatible? I've heard that time.clock() can make problems under these circumstances, but I thought time.time() should be safe. Or is there any other problem?
I figured it out.
Pool.imap_unordered(...) returns a generator and no list. That means, its elements are not already created when the method finishes, but only as soon as I access them.
I did this in the line l = len(list(sudokus)), where I converted the generator into a list to get the length. And the finish time got measured one line before that, so it correctly reported the time it took to initialize the generator. This was not what I want, so swapping those two lines results in correct times.
I know I may not convert a generator into a list just to find out the length and then discard the list again. I must either rely on the saved requested length if I want a generator, or I must use Pool.map(...) instead which produces a list and blocks until it's ready.

What is the time complexity for repeatedly doubling a string?

Consider the following piece of C++ code:
string s = "a";
for (int i = 0; i < n; i++) {
s = s + s; // Concatenate s with itself.
}
Usually, when analyzing the time complexity of a piece of code, we would determine how much work the inner loop does, then multiply it by the number of times the outer loop runs. However, in this case, the amount of work done by the inner loop varies from iteration to iteration, since the string being built up gets longer and longer.
How would you analyze this code to get the big-O time complexity?
The time complexity of this function is Θ(2n). To see why this is, let's look at what the function does, then see how to analyze it.
For starters, let's trace through the loop for n = 3. Before iteration 0, the string s is the string "a". Iteration 0 doubles the length of s to make s = "aa". Iteration 1 doubles the length of s to make s = "aaaa". Iteration 2 then doubles the length of s to make s = "aaaaaaaa".
If you'll notice, after k iterations of the loop, the length of the string s is 2k. This means that each iteration of the loop will take longer and longer to complete, because it will take more and more work to concatenate the string s with itself. Specifically, the kth iteration of the loop will take time Θ(2k) to complete, because the loop iteration constructs a string of size 2k+1.
One way that we could analyze this function would be to multiply the worst-case time complexity of the inner loop by the number of loop iterations. Since each loop iteration takes time O(2n) to finish and there are n loop iterations, we would get that this code takes time O(n · 2n) to finish.
However, it turns out that this analysis is not very good, and in fact will overestimate the time complexity of this code. It is indeed true that this code runs in time O(n · 2n), but remember that big-O notation gives an upper bound on the runtime of a piece of code. This means that the growth rate of this code's runtime is no greater than the growth rate of n · 2n, but it doesn't mean that this is a precise bound. In fact, if we look at the code more precisely, we can get a better bound.
Let's begin by trying to do some better accounting for the work done. The work in this loop can be split apart into two smaller pieces:
The work done in the header of the loop, which increments i and tests whether the loop is done.
The work done in the body of the loop, which concatenates the string with itself.
Here, when accounting for the work in these two spots, we will account for the total amount of work done across all iterations, not just in one iteration.
Let's look at the first of these - the work done by the loop header. This will run exactly n times. Each time, this part of the code will do only O(1) work incrementing i, testing it against n, and deciding whether to continue with the loop. Therefore, the total work done here is Θ(n).
Now let's look at the loop body. As we saw before, iteration k creates a string of length 2k+1 on iteration k, which takes time roughly 2k+1. If we sum this up across all iterations, we get that the work done is (roughly speaking)
21 + 22 + 23 + ... + 2n+1.
So what is this sum? Previously, we got a bound of O(n · 2n) by noting that
21 + 22 + 23 + ... + 2n+1.
< 2n+1 + 2n+1 + 2n+1 + ... + 2n+1
= n · 2n+1 = 2(n · 2n) = Θ(n · 2n)
However, this is a very weak upper bound. If we're more observant, we can recognize the original sum as the sum of a geometric series, where a = 2 and r = 2. Given this, the sum of these terms can be worked out to be exactly
2n+2 - 2 = 4(2n) - 2 = Θ(2n)
In other words, the total work done by the body of the loop, across all iterations, is Θ(2n).
The total work done by the loop is given by the work done in the loop maintenance plus the work done in the body of the loop. This works out to Θ(2n) + Θ(n) = Θ(2n). Therefore, the total work done by the loop is Θ(2n). This grows very quickly, but nowhere near as rapidly as O(n · 2n), which is what our original analysis gave us.
In short, when analyzing a loop, you can always get a conservative upper bound by multiplying the number of iterations of the loop by the maximum work done on any one iteration of that loop. However, doing a more precisely analysis can often give you a much better bound.
Hope this helps!

Resources