My professor gave us our first assignment (Cs315), which involves dealing with some huge (odd) integers and determining if they are prime. I started to do this in c++ until I realized that even long long ints could not hold the numbers needed, so I was left with the choices of making a class of vectors in c++, or learning python in a few days. This simple piece of Python code is supposed to spit out an odd 256 bit random number. It spits out random numbers, both even and odd, and I don't know why, but my guess is a that it is a simple syntactical error that I am not seeing.
import random
x = random.getrandbits(256)
if x % 2 == 0:
x + 1
print x
You need to assign x + 1 back to x. You can either do this like this: x = x+1 or like this: x += 1
Related
My homework is simple, declare a function named printPrimeNumbersTo with a single argument named to
I created the skeleton of the code itself, however, I needed some help from the net.
GeeksforGeeks was the site where I "borrowed" a line of code, which I don't completely understand. (Site: https://www.geeksforgeeks.org/python-program-to-print-all-prime-numbers-in-an-interval/)
My code looks like this (I have comments on nearly every line, describing what I think that the line of code does):
def printPrimeNumbersTo(to):
x = 0
prime_list = [] # This was a string, however, I changed it to a list so I won't have to convert the numbers to a string every time I wanted to append it to the list
for i in range(x, to + 1): # Create a for loop, using the function range an starting the loop at number 0. Add 1 to 'to', because range excludes the end integer
if i == 0 or i == 1:
continue
else:
for j in range(2, i // 2 + 1): # <--
if i % j == 0: # If 'j' is divided by any number in the list and remainder is 0, then the number is not a prime number, which means I can break the loop
break
else:
prime_list.append(i) # Append the prime number to the list
return str(prime_list)[1:-1] # Returns '[2,3,5,7..]', I use the square brackets the get rid of the brackets themselves
print(printPrimeNumbersTo(7)) # >>> 2, 3, 5, 7
The one line I don't understand is marked with an arrow, it's the 8th line of the code.
Why am I dividing the number by 2? And then making it an integer? When I do the calculations, it works, but... where is the logic? Anybody help?
The biggest number which could possibly be an even factor of a number is the half of that number. The integer division operator // produces this number as an integer.
Because of how range works, the ending index needs to be the desired number plus one.
There are two points to note:
the code needs to be indented correctly, in Python indentation matters as it forms the code blocks.
aside from this and specifically adressing the question: the range function that you refer to requires integers otherwise it would throw an typeerror like this: 'float' object cannot be interpreted as an integer .
# this will throw an error
for i in range(1, 10.5):
print(i)
# this will work
for i in range(1, 10):
print(i)
So the reason why the line of code you queried was written like that was to ensure that the upper bound of the range was an integer.
You should also note that the // has a meaning, for example try this:
x = 5//2
print(x)
y = 5/2
print(y)
x is the integer part only (x=2)
y is the full number (y=2.5)
In terms of implementaiton, there are a number of methods that would be better (suggested here):
Print series of prime numbers in python
Dividing the number by 2 is done to reduce the number of iterations. For example, the number 12 you can divide it without a remainder by 1,2,3,4,6. Notice that there is no number bigger than (6) which is 12 / 2. And this goes on with all of the numbers.
16 ---> 1,2,8 no number bigger than its half (8)
When I run my code below I get Memory Error
import math
X = 600851475143
halfX = math.trunc(int(X / 2))
countFactors = 0
for i in range(halfX):
if i >0 and X % i:
countFactors += 1
print countFactors
I understand because of math calcs here but I do not know how to correct it.
I'm going to guess you're using Python 2.7 (or 2.x, at any rate).
If that's the case, you should use xrange instead of range.
In python 3.x, range creates an iterator that only uses a few bytes of memory regardless of how large it is. In python 2.x, range always creates a list containing numbers counting up (or down) over the specified range. Calling range(some_large_number) can cause you to run out of memory in 2.x.
Therefore, Python 2.x has xrange which creates an iterator identical to range in 3.x.
Also, you can simplify your math somewhat. For example:
x = 600851475143
half_x = x // 2
count_factors = 0
for i in xrange(half_x):
if i > 0 and x % i == 0:
count_factors += 1
print count_factors
However, there are much more efficient ways to do this.
As a simple example, if the number is divisible by two, you can iterative over every other number, cutting the number of tests in half. Similarly, if it's divisible by 3, 5, etc.
I'll leave it to you to figure out the generalization. It's a fun problem :)
I've got, what I think is a valid solution to problem 2 of Project Euler (finding all even numbers in the Fibonacci sequence up to 4,000,000). This works for lower numbers, but crashes when I run it with 4,000,000. I understand that this is computationally difficult, but shouldn't it just take a long time to compute rather than crash? Or is there an issue in my code?
import functools
def fib(limit):
sequence = []
for i in range(limit):
if(i < 3):
sequence.append(i)
else:
sequence.append(sequence[i-1] + sequence[i-2])
return sequence
def add_even(x, y):
if(y % 2 == 0):
return x + y
return x + 0
print(functools.reduce(add_even,fib(4000000)))
The problem is about getting the Fibonacci numbers that are smaller than 4000000. Your code tries to find the first 4000000 Fibonacci values instead. Since Fibonacci numbers grow exponentially, this will reach numbers too large to fit in memory.
You need to change your function to stop when the last calculated value is more than 4000000.
Another possible improvement is to add the numbers as you are calculating them instead of storing them in a list, but this won't be necessary if you stop at the appropriate time.
Question: What's the best way to iterate over an integer and find other integers inside it, then throw that integer away if it contains them?
Long Version:
I have been working on my Python skills by trying to make efficient solutions to the problems at Project Euler. After going through around 20 problems, I find that while I can solve the problems my solutions are often inelegant and clunky (i.e., ugly and slow). The way the problems are structured, I think I need to learn some better solutions because more complex stuff is going to compound these inefficiencies.
Anyway, today I'm working on problem 35, which requests all circular primes below 1,000,000. I have produced a list of all primes below 1,000,000 and I built a little framework to spit out permutations of these primes below, for each of which I was planning to test for prime-ness:
def number_switcher(number):
number = [num for num in str(number)]
numlist = [''.join(num) for num in list(itertools.permutations(number))]
return [int(num) for num in numlist]
Running this on all the primes and then testing each possible permutation for prime-ness, as you can imagine, is no way to solve the problem.
Then it occurred to me that I could throw away all numbers that have an even number in them (assuming they're longer than one digit) or any numbers with fives in them before I even start running the permutations.
Here's where I really got lost. Even though it seems simple, I can't figure out after two days of trying, how to throw away any multi-digit number with an even number or a 5 inside of it.
Here's what I tried (assuming a list of all primes below 1,000,000 called here "primes"):
[num for num in primes if any(x for x in '024685' in str(num))] # failed: 'bool' object is not iterable
Then I experimented with the following:
for prime in primes:
if '0' in str(prime):
primes.remove(prime)
>>>>len(primes)
4264
This cut my primes list about in half. Okay, so maybe I'm on the right track and I just need an ugly "if '0' in str(prime) or if '2' in str(prime)," etc.
But here's the weird thing: when I examine my 'primes' list, it still has primes with '0's in it. Running the same thing again on the new list of primes, I get the following results:
for prime in primes:
if '0' in str(prime):
primes.remove(prime)
>>>>len(primes)
4026
...and again the result drops to:
>>>>len(primes)
3892
....
3861 # again
....
3843 #and again
Maybe I'm missing something obvious here, but it seemed like that first if-test should find any prime with '0' in it and remove all of them?
Lastly, I also tried the following, which seems terrible because it jumps pointlessly back and forth across the str-integer train tracks, but it seemed like it just had to work:
for num in primes:
for d in str(num):
if (int(d) % 2 == 0 or int(d) == 5):
primes.remove(num) # doesn't work: ValueError: list.remove(x): x not in list
else:
pass
I feel like I shouldn't be tearing my hair out over this question, but it's making me a little crazy and probably because I've gotten to a point where I'm just trying to hack out a solution, my attempts are getting less lucid.
Here's my question:
What's the best way to iterate over an integer and find other integers inside it, then throw that stupid integer away if it contains them?
Thanks for your help/reading.
Footnote:
This is the first question I have asked here but I have benefitted from this site's guidance for a few months now. Apologies if this question/solution is extant, but I looked for it and could not find a way to cobble together a solution. Most search results come up as "how to tell if an integer is even".
#root is correct that your assumption about how to optimise this is false, but I'd thought it'd be useful to point out why what you're doing isn't working on a Python level.
Your bool problem:
[num for num in primes if any(x for x in '024685' in str(num))] # failed: 'bool' object is not iterable
'024685' in str(num) is being evaluated first, so it equates to for x in True - which isn't possible. The above would be written as:
[num for num in primes if not any(ch in '024685' for ch in str(num)]
Which takes each character from str(num) and checks to see if it's one of '024685'.
Your list problem:
There's a rule of thumb here - don't modify something you're iterating over. If you were to try this with a dict you'd get an exception thrown - but for a list it's likely to get silently wrong, but occasionally will break.
When removing more than one value from a list, it's better to build a new list keeping only the required values, eg:
no_zero = [num for num in primes if '0' not in str(num)]
And if you wanted to modify the original primes:
primes[:] = no_zero
Your last example also fails because of .remove(), and putting the above together can be written as:
[num for num in primes if not any(num % i == 0 for i in (2, 5)]
Misc:
You may wish to consider storing the primes in a set - as you're not concerned about the order of the primes, and will be faster for membership testing.
Thanks, Jon Clements. I was able to solve the problem today with the following script (note that I had to make sure the '024685' stripper did not strip out '2' and '5' because those were part of the answer, which threw me off for awhile...):
import math
import itertools
def prime_test(number):
if all(number % x != 0 for x in range(2, int(math.sqrt(number)) + 1)):
return True
else:
return False
def find_primes(limit):
primes = [2]
for x in range(3, limit + 1, 2):
if prime_test(x):
primes.append(x)
else:
pass
return primes
def circulate(number):
circ_list = [number]
x = 1
while x < len(str(number)):
number = str(number)[1:] + str(number)[0]
circ_list.append(number)
x += 1
return circ_list
def main():
primes = find_primes(1000000)
no_evens = [x for x in primes if not any(ch in '024685' for ch in str(x) if len(str(x)) > 1)]
circular_primes = []
for prime in no_evens:
if all(prime_test(x) for x in circulate(prime)):
circular_primes.append(prime)
else:
pass
return circular_primes, len(circular_primes)
if __name__ == '__main__':
print(main())
Another thing I didn't realize is that I was merely supposed to rotate the number, not provide all possible permutations of it. These gotches probably throw people off when they're trying to solve the problem.
I can't wrap my head around what's causing the index error here, not exactly looking for a quick fix. Let me know however if my code repulses you/is incredibly ineffectual. The goal is to generate palindromes produced by the product of two four digit numbers.
Code:
for x in range(10000):
for y in range(10000):
product = str(x*y)
lengthprod = len(str(product))
for digit in range(lengthprod+1):
if (product[digit]==product[lengthprod-digit]):
print x,"x",y,"=",product
Traceback:
Traceback (most recent call last):
File "<pyshell#31>", line 6, in <module>
if (product[digit]==product[lengthprod-digit]):
IndexError: string index out of range
Converting a number to a string is generally a slow operation, since there are many possibilities in general (integers, floating point, scientific notation, maybe something exotic like fractions or imaginary numbers, not to mention things like handling leading zero or overwidth numbers or rounding to two decimal places). Thus, it is often a better approach for checking if a positive integer is a palindrome to reverse the digits numerically by repeatedly taking the input modulo 10 to extract the last digit, adding the digit to an accumulator that is multiplied by 10 at each step, then dividing the input number by 10 before looping. I don't speak Python, so here is my Scheme program to reverse a number:
(define (rev n)
(let loop ((n n) (r 0))
(if (zero? n) r
(loop (quotient n 10)
(+ (* r 10) (modulo n 10))))))
Then you can check if the number is a palindrome by checking if the input number equals its reversal.
Edit: Here it is in Python:
def rev(n):
r = 0
while n > 0:
r = r * 10 + n % 10
n = n // 10
return r
You iterate over values 0...lengthprod , but the legal subscripts for product are 0...lengthprod-1.
The last index is out of bounds. It references an element that is one byte beyond the end of the string.
Two changes:
1: range(0, lengthprod+1) should be range(0, lengthprod)
See documentation on range()
2: product[lengthprod-digit] should be product[lengthprod-digit-1]
Off by one error since lengthprod is a length (1 based) and digit is an index (0 based).
Note, this will only give you valid "single digit" palindromes, but gets you past the index out of range error.
Your code repulses me!
(Sorry, I wouldn't normally be so rude, but since you asked for it... ;)
Use xrange rather than range for long loops like this.
Start the range from 1 rather than 0 unless you don't mind all the duplicated trivial results.
Since multiplication commutes, you might want to loop over a "triangle" rather than a "square" to avoid duplicates.
Your variable name product shadows a function from numeric core.
The question says you're interested in the "product of two four digit numbers", but your code has no such restrictions on the number of digits in the numbers. If you want the four digit numbers as input, just start your xrange(start, stop) from 1000.
Since your stated "goal is to generate palindromes", how about to try it with the correct tool for the job: generators!
def pairs(n):
for x in xrange(n):
for y in xrange(n):
yield (x,y)
pairs_generator = pairs(100)
filter(None, ['{x}*{y}={xy}'.format(x=x,y=y,xy=x*y) if str(x*y) == str(x*y)[::-1] else None for x,y in pairs_generator])
I kept my generator simple for clarity's purpose. I will leave it as an exercise for you to simply make a generator to spit out the palindromes. This will involve moving the logic which I have put in my list comprehension into the generator (or you could make a new palindrome_generator which uses a pairs_generator).
Have fun!