Can One Decrease Overall Accuracy in Python? - python-3.x

I'm making a program to calculate primes, and I look at the remainder of the possible prime I'm testing and all the primes I have so far, but stop if I get to the point where I am comparing the PossPrime to anything above its square root. (I can explain this if needed). I don't care about any digits after the decimal point of the sqrt; is there a way to tell Python not to bother calculating those?
And, is there a way to integrate that aspect (only testing the primes under it until I get to the sqrt) into the for loop?
#There's some boring setup before here that isn't problematic.
while True:
PossWasDivis = False #initialize the var (used to convey if the possible prime was divis)
sqrtP = int(sqrt(PossPrime))
for iterationOfArray in range(2, sqrtP):
# print ("Comparing: (", PossPrime, "% (", GlobPrimeList [iterationOfArray],")) == 0")
if (PossPrime % (GlobPrimeList [iterationOfArray])) == 0:
# print(PossPrime, "was divisable by", GlobPrimeList[iterationOfArray],"! Breaking for loop")
PossWasDivis = True
break
if (GlobPrimeList [iterationOfArray]) > sqrtP:
break
if PossWasDivis == False: # Occurs when none of the tested #s are divis
GlobPrimeList.append (PossPrime)
f.write(str(PossPrime)+'\n')
#Switch between incramenting PossPrime between 2 and 4
if PossPrimeStat == 2:
PossPrimeStat = 4
PossPrime += 4
else: # if PossPrimeStat == 4:
PossPrimeStat = 2
PossPrime += 2
The GlobPrimeList has some primes preloaded in it to start out with and continues finding more indefinitely until I cancel the program.

I don't care about any digits after the decimal point of the sqrt; is there a way to tell Python not to bother calculating those?
Nope.
math.sqrt() works with floating-point values. The precision you get is baked right in to the math.
Python does contain functions for "arbitrary-precision" math, where you can specify how much precision you will get... but those functions are much slower than the functions that operate on float values. If you want faster code, you will be using float values, and there is no way to tell Python not compute the whole value.

Related

How to skew random choice probability towards one option?

I am using the random library in python to select win or lose.
import random
choice = random.choice(['win','lose'])
Is there anyway I can say set the probability in the code to say I want more lose than win everytime the code runs?
Well, #CloC is technically right, you could do that, but better use the standard Python library as it is designed, less code, less bugs
F.e., sampling with probability of Win being 60%
v = random.choices(["Win", "Lose"], weights=[60, 40], k=1)
A way to control random (which wont be random...) would be to:
Generate a number between 1 and 100:
n = random.randint(1,101)
and then compare it with the percentage of win/loses you want :
chances_to_win = 51 # 50%
if n < chances_to_win:
print(str(chances_to_win-1) +"% chances to Win")
choice = "Win"
else:
print(str(100-(chances_to_win-1)) +"% chances to Lose")
choice = "Lose"
That way, you can control what is the percentage of wins and loses.

How can I reduce the time complexity of the given python code?

