Random number that is divisible by N [duplicate] - python

This question already has answers here:
Python: Generate random number between x and y which is a multiple of 5 [duplicate]
(4 answers)
Closed 3 years ago.
I want to generate a random number from range [a,b] that is dividsible by N (4 in my case).
I have the solution, but is there a better (more elegant) way to do it?
result = random.randint(a, b)
result = math.ceil(result / 4) * 4
Solutions from here:
Python: Generate random number between x and y which is a multiple of 5
doesn't answer my question since I'll have to implement something like:
random.randint(a, b) * 4;
I'll have to divide original range by 4 and it's less readable then my original solution

A generic solution and an example
import random
def divisible_random(a,b,n):
if b-a < n:
raise Exception('{} is too big'.format(n))
result = random.randint(a, b)
while result % n != 0:
result = random.randint(a, b)
return result
# get a random int in the range 2 - 12, the number is divisible by 3
print(divisible_random(2,12,3))

The first thing coming to my mind is creating a list of all the possible choices using range in the given interval, followed by randomly choosing one value using choice.
So, in this case, for a given a and b,
random.choice(range(a + 4 - (a%4), b, 4))
If a is a perfect multiple of 4, then
random.choice(range(a, b, 4))
Would give you the required random number.
So, in a single generic function, (as suggested in comments)
def get_num(a, b, x):
if not a % x:
return random.choice(range(a, b, x))
else:
return random.choice(range(a + x - (a%x), b, x))
where x is the number whose multiples are required.

