What are the errors inside this random walking code? [duplicate] - python

This question already has an answer here:
Random walk's weird outcome in python 3?
(1 answer)
Closed 6 years ago.
I am having unexpected outputs with the following code:
import random
N = 30 # number of steps
n = random.random() # generate a random number
x = 0
y = 0
z = 0
count = 0
while count <= N:
if n < 1/3:
x = x + 1 # move east
n = random.random() # generate a new random number
if n >= 1/3 and n < 2/3:
y = y + 1 # move north
n = random.random() # generate a new random number
if n >= 2/3:
z = z + 1 # move up
n = random.random() # generate a new random number
print("(%d,%d,%d)" % (x,y,z))
count = count + 1
When I run the code, the problem is:
Code output displays 31 coordinates, 1 more than the number of steps (N) variable.
Each iteration for 1 step should take only 1 step but it sometimes take multiple steps.
When I tested the code, the problem is ensured. To test the code, I assigned N = 1, and saw the following output:
(-1,0,1) This should be the initial step, but it took multiple steps (both x-1 and z+1), how could this happen?
(-2,0,1) Number of step variable (N) = 1 but this is the second output, why was it displayed?
Thanks for helping

N is 30, so count goes from 0 to 30. Since 30 <= 30 you will run the loop for count=0, 1, ..., 29 AND 30 which is 31 times
When you take a step, you don't ensure that another step is NOT taken. If random happens, you could enter the second or third if after already being in a previous one in the same loop iteration

You are dividing two ints which will only result in another int. So basically your code is do the following:
if n < 0:
x = x + 1 # move east
n = random.random() # generate a new random number
if n >= 0 and n < 1:
y = y + 1 # move north
n = random.random() # generate a new random number
if n >= 1:
z = z + 1 # move up
n = random.random()
fix by changing each if line to include a floating point number
if n < 1.0/3

Related

Python - Different result from while loop than when in a user defined function

I am trying to create a code that returns a approximation of pi given n iterations that the user will give. The higher n the more accurate.
I created a while loop to do this, and it works fine:
import math
x = 1
k = 0
n = int(input("Enter n:"))
while x <= n:
k=k+(1/x**2) # summation of 1/k**2 for every n times
y=k*6 # multiply k by 6 like in formula
fin = math.sqrt(y) # find sqrt of y like in the formula
x += 1
print(fin)
But now I'm trying to make this into a function. This is what I've come up with:
import math
def pi(n):
x = 1
k = 0
#n = int(input("Enter n:"))
while x <= n:
k=k+(1/x**2) # summation of 1/k**2 for every n times
y=k*6 # multiply k by 6 like in formula
fin = math.sqrt(y) # find sqrt of y like in the formula
x += 1
return fin
g=pi(int(input("Enter n:")))
print(g)
For some reason I get different answers... why is it when I use the function that the answer becomes inaccurate?
You have your return inside the loop, hence the block inside the while is executed only once and the rest of approximations are never calculated, put your return out of your cycle:
while x <= n:
k=k+(1/x**2) # summation of 1/k**2 for every n times
y=k*6 # multiply k by 6 like in formula
fin = math.sqrt(y) # find sqrt of y like in the formula
x += 1
return fin
I tested it, now it returns the same result with both approaches.
Have a good day! :D

How can I improve my spiral index function?

Introduction
I am taking an online Introduction to Computer Science course for which I was given the task to create a function that takes in a coordinate and returns its corresponding "spiral index". I have a working function, but the online learning platform tells me that my code takes too long to execute (I am currently learning about code complexity and Big O notation).
The Problem Statement
All numbers on an infinite grid that extends in all four directions can be identified with a single number in the following manner:
Where 0 corresponds with the coordinate (0, 0), 5 corresponds with the coordinate (-1, 0), and 29 with (3, 2).
Create a function which returns the spiral index of any pair of coordinates that are input by the user.
Examples:
spiral_index(10, 10) returns 380.
spiral_index(10, -10) returns 440.
spiral_index(3, 15) returns 882.
spiral_index(1000, 1000) returns 3998000.
My Approach
def spiral_index(x, y):
if x == 0 and y == 0:
return 0
pos = [1, 0]
num = 1
ring_up = 0
ring_left = 0
ring_down = 0
ring_right = 0
base = 3
while pos != [x, y]:
if ring_up < base - 2:
pos[1] += 1
ring_up += 1
num += 1
elif ring_left < base - 1:
pos[0] -= 1
ring_left += 1
num += 1
elif ring_down < base - 1:
pos[1] -= 1
ring_down += 1
num += 1
elif ring_right < base:
pos[0] += 1
ring_right += 1
num += 1
else:
base = base + 2
ring_up = 0
ring_left = 0
ring_down = 0
ring_right = 0
return num
The above code is able to find the correct index for every coordinate, and (on my laptop) computes spiral_index(1000, 1000) in just over 2 seconds (2.06).
Question
I have seen some solutions people have posted to a similar problem. However, I am wondering what is making my code so slow? To my knowledge, I believe that it is executing the function in linear time (is that right?). How can I improve the speed of my function? Can you post a faster function?
The course told me that a for loop is generally faster than a while loop, and I am guessing that the conditional statements are slowing the function down as well.
Any help on the matter is greatly appreciated!
Thanks in advance.
First of all, your solution takes two coordinates, A and B, and is O(AB), which can be considered quadratic. Second of all, the similar problem involves constructing the entire spiral, which means there is no better solution. You only have to index it, which means there's no reason to traverse the entire spiral. You can simply find which ring of the spiral you're on, then do some math to figure out the number. The center has 1 element, the next ring has 8, the next 16, the next 24, and it always increases by 8 from there. This solution is constant time and can almost instantly calculate spiral_index(1000, 1000).
def spiral_index(x, y):
ax = abs(x)
ay = abs(y)
# find loop number in spiral
loop = max(ax, ay)
# one less than the edge length of the current loop
edgelen = 2 * loop
# the numbers in the inner loops
prev = (edgelen - 1) ** 2
if x == loop and y > -loop:
# right edge
return prev + y - (-loop + 1)
if y == loop:
# top edge
return prev + loop - x + edgelen - 1
if x == -loop:
# left edge
return prev + loop - y + 2 * edgelen - 1
if y == -loop:
# bottom edge
return prev + x + loop + 3 * edgelen - 1
raise Exception("this should never happen")