I have this python program which computes the "Square Free Numbers" of a given number. I'm facing problem regarding the time complexity that is I'm getting the error as "Time Limit Exceeded" in an online compiler.
number = int(input())
factors = []
perfectSquares = []
count = 0
total_len = 0
# Find All the Factors of the given number
for i in range(1, number):
if number%i == 0:
factors.append(i)
# Find total number of factors
total_len = len(factors)
for items in factors:
for i in range(1,total_len):
# Eleminate perfect square numbers
if items == i * i:
if items == 1:
factors.remove(items)
count += 1
else:
perfectSquares.append(items)
factors.remove(items)
count += 1
# Eleminate factors that are divisible by the perfect squares
for i in factors:
for j in perfectSquares:
if i%j == 0:
count +=1
# Print Total Square Free numbers
total_len -= count
print(total_len)
How can I reduce the time complexity of this program? That is how can I reduce the for loops so the program gets executed with a smaller time complexity?
Algorithmic Techniques for Reducing Time Complexity(TC) of a python code.
In order to reduce time complexity of a code, it's very much necessary to reduce the usage of loops whenever and wherever possible.
I'll divide your code's logic part into 5 sections and suggest optimization in each one of them.
Section 1 - Declaration of Variables and taking input
number = int(input())
factors = []
perfectSquares = []
count = 0
total_len = 0
You can easily omit declaration of perfect squares, count and total_length, as they aren't needed, as explained further. This will reduce both Time and Space complexities of your code.
Also, you can use Fast IO, in order to speed up INPUTS and OUTPUTS
This is done by using 'stdin.readline', and 'stdout.write'.
Section 2 - Finding All factors
for i in range(1, number):
if number%i == 0:
factors.append(i)
Here, you can use List comprehension technique to create the factor list, due to the fact that List comprehension is faster than looping statements.
Also, you can just iterate till square root of the Number, instead of looping till number itself, thereby reducing time complexity exponentially.
Above code section guns down to...
After applying '1' hack
factors = [for i in range(1, number) if number%i == 0]
After applying '2' hack - Use from_iterable to store more than 1 value in each iteration in list comprehension
factors = list( chain.from_iterable(
(i, int(number/i)) for i in range(2, int(number**0.5)+1)
if number%i == 0
))
Section 3 - Eliminating Perfect Squares
# Find total number of factors
total_len = len(factors)
for items in factors:
for i in range(1,total_len):
# Eleminate perfect square numbers
if items == i * i:
if items == 1:
factors.remove(items)
count += 1
else:
perfectSquares.append(items)
factors.remove(items)
count += 1
Actually you can completely omit this part, and just add additional condition to the Section 2, namely ... type(i**0.5) != int, to eliminate those numbers which have integer square roots, hence being perfect squares themselves.
Implement as follows....
factors = list( chain.from_iterable(
(i, int(number/i)) for i in range(2, int(number**0.5)+1)
if number%i == 0 and type(i**0.5) != int
))
Section 4 - I think this Section isn't needed because Square Free Numbers doesn't have such Restriction
Section 5 - Finalizing Count, Printing Count
There's absolutely no need of counter, you can just compute length of factors list, and use it as Count.
OPTIMISED CODES
Way 1 - Little Faster
number = int(input())
# Find Factors of the given number
factors = []
for i in range(2, int(number**0.5)+1):
if number%i == 0 and type(i**0.5) != int:
factors.extend([i, int(number/i)])
print([1] + factors)
Way 2 - Optimal Programming - Very Fast
from itertools import chain
from sys import stdin, stdout
number = int(stdin.readline())
factors = list( chain.from_iterable(
(i, int(number/i)) for i in range(2, int(number**0.5)+1)
if number%i == 0 and type(i**0.5) != int
))
stdout.write(', '.join(map(str, [1] + factors)))
First of all, you only need to check for i in range(1, number/2):, since number/2 + 1 and greater cannot be factors.
Second, you can compute the number of perfect squares that could be factors in sublinear time:
squares = []
for i in range(1, math.floor(math.sqrt(number/2))):
squares.append(i**2)
Third, you can search for factors and when you find one, check that it is not divisible by a square, and only then add it to the list of factors.
This approach will save you all the time of your for items in factors nested loop block, as well as the next block. I'm not sure if it will definitely be faster, but it is less wasteful.
I used the code provided in the answer above but it didn't give me the correct answer. This actually computes the square free list of factors of a number.
number = int(input())
factors = [
i for i in range(2, int(number/2)+1)
if number%i == 0 and int(int(math.sqrt(i))**2)!=i
]
print([1] + factors)

Keep Getting ZeroDivisonError Whenever using module

So I am working on a problem which need me to get factors of a certain number. So as always I am using the module % in order to see if a number is divisible by a certain number and is equal to zero. But when ever I am trying to do this I keep getting an error saying ZeroDivisionError . I tried adding a block of code like this so python does not start counting from zero instead it starts to count from one for potenial in range(number + 1): But this does not seem to work. Below is the rest of my code any help will be appreciated.
def Factors(number):
factors = []
for potenial in range(number + 1):
if number % potenial == 0:
factors.append(potenial)
return factors
In your for loop you are iterating from 0 (range() assumes starting number to be 0 if only 1 argument is given) up to "number". There is a ZeroDivisionError since you are trying to calculate number modulo 0 (number % 0) at the start of the for loop. When calculating the modulo, Python tries to divide number by 0 causing the ZeroDivisionError. Here is the corrected code (fixed the indentation):
def get_factors(number):
factors = []
for potential in range(1, number + 1):
if number % potential == 0:
factors.append(potential)
return factors
However, there are betters ways of calculating factors. For example, you can iterate only up to sqrt(n) where n is the number and then calculate "factor pairs" e.g. if 3 is a factor of 15 then 15/3 which is 5 is also a factor of 15.
I encourage you to try an implement a more efficient algorithm.
Stylistic note: According to PEP 8, function names should be lowercase with words separated by underscores. Uppercase names generally indicate class definitions.