As the others have pointed out, your solution might produce out of range results, e.g. math.ceil(15 / 4) * 4 == 16. Also, be aware that the produced distribution might be very far from uniform. For example, if a == 0 and b == 4, the generated number will be 4 in 80% of the cases.
Aside from that, it seems good to me, but in Python, you can also just use the integer division operator (actually floor division, so it's not equivalent to your examlpe):
result = random.randint(a, b)
result = result // 4 * 4
But a more general albeit less efficient method of generating uniform random numbers with specific constraints (while also keeping the uniform distribution) is generating them in a loop until you find a good one:
result = 1
while result % 4 != 0:
result = random.randint(a, b)

Use random.randrange with a step size of n, using a+n-(a%n) as start if a is non-divisible by n, else use a as start
import random
def rand_n(a, b,n):
#If n is bigger than range, return -1
if n > b-a:
return -1
#If a is divisible by n, use a as a start, using n as step size
if a%n == 0:
return random.randrange(a,b,n)
# If a is not divisible by n, use a+n-(a%n) as a start, using n as step size
else:
return random.randrange(a+n-(a%n),b, n)

Related

Sum of two squares in Python

I have written a code based on the two pointer algorithm to find the sum of two squares. My problem is that I run into a memory error when running this code for an input n=55555**2 + 66666**2. I am wondering how to correct this memory error.
def sum_of_two_squares(n):
look=tuple(range(n))
i=0
j = len(look)-1
while i < j:
x = (look[i])**2 + (look[j])**2
if x == n:
return (j,i)
elif x < n:
i += 1
else:
j -= 1
return None
n=55555**2 + 66666**2
print(sum_of_two_squares(n))
The problem Im trying to solve using two pointer algorithm is:
return a tuple of two positive integers whose squares add up to n, or return None if the integer n cannot be so expressed as a sum of two squares. The returned tuple must present the larger of its two numbers first. Furthermore, if some integer can be expressed as a sum of two squares in several ways, return the breakdown that maximizes the larger number. For example, the integer 85 allows two such representations 7*7 + 6*6 and 9*9 + 2*2, of which this function must therefore return (9, 2).
You're creating a tuple of size 55555^2 + 66666^2 = 7530713581
So if each element of the tuple takes one byte, the tuple will take up 7.01 GiB.
You'll need to either reduce the size of the tuple, or possibly make each element take up less space by specifying the type of each element: I would suggest looking into Numpy for the latter.
Specifically for this problem:
Why use a tuple at all?
You create the variable look which is just a list of integers:
look=tuple(range(n)) # = (0, 1, 2, ..., n-1)
Then you reference it, but never modify it. So: look[i] == i and look[j] == j.
So you're looking up numbers in a list of numbers. Why look them up? Why not just use i in place of look[i] and remove look altogether?
As others have pointed out, there's no need to use tuples at all.
One reasonably efficient way of solving this problem is to generate a series of integer square values (0, 1, 4, 9, etc...) and test whether or not subtracting these values from n leaves you with a value that is a perfect square.
You can generate a series of perfect squares efficiently by adding successive odd numbers together: 0 (+1) → 1 (+3) → 4 (+5) → 9 (etc.)
There are also various tricks you can use to test whether or not a number is a perfect square (for example, see the answers to this question), but — in Python, at least — it seems that simply testing the value of int(n**0.5) is faster than iterative methods such as a binary search.
def integer_sqrt(n):
# If n is a perfect square, return its (integer) square
# root. Otherwise return -1
r = int(n**0.5)
if r * r == n:
return r
return -1
def sum_of_two_squares(n):
# If n can be expressed as the sum of two squared integers,
# return these integers as a tuple. Otherwise return <None>
# i: iterator variable
# x: value of i**2
# y: value we need to add to x to obtain (i+1)**2
i, x, y = 0, 0, 1
# If i**2 > n / 2, then we can stop searching
max_x = n >> 1
while x <= max_x:
r = integer_sqrt(n-x)
if r >= 0:
return (i, r)
i, x, y = i+1, x+y, y+2
return None
This returns a solution to sum_of_two_squares(55555**2 + 66666**2) in a fraction of a second.
You do not need the ranges at all, and certainly do not need to convert them into tuples. They take a ridiculous amount of space, but you only need their current elements, numbers i and j. Also, as the friendly commenter suggested, you can start with sqrt(n) to improve the performance further.
def sum_of_two_squares(n):
i = 1
j = int(n ** (1/2))
while i < j:
x = i * i + j * j
if x == n:
return j, i
if x < n:
i += 1
else:
j -= 1
Bear in mind that the problem takes a very long time to be solved. Be patient. And no, NumPy won't help. There is nothing here to vectorize.

How to determine the existence of a d-redigit multiple of N? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have the following problem:
I am given 2 natural positive numbers: d and N.
I need to find the length of the minimum d-redigit that is a multiple of N.
A natural number x is a d-redigit if x is a sequence of d's.
Example: 111111 is a 1-redigit.
There may be no d-redigit multiple of N.
I know how to solve the problem when I know that a d-redigit that is multiple of N exists. However, my question is: How can I determine if this d-redigit, multiple of N, exists?
Note: The programming language for this implementation doesn't really matter, it can be pseudo code, GCL preferably.
I have tried the following implementation in Python:
def proyect_a(n:int, d:int):
if n == 0 or d == 0:
return ''
i = 1
red = d
while i < 11 and red%n != 0:
red = 10*red + d
i+=1
if i < 11:
return len(str(red))
else:
return '*'
The previous algorithm is a brute-force partial solution, since it can't really tell the length of the minimum d-redigit for all cases. As you can see, the cycle repeats 10 times max, given that I really don't know how to check if a d-redigit multiple of N exists.
First of all, since you're only concerned about divisibility by n, there's no need to use huge integers. Just compute the value of repdigit modulo n at each step. For any value of repdigit, there are only n possible values of repdigit % n, so if you don't find a multiple of n after n iterations, you can be sure that no solution exists.
But you can do a lot better by looking for repeating cycles in the calculated values. The simplest approach would be to store each successive value of repdigit. If a value occurs twice, then that means you've entered a repeating cycle and there is no solution. But there's no need to store every value of repdigit. Each iteration of the loop is equivalent to calculating the next output of a linear congruential generator with a=10, c=d, and m=n. If you start with an initial value of zero, the output sequence will settle into a repeating cycle after at most 3 iterations.
With a bit of mathematical reasoning, you could speed up the calculations even more. What you're essentially calculating is the number of iterations that it takes for an LCG seeded with a value of zero to output zero a second time (using parameters a,c,m = 10,d,n).
For example, this LCG will produce a maximal length sequence when n and d are coprime and n is a power of 3, in which case min_repdigit_multiple(n,d) will be equal to n. There are probably other short cuts you could take.
def min_repdigit_multiple(n:int, d:int):
#
# Returns the length of the smallest repdigit number divisible by n
# i.e. the smallest value of x such that ((10**x-1)*d//9) % n == 0
# If no solution exists, returns -1 instead
#
assert 0 < d <= 9, "d must be a single non-zero digit"
#
# Check for a maximal length LCG sequence
from math import gcd
if gcd(n,d) == 1:
n0 = n
while n0 % 3 == 0:
n0 //= 3
if n0 == 1:
return n
#
i = 1
repdigit = 0
seen = set()
while i <= n:
repdigit = (10 * repdigit + d) % n
if repdigit in seen:
# We've been here before, so there is no solution
return -1
if repdigit == 0:
# Success: repdigit is divisible by n
return i
# There's no point in storing more
# than the first few values of repdigit
if i < 4:
seen.add(repdigit)
i += 1
return -1 # Searched all possible values without finding a solution

Get a number of possible combinations Python [duplicate]

This question already has answers here:
counting combinations and permutations efficiently
(13 answers)
Closed 7 years ago.
How do I get a number of the possible combinations knowing the number of characters used in generating the combinations and a range of lengths.
To get all permutations i would use:
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
minLen = 1
maxLen = 3
total = 0
for i in range(minLen,maxLen+1):
total += len(chars)**i
How would I do this for combinations? When repetition is not allowed.
I'm sure there's a mathematical formula to do this but I couldn't find it anywhere.
Thanks!
EDIT:
I realised that code might not be readable so here's an explenation:
It's pretty obvious what the variables are: minimum combination length, maximum, used characters...
The for loop goes from 1 to 3 and each time it adds this to the total: length of characters (len(chars)) to the power of i (the current iteration's length).
This is a basic way of calculating permutations.
So, you actually need a way to count the Binomial coefficient, right?
import math
def binomial_cooefficient(n: int, k: int) -> int:
n_fac = math.factorial(n)
k_fac = math.factorial(k)
n_minus_k_fac = math.factorial(n - k)
return n_fac/(k_fac*n_minus_k_fac)
This might not be the most optimal implementation, but it works :)
I believe that you are looking for scipy.misc.comb (which gives you the number of unique combinations of a binomial (of the form of from N take X):
>>> from scipy.misc import comb
>>> comb(10, 1) # Num of unique combinations of *from 10 take 1*
10.0
>>> comb(10, 2) # Num of unique combinations of *from 10 take 2*
45.0
And so on.. You can then get a nice reduce:
>>> total_len = 10
>>> min_size = 1
>>> max_size = 2
>>> reduce(lambda acc, x: acc + comb(total_len, x), range(min_size, max_size+1), 0)
55.0
The above reduce is the 1-liner functional equivalent of your for:
>>> total = 0
for x in range(min_size, max_size+1):
total += comb(total_len, x)
As a side note, if you use comb(total_len, x, exact=True) you will get the result as an integer rather than a float.

Dynamic programming - save calculating times

I had an overflow error with this program here!, I realized the mistake of that program. I cannot use range or xrange when it came to really long integers. I tried running the program in Python 3 and it works. My code works but then responds after several times. Hence in order to optimize my code, I started thinking of strategies for the optimizing the code.
My problem statement is A number is called lucky if the sum of its digits, as well as the sum of the squares of its digits is a prime number. How many numbers between A and B are lucky?.
I started with this:
squarelist=[0,1,4,9,16,25,36,49,64,81]
def isEven(self, n):
return
def isPrime(n):
return
def main():
t=long(raw_input().rstrip())
count = []
for i in xrange(t):
counts = 0
a,b = raw_input().rstrip().split()
if a=='1':
a='2'
tempa, tempb= map(int, a), map(int,b)
for i in range(len(b),a,-1):
tempsum[i]+=squarelist[tempb[i]]
What I am trying to achieve is since I know the series is ordered, only the last number changes. I can save the sum of squares of the earlier numbers in the list and just keep changing the last number. This does not calculate the sum everytime and check if the sum of squares is prime. I am unable to fix the sum to some value and then keep changing the last number.How to go forward from here?
My sample inputs are provided below.
87517 52088
72232 13553
19219 17901
39863 30628
94978 75750
79208 13282
77561 61794
I didn't get what you want to achieve with your code at all. This is my solution to the question as I understand it: For all natural numbers n in a range X so that a < X < b for some natural numbers a, b with a < b, how many numbers n have the property that the sum of its digits and the sum of the square of its digits in decimal writing are both prime?
def sum_digits(n):
s = 0
while n:
s += n % 10
n /= 10
return s
def sum_digits_squared(n):
s = 0
while n:
s += (n % 10) ** 2
n /= 10
return s
def is_prime(n):
return all(n % i for i in xrange(2, n))
def is_lucky(n):
return is_prime(sum_digits(n)) and is_prime(sum_digits_squared(n))
def all_lucky_numbers(a, b):
return [n for n in xrange(a, b) if is_lucky(n)]
if __name__ == "__main__":
sample_inputs = ((87517, 52088),
(72232, 13553),
(19219, 17901),
(39863, 30628),
(94978, 75750),
(79208, 13282),
(77561, 61794))
for b, a in sample_inputs:
lucky_number_count = len(all_lucky_numbers(a, b))
print("There are {} lucky numbers between {} and {}").format(lucky_number_count, a, b)
A few notes:
The is_prime is the most naive implementation possible. It's still totally fast enough for the sample input. There are many better implementations possible (and just one google away). The most obvious improvement would be skipping every even number except for 2. That alone would cut calculation time in half.
In Python 3 (and I really recommend using it), remember to use //= to force the result of the division to be an integer, and use range instead of xrange. Also, an easy way to speed up is_prime is Python 3's #functools.lru_cache.
If you want to save some lines, calculate the sum of digits by casting them to str and back to int like that:
def sum_digits(n):
return sum(int(d) for d in str(a))
It's not as mathy, though.

List of numbers whose squares are the sum of two squares

I've just started learning Python and have started doing some problems just to help buid my skills however I am pretty stuck on this question.
Make a list containing all positive integers up to 1000 whose squares can be expressed as a sum of two squares, (i,e., integers p for which p^2=m^2+n^2, where m and n are integers greater than 0.)
Hints: There are several approaches. You might find it helpful to have a list of all the square numbers. The in operator might be useful.
Here's the code that I've come up with so far:
numbers=xrange(1001)
numbers_squared=[x**2 for x in numbers]
a=[]
for x in numbers_squared:
for b in numbers_squared:
if (x+b)**.5 <= 1001:
a.append(x+b)
print a
The problem I get with this is that Python takes years to do these calculations (I've waited about ten minutes and it's still printing numbers). Any hints on how to solve this would be very appreciated.
p.s. The main point is to use lists. Also hints would be more appreciated than the solution itself.
Thank You!
First of all, you aren't solving the problem. You need to do a check to make sure (x+b)**.5 is actually an integer.
Secondly, if you are printing numbers, you have already calculated out all the numbers. Doing the above will decrease the time required for this step.
how about a list comprehension?
calculate for c in range(1,1011)
for b in range (1, c)
for a in range (1, b)
as follows:
x = [(a,b,c) for c in range(1,1001) for b in range(1, c) for a in range(1,b) if a**2+b**2==c**2]
print x
I have timed this and it takes 46 seconds to complete on my computer
This might work:
def isSumOfSquares(n):
"""return True if n can be expressed as the sum of two squares; False otherwise"""
for a in xrange(1,n):
b = n-(a**2)
if b<=0:
return False
elif not math.sqrt(b)%1:
return True
return False
answer = [i for i in xrange(1,1001) if isSumOfSquares(i**2)]
Let me know if this works for you
I just answered this elsewhere!
import math
def is_triple(hypotenuse):
"""return (a, b, c) if Pythagrean Triple, else None"""
if hypotenuse < 4:
return None
c = hypotenuse ** 2
for a in xrange(3, hypotenuse):
b = math.sqrt(c - (a ** 2))
if b == int(b):
return a, int(b), hypotenuse
return None
>>> results = [x for x in range(1001) if is_triple(x)]
>>> len(results)
567
Runs almost instantly.

Categories