Repeating if statement

I am having a problem with my code mapping a random walk in 3D space. The purpose of this code is to simulate N steps of a random walk in 3 dimensions. At each step, a random direction is chosen (north, south, east, west, up, down) and a step of size 1 is taken in that direction. Here is my code:
import random # this helps us generate random numbers
N = 30 # number of steps
n = random.random() # generate a random number
x = 0
y = 0
z = 0
count = 0
while count <= N:
if n < 1/6:
x = x + 1 # move east
n = random.random() # generate a new random number
if n >= 1/6 and n < 2/6:
y = y + 1 # move north
n = random.random() # generate a new random number
if n >= 2/6 and n < 3/6:
z = z + 1 # move up
n = random.random() # generate a new random number
if n >= 3/6 and n < 4/6:
x = x - 1 # move west
n = random.random() # generate a new random number
if n >= 4/6 and n < 5/6:
y = y - 1 # move south
n = random.random() # generate a new random number
if n >= 5/6:
z = z - 1 # move down
n = random.random() # generate a new random number
print("(%d,%d,%d)" % (x,y,z))
count = count + 1
print("squared distance = %d" % (x*x + y*y + z*z))
The problem is I am getting more than a single step between each iteration. I've added comments showing the difference in steps between iterations.
Here are the first 10 lines of the output:
(0,-1,0) #1 step
(0,-2,0) #1 step
(1,-3,1) #4 steps
(1,-4,1) #1 step
(1,-3,1) #1 step
(1,-2,1) #1 step
(2,-2,0) #2 steps
(2,-2,0) #0 steps
(2,-2,0) #0 steps
(2,-1,0) #1 step
If you remove the multiple n = random.random() from within the if statements and replace by a single n = random.random() at start of the while loop then there will be only one step per loop.
The issues lies with this line in each of your if statement : n = random.random(). Basically you should had used if and else if so if in a single iteration one if has been executed then it does not get executed again. Also you can add this line at the end of the all if statements instead of repeating it.n = random.random()
Replacing multiple if statements with chain of if-elif-else solved the problem. Also, you could iterate using for instead of while. And in addition - you don't need to regenerate n under each if.
import random # this helps us generate random numbers
N = 30 # number of steps
x = 0
y = 0
z = 0
for _ in range(N):
n = random.random() # generate a new random number
if n < 1/6:
x += 1 # move east
elif 1/6 <= n < 2/6:
y += 1 # move north
elif 2/6 <= n < 3/6:
z += 1 # move up
elif 3/6 <= n < 4/6:
x -= 1 # move west
elif 4/6 <= n < 5/6:
y -= 1 # move south
else:
z -= 1 # move down
print("(%d,%d,%d)" % (x, y, z))
print("squared distance = %d" % (x*x + y*y + z*z))
This is because you are setting n in each if-block which is satisfying next if blocks as well.
Just take out n = random.random() from all if blocks and place it just before end of while loop.
Tip:
To debug this I would've printed the value of n in each if case.

Simulating a random walk in Python

