I'm new to Python and have no experience with QBasic. I was running a simulation in Python that came up with theoretically wrong values. I then ran it in QBasic and came up with theoretically predicted values.
Here are the test cases. I'm only counting the probability P(0.9<%Y<=1.8) so the count has to fall within those values. The 1-random.random() was only for that case, when I tried using that for all the cases they still came up with the wrong values. Here's the theoretical outcomes and you can see how it's different:
y~u(0,1)
= 0.575
y~exp(2)
= 0.3371
x1~u(0,1)
x2~u(0,2)
= 0.4475
P(y=0.25)=0.8
P(y=1.5)=0.2
= 0.32
In Python the simulation code is:
def test():
x1,x2,c = 0.0,0.0,0.0
for i in range(10000):
if random.random()< 0.8:
x1 += 0.25
else:
x2 += 1.5
y = x1 + x2
if y>0.9 and y<=1.8:
c = c + 1
return x1,x2,c
print "test: ",test()
def sim(a,b):
#pyab1 = sum([a for a in a if a>0.9 and a<=1.8])/10000
#pyab2 = sum([b for b in b if b>0.9 and b<=1.8])/10000
#print "*****",float(pyab1+pyab2)
#print a+b
#array1 = [[a],[b]]
array1 = a+b
#array1.extend(a)
#array1.extend(b)
#c = 0
#for y in array1:
#if y>0.9 and y<=1.8:
#c = c + 1
pyab = sum([y for y in array1 if y>0.9 and y<=1.8])/10000
print("P(a < x <= b) : {0:8.4f}".format(pyab))
Here's the Python output followed by the values it's supposed to give, but this shows how far off the results are.
case 1: P(a < x <= b) : 0.7169 #should be 0.575
case 2: P(a < x <= b) : 0.4282 #should be 0.3371
case 3: P(a < x <= b) : 0.5966 #should be 0.4475
case 4: P(a < x <= b) : 0.5595 #should be 0.32
In QBasic the simulation code is:
Case 1:
RANDOMIZE
FOR i = 1 TO 10000
X1 = RND(1)
X2 = RND(1)
Y = X1+X2
IF (Y>0.9) AND (Y<=1.8) THEN C=C+1
NEXT i
PRINT C/10000
Case 2:
RANDOMIZE
FOR i = 1 TO 10000
X1 = (-0.5)*(LOG(1-RND(1)))
X2 = (-0.5)*(LOG(1-RND(1)))
Y = X1+X2
IF (Y>0.9) AND (Y<=1.8) THEN C=C+1
NEXT i
PRINT C/10000
Case 3:
RANDOMIZE
FOR i = 1 TO 10000
X1 = RND(1)
X2 = RND(1)*2
Y = X1+X2
IF (Y>0.9) AND (Y<=1.8) THEN C=C+1
NEXT i
PRINT C/10000
Case 4:
RANDOMIZE
FOR i = 1 TO 10000
X14 = RND(1)
X24 = RND(1)
IF (X14<0.8) THEN X41=0.25 ELSE X41=1.5
IF (X24<0.8) THEN X42=0.25 ELSE X42=1.5
Y = X1+X2
IF (Y>0.9) AND (Y<=1.8) THEN C=C+1
NEXT i
PRINT C/10000
Here's the QBasic output, which shows how this is actually getting the right results.
case 1: P(a < x <= b) : 0.5715
case 2: P(a < x <= b) : 0.3371
case 3: P(a < x <= b) : 0.4413
case 4: P(a < x <= b) : 0.3213
All of the above code works for me without error. I don't see any differences in the algorithm used to get the values. Not sure if Python generates numbers differently from QBasic, and if that accounts for the reason behind this behavior.
I'm new to both of these languages but QBasic seems very primitive, and it would seem more likely that Python would get the right answer and QBasic the wrong one. But the opposite is happening. It doesn't appear to be something related to any difference in code. On translation, they both seem to be saying the same thing.
I'm interested in the reason why they give the 2 different outcomes. I'm more interested in why Python is giving the wrong answers and QBasic is giving the right ones.
Your Python code is totally wrong. What I think you want it to do is the following:
Take two arrays, a and b, each containing 10000 numbers generated by some random function. (Equivalently, each an array of 10000 samples from data following some given distribution.)
Pair up the values into 10000 pairs, with each pair taking an element from a and an element from b.
Take the sum of each pair.
Count how many of those 10000 pair-sums lie between 0.9 and 1.8
Divide the above count by 10000 to get the probability that any given pair of data drawn from these distributions will sum to between 0.9 and 1.8, and print that probability.
However, your sim(a, b) function is doing something wildly different. Basically, what you're actually doing is:
Concatenate the two 10000 element arrays, forming a 20000-element array of their elements.
Take the sum of any elements in this new 20000-element array that are greater than 0.9.
Divide that sum by 10000 and print it.
This algorithm bears no resemblance to anything in your Q-Basic code.
If I've understood your problem properly, I think what you want your sim function to be is this:
def sim(x_sample, y_sample):
count = 0
for i in range(10000):
if 0.9 <= x_sample[i] + y_sample[i] <= 1.8:
count += 1
probability = count/10000.0
print("P(a < x <= b) : {0:8.4f}".format(probability))
(There are almost certainly more elegant and Pythonic ways to implement the above function, but this way should be easy for a Python newbie to understand.)
Here are the results of tests I ran in the interpreter for your cases 1 to 3, as I've understood them from the QBasic program. I haven't included a version of test 4 because I didn't understand the QBasic code for test 4. The results for the first three tests are what you said they should be, though.
>>> from random import random
>>>
>>> sim([random() for i in range(10000)],
... [random() for i in range(10000)])
P(a < x <= b) : 0.5746
>>>
... from math import log
>>>
>>> sim([-0.5*log(1-random()) for i in range(10000)],
... [-0.5*log(1-random()) for i in range(10000)])
P(a < x <= b) : 0.3405
>>>
... sim([random() for i in range(10000)],
... [2*random() for i in range(10000)])
P(a < x <= b) : 0.4479
Related
I am very new to Julia and was trying to implement/rewrite some of my previous Python code as practice. I was using the Project Euler problem 25 as practice
In Python I have
def fibonacci(N):
"""Returns the Nth Fibonacci Number"""
F = [0, 1]
i = 0
while i <= N-2:
F_new = F[i] + F[i+1]
F.append(F_new)
i += 1
return F[N]
N = 0
x = 1000
while len(str(fibonacci(N))) <= x:
if len(str(fibonacci(N))) == x:
print(N)
break
N = N + 1
Which runs and gives me the correct answer in about 6.5 seconds. When trying to do this in Julia below
function fib(N)
F = [0, 1]
global i = 1
while i <= N-2
F_new = F[i] + F[i+1]
append!(F, F_new)
global i += 1
end
return F[N]
end
N = 1
x = 1000
while length(string(fib(N))) <= x
if length(string(fib(N))) == x
print(N-1)
break
end
global N += 1
end
The code seems to run "forever". However in the Julia code only when x<= 20 will the code finish and produce the correct answer. In the Julia code when x>20 the program never ends.
I'm not sure where something could go wrong if it runs for all values below 21? Could somebody explain where the error is happening and why?
Python integers are by default unbounded in size and will grow as needed. Julia on the other hand will default to a signed 64 bit integer if on a 64 bit system. (See docs) This begins to overflow when trying to calculate values above around 19 digits long, hence why this starts around x=20. In order to get the same behavior in Julia, you should use the BigInt type for any values or arguments which can get above this size.
The main problem with your code is what #duckboycool has described. The second advice is to always write functions in Julia. Read the Julia performance tips page for a good start.
Note that you can make the function by #Bill 2X faster by removing the unnecessary if like this:
function test(x = 1000)
N = 0
while ndigits(fib(N)) < x
N += 1
end
return N
end
But if you really want a 16000X faster Julia version, then you can do this:
function euler25()
limit = big(10)^999
a, b = big(1), big(1)
N = 2
while b <= limit
a, b = b, a + b
N += 1
end
return N
end
#btime euler25() = 4782
377.700 μs (9573 allocations: 1.15 MiB)
This runs in 377 μs, because we avoid calculating fib(N) at every step from the beginning. And instead of comparing with the length of a string of the output at each iteration, we just compare with 10^999.
In addition to the earlier answer, note that you should avoid globals if looking at performance, so this is much faster than your global i and x code:
function fib(N)
F = [big"0", big"1"]
for i in 1:N-2
F_new = F[i] + F[i+1]
push!(F, F_new)
end
return F[N]
end
function test(x = 1000)
N = 1
while length(string(fib(N))) <= x
if length(string(fib(N))) == x
print(N-1)
break
end
N += 1
end
end
test()
#AboAmmar shows probably the best "normal" way of writing this. But if you want something even a bit more optimized, you can use in-place BigInt calls. I'm not sure whether I would recommend this, but it's nice to be aware of it.
using Base.GMP.MPZ: add!, set!
function euler25_(limit=big(10)^999)
a, b = big(1), big(1)
N = 2
c = big(0)
while b <= limit
add!(c, a, b)
set!(a, b)
set!(b, c)
N += 1
end
return N
end
This uses the special BigInt functions in the GMP.MPZ library, and writes values in-place, avoiding most of the allocations, and running 2.5x faster on my laptop.
Let a,b,c be the first digits of a number (e.g. 523 has a=5, b=2, c=3). I am trying to check if abc == sqrt(a^b^c) for many values of a,b,c. (Note: abc = 523 stands for the number itself.)
I have tried this with Python, but for a>7 it already took a significant amount of time to check just one digit combination. I have tried rewriting the equality as multiple logs, like log_c[log_b[log_a[ (abc)^2 ]]] == 1, however, I encountered Math Domain Errors.
Is there a fast / better way to check this equality (preferably in Python)?
Note: Three digits are an example for StackOverflow. The goal is to test much higher powers with seven to ten digits (or more).
Here is the very basic piece of code I have used so far:
for a in range(1,10):
for b in range(1,10):
for c in range(1,10):
N = a*10**2 + b*10 + c
X = a**(b**c)
if N == X:
print a,b,c
The problem is that you are uselessly calculating very large integers, which can take much time as Python has unlimited size for them.
You should limit the values of c you test.
If your largest possible number is 1000, you want a**b**c < 1000**2, so b**c < log(1000**2, a) = 2*log(1000, a)), so c < log(2*log(1000, a), b)
Note that you should exclude a = 1, as any power of it is 1, and b = 1, as b^c would then be 1, and the whole expression is just a.
To test if the square root of a^b^c is abc, it's better to test if a^b^c is equal to the square of abc, in order to avoid using floats.
So, the code, that (as expected) doesn't find any solution under 1000, but runs very fast:
from math import log
for a in range(2,10):
for b in range(2,10):
for c in range(1,int(log(2*log(1000, a), b))):
N2 = (a*100 + b*10 + c)**2
X = a**(b**c)
if N2 == X:
print(a,b,c)
You are looking for numbers whose square root is equal to a three-digit integer. That means your X has to have at most 6 digits, or more precisely log10(X) < 6. Once your a gets larger, the potential solutions you're generating are much larger than that, so we can eliminate large swathes of them without needing to check them (or needing to calculate a ** b ** c, which can get very large: 9 ** 9 ** 9 has 369_693_100 DIGITS!).
log10(X) < 6 gives us log10(a ** b ** c) < 6 which is the same as b ** c * log10(a) < 6. Bringing it to the other side: log10(a) < 6 / b ** c, and then a < 10 ** (6 / b ** c). That means I know I don't need to check for any a that exceeds that. Correcting for an off-by-one error gives the solution:
for b in range(1, 10):
for c in range(1, 10):
t = b ** c
for a in range(1, 1 + min(9, int(10 ** (6 / t)))):
N = a * 100 + b * 10 + c
X = a ** t
if N * N == X:
print(a, b, c)
Running this shows that there aren't any valid solutions to your equation, sadly!
a**(b**c) will grow quite fast and most of the time it will far exceed three digit number. Most of the calculations you are doing will be useless. To optimize your solution do the following:
Iterate over all 3 digit numbers
For each of these numbers square it and is a power of the first digit of the number
For those that are, check if this power is in turn a power of the second digit
And last check if this power is the third digit
I've been trying to figure this out for ages but with no luck. I need to round each coefficient to the nearest integer.
To do this I introduce a small number dq=0.0001. If a[0]=0.5, then round(a[0]) = 0.0; this is clearly not good. However, to work around this introduce dq: round(a[0]+dq) = round(0.5001) = 1.0; this is good.
For negatives such as a[2] = -0.5: round(a[2]-dq) = round(-0.5001) = -1.0. I take into account the negatives using if statements. This is my code which does not return the right value:
a= 0.5,0.5,-0.5,-0.5
dq = 0.0001 #small number
b = round(a[0]+dq), round(a[1]+dq), round(a[2]+dq), round(a[3]+dq)
if a[0] < 0:
b[0] == round(a[0]-dq)
if a[1] < 0:
b[1] == round(a[1]-dq)
if a[2] < 0:
b[2] == round(a[2]-dq)
if a[3] < 0:
b[3] == round(a[3]-dq)
print(b)
Output:
(1,1,0,0)
Clearly it is the if statements that are dysfunctional.
P.s. and I need to be able to use the resulting b in later calculations.
perhaps you could just use something like
a = [0.5, 0.5, -0.5, -0.5]
print(list(map(lambda v: int(round(v + (dq if v > 0 else -dq))), a)))
this yields
[1, 1, -1, -1]
However, an alternative would be:
x = 0.49999 #just slightly less than 0.5
round(x)
>>> 0.0
#first round to 2 digits and then to an "integer"
round(round(x, 2))
>>> 1.0
You can probably do it in a smarter way, but here's a quick solution to your problem. First of all, use a for loop to round the elements of a. a is a tuple, by the way, so you could loop through its elements.
Second of all, your logic is at fault above. If an element of a is positive, i.e. > 0, you should add the dq instead of subtracting, as you mentioned yourself.
In [53]: for i in a:
...: if i < 0:
...: print(round(i-dq))
...: else:
...: print(round(i+dq))
...:
...:
1.0
1.0
-1.0
-1.0
If I understand your problem correctly, you'd like negative numbers to be rounded down to the nearest integer and positive numbers to be rounded up to the nearest integer. If that's the case, you could use math.ceil and math.floor:
import math
def my_round(x):
if x < 0:
return math.floor(x)
if x >= 0:
return math.ceil(x)
my_round(0.5) # 1
my_round(-0.5) # -1
This is my assignment and for the life of me i cant seem to think of a way to do it. This is the code I have so far:
sum = 0
k = 1
while k <= 0.0001:
if k % 2 == 1:
sum = sum + 1.0/k
else:
sum = sum - 1.0/k
k = k + 1
print()
This is my assignment :
Create a python program named sumseries.py that does the following:
Put comments at the top of your program with your name, date, and
description of what the program does.
Write a program to calculate and display the sum of the series:
1 - 1/2 + 1/3 - 1/4 + ...
until a term is reached that is less than 0.0001.
The answer with 10,000 iterations appears to be 0.6930971830599583
I ran the program with 1,000,000,000 (billion) iterations and came up with a number of 0.6931471810606472. I need to create a loop to programmably create the series.
Actually, you could write this shorter:
Answer = sum(1.0 / k if k % 2 else -1.0 / k for k in range(1, 10001))
What this code does:
the innermost part is a generator expression, which computes the elements of a series 'on the fly'
1.0 / k if k % 2 else -1.0 / k results in 1.0 / k if k is odd and -1.0 / k otherwise (a - b is the same as a + (-b))
for k in range(1, 10001) goes through all ks in range from 1 (included) to 10001 (excluded)
sum can compute the sum of any sequence (any iterable, to be precise), be it a list, a tuple, or a generator expression
The same without generator expressions:
Answer = 0
for k in range(1, 10001):
if k % 2:
Answer += 1.0 / k
else:
Answer -= 1.0 / k
# or simply:
# Answer += 1.0 / k if k % 2 else -1.0 / k
You're almost there, all you need to do is to replace
while k <= 0.0001:
with:
while term <= 0.0001:
term is naturally 1/k
To make the teacher happy, you must follow the details of the problem, as well as the spirit of the problem. The problem clearly states to print the sum, not all the partial sums. You will anger the teacher by submitting a solution that spews 10000 lines of crap not requested.
Some have suggested pre-calculating a loop limit of 10000, but that was not the requested algorithm. Instead, one is to calculate successive terms (1, -1/2, 1/3, -1/4, ...) until reaching a term less than 0.0001.
The reason the problem was specified that way is that one ends up with a more generally useful program, applicable to a wide class of term formulas. Not a fragile one that gets the wrong answer if the term formula is changed from (-1)**(k-1)/k, to say 1/k or 1/k^2.
The teacher's wording "term less than 0.0001" is imprecise and assumed some math knowledge. They want the magnitude (absolute value) of the term to be less than 0.0001. Otherwise, iteration would stop at the second term -1/2, as someone pointed out.
So, this answer would not be complete without a pompous pedantic solution that skips ahead a chapter. ;) Note that previous some answers will not work in Python2.x without a conversion to float.
def term(k):
return (-1)**(k - 1) / float(k)
err = 0.0001
def terms():
k = 1
t = term(k)
while abs(t) >= err:
yield t
k += 1
t = term(k)
print(sum(terms()))
Here is the answer your teacher is looking for for full credit.
until < .0001 means while >= 0.0001 This modifies your code the least, so makes it a correction of what you wrote
sum = 0
k = 1
while 1.0/k >= 0.0001:
if k % 2 == 1:
sum = sum + 1.0/k
else:
sum = sum - 1.0/k
k = k + 1
print(sum)
Absolutly simplest way would be the following
sum((-1)**(k) / k for k in range(1, 10001))
I'm completely new to python and coding in general, it's probably some ridiculously obvious error but I can't figure out why this while loop won't break.
I'm trying to find the value of t when y is equal to 0. When changing t manually, y is less than 0 when t is just under 2.5.
Unfortunately I don't have anyone else I can ask for right now. Thanks!
t = 0
y0 = 1.8
v0 = 15.0
theta0 = 0.785398163
vy0 = v0*sin(theta0)
ay0 = -9.81
y = y0 + vy0*t + 0.5*ay0*t**2
while y > 0:
print(t)
t += 0.25
if y < 0:
break
print(t)
You need to include your equation in the loop so that the value of y changes each time you increase t. Like this:
while y > 0:
y = y0 + vy0*t + 0.5*ay0*t**2
print(t)
t += 0.25
if y < 0:
break print(t)
You could restructure your loop as follows:
t = 0
y0 = 1.8
v0 = 15.0
theta0 = 0.785398163
vy0 = v0*sin(theta0)
ay0 = -9.81
y = 1 # dummy start value
while y >= 0:
y = y0 + vy0*t + 0.5*ay0*t**2
print("t={}, y={}".format(t,y))
t += 0.25
This would then also display all of the values as it loops, so you can see it working:
t=0, y=1.8
t=0.25, y=4.145087928395659
t=0.5, y=5.8770508567913184
t=0.75, y=6.9958887851869775
t=1.0, y=7.501601713582638
t=1.25, y=7.394189641978297
t=1.5, y=6.673652570373955
t=1.75, y=5.339990498769618
t=2.0, y=3.3932034271652753
t=2.25, y=0.8332913555609345
t=2.5, y=-2.3397457160434065
By adding a dummy start value, it ensures that the loop will be entered, and avoids the need to also add a break statement within the loop.
From these results you can see there is a solution somewhere between 2.25 and 2.5. You could then change your start value to say t = 2.25 and change the increment to t += 0.01 and you would see a slightly more accurate estimation.
while y > 0
at this line loop will start when y > 0, but then you didn't change the value of y during while loop then how if y < 0 this statement will execute.
And your y = 1.8 after calculating y = y0 + vy0*t + 0.5*ay0*t**2 so it is an infinite loop as y > 0 is all time true.
As you can see from other answers, you need to move your equation to inside the while loop.
In programming the assignment operator (this thing: =) does not create relationships between variables. It (usually) simply takes what is on the right and puts it in what is on the left.
Consider this code:
y = 0
x = y+1
y = 33
print x
It will print out 1.
y+1 gets evaluated to 0+1 then 1.
Then x gets set to the integer value of 1.
Changing y will not do anything because x was set to the specific value of that expression at that specific time, not to a reference.
You might have noticed the "usually" in my definition of the assignment operators, that's because references do exist in programming and specifically in python. For example this happens when you set a variable equal to an uninstantiated class, but at this point understanding that is not necessary.