Python 3.3.2 - Calculating the Carrying of Numbers

Remember back in primary school where you learn to carry numbers?
Example:
123
+ 127
-------
250
You carry the 1 from 3+7 over to the next column, and change the first column to 0?
Anyway, what I am getting at is that I want to make a program that calculates how many carries that the 2 numbers make (addition).
The way I am doing it, is that I am converting both numbers to strings, splitting them into individuals, and turning them back into integers. After that, I am going to run through adding 1 at a time, and when a number is 2 digits long, I will take 10 off it and move to the next column, calculating as I go.
The problem is, I barely know how to do that, and it also sounds pretty slow.
Here is my code so far.
numberOne = input('Number: ')
numberTwo = input('Number: ')
listOne = [int(i) for i in str(numberOne)]
listTwo = [int(i) for i in str(numberTwo)]
And then... I am at a loss for what to do. Could anyone please help?
EDIT:
Some clarification.
This should work with floats as well.
This only counts the amount of times it has carried, not the amount of carries. 9+9+9 will be 1, and 9+9 will also be 1.
The numbers are not the same length.
>>> def countCarries(n1, n2):
... n1, n2 = str(n1), str(n2) # turn the numbers into strings
... carry, answer = 0, 0 # we have no carry terms so far, and we haven't carried anything yet
... for one,two in itertools.zip_longest(n1[::-1], n2[::-1], fillvalue='0'): # consider the corresponding digits in reverse order
... carry = int(((int(one)+int(two)+carry)//10)>0) # calculate whether we will carry again
... answer += ((int(one)+int(two)+carry)//10)>0 # increment the number of carry terms, if we will carry again
... carry += ((int(one)+int(two)+carry)//10)>0 # compute the new carry term
... return answer
...
>>> countCarries(127, 123)
1
>>> countCarries(127, 173)
2

Heron method in Python

Heron's method generates a sequence of numbers that represent better and better approximations for √n. The first number in the sequence is an arbitrary guess; every other number in the sequence is obtained from the previous number prev using the formula:
(1/2)*(prev+n/prev)
I am supposed to write a function heron() that takes as input two numbers: n and error. The function should start with an initial guess of 1.0 for √n and then repeatedly generate better approximations until the difference (more precisely, the absolute value of the difference) between successive approximations is at most error.
usage:
>>> heron(4.0, 0.5)
2.05
>>> heron(4.0, 0.1)
2.000609756097561
this is a bit tricky, but I will need to keep track of four variables:
# n, error, prev and current
I will also need a while loop with the condition:
((current - prev) > error):
A general rule for the while loop is that:
# old current goes into new prev
So this is what I got so far, it's not much because to start with I don't know how to incorporate the 'if' statement under the while loop.
def heron(n, error):
guess = 1
current = 1
prev = 0
while (current - prev) > error:
previous==1/2*(guess+n/guess):
print (previous) # just a simple print statement
# in order to see what i have so far
Can someone give me a few pointers in the right direction please?
thank you
If you don't want to use generators then the simplest would be:
def heron(n, error):
prev, new = 1.0, 0.5 * (1 + n)
while abs(new - prev) > error:
prev, new = new, 0.5 * (new + n/new)
return new
You can also generate an "infinite" sequence of heron numbers:
def heron(n):
prev = 1.0
yield prev, float('inf')
while True:
new = 0.5 * (prev + n/prev)
error = new - prev
yield new, error
prev = new
Now you can print so many numbers as you like, for example:
list(islice(heron(2), 3)) # First 3 numbers and associated errors
Generate as long as the error is greater than 0.01:
list(takewhile(lambda x:x[1] > 0.01, heron(2)))
Just to build on #elyase's answer, here's how you would get the arbitrary precision square root from the heron number generator they have provided. (the generator just gives the next number in the heron sequence)
def heron(n): ### posted by elyase
a = 1.0
yield a
while True:
a = 0.5 * (a + n/a)
yield a
def sqrt_heron(n, err):
g = heron(n)
prev = g.next()
current = g.next()
while( (prev - current) > err):
prev = current
current = g.next()
print current, prev
return current
print sqrt_heron(169.0,0.1)
Aside from python syntax, the thing that may be messing you up is that you need two guesses calculated from your initial guess to get started, and you compare how far apart these two guesses are. The while condition should be (prev - current) > err not (current - prev) > err since we expect the previous guess to be closer to the square (and therefore larger) than the current guess which should be closer to the square root. Since the initial guess could be any positive number, we need to calculate two iterations from it, to ensure that current will be less than prev.
The other answers up as I write this are using a Python generator function. I love generators but those are overkill for this simple problem. Below, solutions with simple while loops.
Comments below the code. heron0() is what you asked for; heron() is my suggested version.
def heron0(n, error):
guess = 1.0
prev = 0.0
while (guess - prev) > error:
prev = guess
guess = 0.5*(guess+n/guess)
print("DEBUG: New guess: %f" % guess)
return guess
def _close_enough(guess, n, allowed_error):
low = n - allowed_error
high = n + allowed_error
return low <= guess**2 <= high
def heron(n, allowed_error):
guess = 1.0
while not _close_enough(guess, n, allowed_error):
guess = 0.5*(guess+n/guess)
print("DEBUG: New guess: %f" % guess)
return guess
print("Result: %f" % heron0(4, 1e-6))
print("Result: %f" % heron(4, 1e-6))
Comments:
You don't really need both guess and current. You can use guess to hold the current guess.
I don't know why you were asking about putting an if statement in the while loop. In the first place, it is easy: you just put it in, and indent the statement(s) that are under the if. In the second place, this problem doesn't need it.
It's easy and fast to detect whether guess is close to prev. But I think for numerical accuracy, it would be better to directly test how good a square root guess actually is. So, square the value of guess and see if that is close to n. See how in Python it is legal to test whether a value is, at the same time, greater than or equal to a lower value and also less than or equal to a high value. (The alternate way to check: abs(n - guess**2) <= allowed_error)
In Python 2.x, if you divide an integer by an integer you will probably get an integer result. Thus 1/2 can very possibly have a result of 0. There are a couple of ways to fix that, or you can run your program in Python 3.x which guarantees that 1/2 returns 0.5, but it's simple to make your starting value for guess be a floating-point number.
I think this meets your requirements (note: I wrote it with python 2.7.10): it doesn't assume a guess of 1 and it takes takes 'num' and 'tolerance' as arguments for 'n' and 'error'. Also, it doesn't use variables "prev" and "current" or a while loop - are those part of your requirements, or your thoughts regarding a solution?
def heron(num, guess, tolerance):
if guess**2 != num:
##print "guess =", guess
if abs(float(num) - float(guess)**2) > float(tolerance):
avg_guess = 0.5 * (float(guess) + (float(num) / float(guess)))
return heron(num, avg_guess, tolerance)
print "Given your tolerance, this is Heron's best guess:", guess
else:
print guess, "is correct!"
Uncomment the print cmd if you want to see the progression of guesses.
I was dealing with the same problem and not many tools to solve it since my knowledge in Python is very limited.
I came up with this solution that is not very elegant nor advanced, but it solves the problem using Heron's algorithm. Just want it to share it here:
print("Please enter a positive integer 'x' to find its square root.")
x = int(input("x ="))
g = int(input("What's your best guess: "))
results = [g]
if g * g == x:
print("Good guess! The square root of", x, "is", g)
else:
g = (g + (x / g)) / 2
results.append(g)
while results[-1] != results[-2]:
g = (g + (x / g)) / 2
results.append(g)
else:
print(results)
print("Not quite. The square root of", x, "is", results[-1])

Resources