I am using Python 3. My code below attempts to simulate N steps of a random walk in 3 dimensions. At each step, a random direction is chosen (north, south, east, west, up, down) with 1/6 probability each and a step of size 1 is taken in that direction. The new location is then printed. The starting location is the origin (0,0).
Even though there are no error messages, the code does not work. We should move only one step either in x, y or z. However, in the output, I see that sometimes I don't move at all or sometimes I move in more than one direction.
Here is my code:
import random
N = 30
n = random.random()
x = 0
y = 0
z = 0
count = 0
while count <= N:
if n < 1/6:
x = x + 1
n = random.random()
if n >= 1/6 and n < 2/6:
y = y + 1
n = random.random()
if n >= 2/6 and n < 3/6:
z = z + 1
n = random.random()
if n >= 3/6 and n < 4/6:
x = x - 1
n = random.random()
if n >= 4/6 and n < 5/6:
y = y - 1
n = random.random()
if n >= 5/6:
z = z - 1
n = random.random()
print("(%d,%d,%d)" % (x,y,z))
count = count + 1
print("squared distance = %d" % (x*x + y*y + z*z))
How do you think I can fix the problem?
Thanks a lot.
You should use elif instead of so many ifs. Every time the if is evaluated, the value of n changes and then may qualify for the next if.
Not only should you use elif, even for performance, but you don't need the multiple n = random.random() statements in the loop -- one will do:
import random
N = 30
x = 0
y = 0
z = 0
for _ in range(N):
n = random.random()
if n < 1/6:
x += 1
elif 1/6 <= n < 2/6:
y += 1
elif 2/6 <= n < 3/6:
z += 1
elif 3/6 <= n < 4/6:
x -= 1
elif 4/6 <= n < 5/6:
y -= 1
elif n >= 5/6:
z -= 1
print(f"({x},{y},{z})") # python 3.6ism
print("squared distance = {}".format(x*x + y*y + z*z))
Regardless the version of Python you are using, you need to implement the answer provided by #cdlane.
If you are using Python 2.X your other problem is that Python is interpreting your numbers as ints. To fix that you need to add . to the denominator i.e.
if n < 1/6.:
instead of
if n < 1/6:
1/6 and other fractions are interpreted as ints - you can check it yourself by typing print 1/6 which will give you 0 or printing the actual type with print type(1/6) - which will yield <type 'int'>.
Because of that when you run your program all your ns will satisfy only the last condition (all will be greater than 0).

Infinite Sequence. Cannot process answer in 1 second

I want to find a number[i] of infinite sequence but it takes a long time in the following input.
Let's consider an infinite sequence of digits constructed of ascending powers of 10 written one after another. Here is the beginning of the sequence: 110100100010000... You are to find out what digit is located at the definite position of the sequence.
Input
There is the only integer N in the first line (1 ≤ N ≤ 65535). The i-th of N left lines contains the integer K[i] — the number of position in the sequence (1 ≤ K[i] ≤ 231 − 1).
Output
You are to output N digits 0 or 1 separated with a space. More precisely, the i-th digit of output is to be equal to the Ki-th digit of described above sequence.
INPUT
4
3
14
7
6
OUTPUT
0 0 1 0
Here's my code
x = input()
a = []
for i in range(x):
y = input()
a.append(y)
b = '1'
c = 1
for i in range(100):
c *= 10
b += str(c)
for i in range(x):
print b[a[i]-1],
You need to go beyond the basic description of the problem. If you generate the whole string, that'll be 2^31 characters long (and you'll need to go up to 65536, not 100). Fortunately, there is a better way. You don't really need the string. You just need a method to check if the character at a given index K[i] is 1.
The positions of all "1"s in the string correspond to the triangular numbers. The nth triangular number can be calculated via
x = n * (n + 1) / 2
By solving for n, we get
n = sqrt(2 * x + 0.25) - 0.5
If x is a triangular number, then n will be an integer, and the string will have a "1" on that position. Otherwise, a "0". Also, we have to use K[i] - 1, because the index in the problem is 1-based.
import math
import sys
f = lambda x: math.sqrt(2.0 * x + 0.25) - 0.5
g = lambda x: f(x) % 1 == 0
inp = map(int, sys.stdin.read().split()[1:])
print(" ".join("1" if g(x-1) else "0" for x in inp))
You should not generate a whole string here, rather than that use some maths. Here the numbers will be:
1
10
100
1000
10000
...
If you look at the series you'll notice that the 1's are at the position 1, 2, 4, 7, 11, ....
We can generalize this series using this formula (n^2 - n + 2)/2. So, the quadratic equation will become:
(n^2 - n + 2)/2 = i
#or n^2 - n + 2 - 2i
Where i is the current index coming from input.
Now, if for any i the output of b^2 - 4ac is a perfect square then it means the number is surely 1 otherwise it's 0.(Here value of a is 1, and b is -1 and we can calculate c using 2 - 2*i)
from math import sqrt
def solve(i):
b = -1
a = 1
c = 2 - 2 * i
val = (b**2) - (4*a*c)
sq = sqrt(val)
if int(sq) == sq:
return 1
return 0
for _ in xrange(input()):
print solve(input()),
Demo:
$ python so.py < foo.txt
0 0 1 0
It maybe take a lot of time because you are constructing the complete sequence of digits of ascending powers of 10. If you analyze the structure of the sequence you can notice some patter.
The patter in combination with the fact sum_{i=1}^n = (n+1)*n/2 gives the next solution, where the function digit_pow_10 can determinate directly if the digit in the position y is 1 or 0, without construction the complete sequence. If you need more details please contact me
import math
def digit_pow_10(y):
n = int(math.sqrt(0.25+2*y)-0.5)
diff = y - int(n*(n+1)/2.0)
if diff == 1 or y == 1:
return 1
else:
return 0
x = input()
for i in range(x):
y = input()
a.append(y)
for y in a:
print digit_pow_10(y),

Categories