Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding numbers from a to b not divisible by x to y

This is a problem I've been pondering for quite some time.

What is the fastest way to find all numbers from a to b that are not divisible by any number from x to y?

Consider this:

I want to find all the numbers from 1 to 10 that are not divisible by 2 to 5. This process will become extremely slow if I where to use a linear approach; Like this:

result = []
a = 1
b = 10
x = 2
y = 5
for i in range(a,b):
    t = False
    for j in range(x,y):
        if i%j==0:
            t = True
            break
    if t is False:
        result.append(i)
return result

Does anybody know of any other methods of doing this with less computation time than a linear solution?

If not, can anyone see how this might be done faster, as I am blank at this point...

Sincerely, John

[EDIT]

The range of the number are 0 to >1,e+100

This is true for a, b, x and y

like image 763
JohnWO Avatar asked Apr 12 '13 05:04

JohnWO


People also ask

How do you know if a number is not divisible?

A number is divisible by another number if it can be divided equally by that number; that is, if it yields a whole number when divided by that number.

What is not divisible numbers?

Odd numbers are those numbers which are not divisible by 2. They have 1, 3, 5, 7, 9 at their unit place. Odd numbers leave 1 as a remainder when divided by 2.

Can you give an example of a number which is divisible by 6 but not divisible by 2 and 3 Why?

Answer: No there is not any number which is divisible by 6 but not 2 and 3.


1 Answers

You only need to check prime values in the range of the possible divisors - for example, if a value is not divisible by 2, it won't be divisible by any multiple of 2 either; likewise for every other prime and prime multiple. Thus in your example you can check 2, 3, 5 - you don't need to check 4, because anything divisible by 4 must be divisible by 2. Hence, a faster approach would be to compute primes in whatever range you are interested in, and then simply calculate which values they divide.

Another speedup is to add each value in the range you are interested in to a set: when you find that it is divisible by a number in your range, remove it from the set. You then should only be testing numbers that remain in the set - this will stop you testing numbers multiple times.

If we combine these two approaches, we see that we can create a set of all values (so in the example, a set with all values 1 to 10), and simply remove the multiples of each prime in your second range from that set.

Edit: As Patashu pointed out, this won't quite work if the prime that divides a given value is not in the set. To fix this, we can apply a similar algorithm to the above: create a set with values [a, b], for each value in the set, remove all of its multiples. So for the example given below in the comments (with [3, 6]) we'd start with 3 and remove it's multiples in the set - so 6. Hence the remaining values we need to test would be [3, 4, 5] which is what we want in this case.

Edit2: Here's a really hacked up, crappy implementation that hasn't been optimized and has horrible variable names:

def find_non_factors():
    a = 1
    b = 1000000
    x = 200
    y = 1000

    z = [True for p in range(x, y+1)]
    for k, i in enumerate(z):
        if i:
            k += x
            n = 2
            while n * k < y + 1:
                z[(n*k) - x] = False
                n += 1

    k = {p for p in range(a, b+1)}

    for p, v in enumerate(z):
        if v:
            t = p + x
            n = 1
            while n * t < (b + 1):
                if (n * t) in k:
                    k.remove(n * t)
                n += 1

    return k

Try your original implementation with those numbers. It takes > 1 minute on my computer. This implementation takes under 2 seconds.

like image 152
Yuushi Avatar answered Sep 24 '22 22:09

Yuushi