Το επόμενο πρόγραμμα το είχαμε δει την προηγούμενη φορά και βρίσκει αν ο ακέραιος που δίνει ο χρήστης είναι ή όχι πρώτος. Αν δεν είναι πρώτος μας βρίσκει και όλους τους γνήσιους διαιρέτες του.
n = int(raw_input("Give me a positive integer > 1: "))
isprime = True
divisors = []
for k in range(2, n):
if n % k == 0:
isprime = False
divisors.append(k)
if isprime:
print "The number %d is a prime." % (n)
else:
print "The number %d is not a prime." % (n)
print "The list of divisors is: ",
for x in divisors:
print x,
Βλέπουμε στο επόμενο πρόγραμμα πώς χρησιμοποιείται η εντολή break
. Όταν η εντολή break
εκτελεστεί μέσα σε μια ανακύκλωση (όχι μόνο στην ανακύκλωση for
) τότε σταματάει αμέσως να εκτελείται η ανακύκλωση αυτή (ούτε οι εντολές που έπονται της break
μέσα στην ίδια εκτέλεση της ανακύκλωσης εκτελούνται) και ο έλεγχος του προγράμματος μεταβιβάζεται στην πρώτη εντολή αμέσως μετά το for
(την print "END"
στο παράδειγμα αυτό).
for i in range(100):
print i,
if i>10:
break
print "END"
Το επόμενο είναι ξανά το πρόγραμμα που αποφασίζει αν ένας ακέραιος είναι πρώτος με τη διαφορά ότι δεν κρατάμε τους διαιρέτες σε λίστα ή αλλού. Το τρέχουμε εδώ για ένα αρκετά μεγάλο ακέραιο και παρατηρούμε πόση ώρα κάνει να τρέξει (θα μπορούσαμε και να είχαμε εισαγάγει κάποιες επιπλέον εντολές python που να μετράγανε το χρόνο ακριβώς αλλά δεν το κάνουμε σε αυτή τη φάση).
Αυτό το κάνουμε για να συγκρίνουμε την ταχύτητα αυτού του προγράμματος με το μεθεπόμενο πρόγραμμα που κάνει την ίδια δουλειά αλλά πολύ πιο έξυπνα και γρήγορα.
n = int(raw_input("Give me a positive integer > 1: "))
isprime = True
for k in range(2, n):
if n % k == 0:
isprime = False
if isprime:
print "The number %d is a prime." % (n)
else:
print "The number %d is not a prime." % (n)
Η παρατήρηση που χρησιμοποιούμε στο επόμενο για να επιταχύνουμε τον έλεγχο του αν ένας ακέραιος είναι πρώτος είναι η παρακάτω πρόταση.
Πρόταση Αν \(n > 1\) είναι ακέραιος τότε ο \(n\) είναι πρώτος αν και μόνο αν δεν έχει διαιρέτες >1 και \(\le \sqrt{n}\).
Απόδειξη Αν ο \(n\) είναι πρώτος τότε δεν έχει καθόλου γνήσιους διαιρέτες, \(\le \sqrt{n}\) είτε \(> \sqrt{n}\) οπότε η μία κατεύθυνση της ισοδυναμίας είναι φανερή. Για την άλλη κατεύθυνση, ας υποθέσουμε ότι ο \(n\) δεν έχει γνήσιους διαιρέτες \(\le\sqrt{n}\). Αν \(k>\sqrt{n}\) είναι κάποιος γνήσιος διαιρέτης του \(n\) τότε ο αριθμός \(d = n/k\) είναι ακέραιος και, αφού \(k>\sqrt{n}\), έχουμε \(d<\sqrt{n}\). Αλλά και ο \(d\) (που δεν είναι ίσος με 1 γιατί \(k \neq n\)) είναι διαιρέτης του \(n\), που αντιφάσκει με την υπόθεσή μας ότι ο \(n\) δεν έχει γνήσιους διαιρέτες \(\le\sqrt{n}\). Άρα δεν υπάρχει τέτοιος διαιρέτης \(k\) και ο \(n\) είναι πρώτος.
Αρκεί λοιπόν, για να είμαστε σίγουροι ότι ο \(n\) είναι πρώτος, να ελέγξουμε ότι δεν έχει διαιρέτες \(\ge 1\) και \(\le \sqrt{n}\). Στην ανακύκλωση for
λοιπόν όπου ελέγχουμε όλα τα δυνατά \(k\) για το αν διαιρούν το \(n\) μπορούμε να "σπάσουμε" την ανακύκλωση (με την εντολή break
) μόλις το k
ξεπεράσει το \(\sqrt{n}\), πράγμα που ελέγχουμε με τη συνθήκη k*k>n
.
Με αυτό τον τρόπο ο έλεγχος για το αν ο \(n\) είναι πρώτος παίρνει περίπου \(\sqrt{n}\) ελέγχους ενώ με τον προηγούμενο τρόπο παίρνει περίπου \(n\) ελέγχους. Αυτή η διαφορά είναι τεράστια όταν το \(n\) είναι μεγάλο. Στο παράδειγμα που έχουμε εδώ \(n=10^8\) και αυτό λοιπόν συγκρίνεται με το \(n=10^4\). Τρέχοντας και τους δύο αλγορίθμους η διαφορά στο χρόνο που παίρνουν να τρέξουν είναι οφθαλμοφανής (κάντε το στον υπολογιστή σας).
n = int(raw_input("Give me a positive integer > 1: "))
isprime = True
for k in range(2, n):
if k*k>n:
break
if n % k == 0:
isprime = False
if isprime:
print "The number %d is a prime." % (n)
else:
print "The number %d is not a prime." % (n)
Στο επόμενο τροποποιούμε τη γρηγορότερη μέθοδο απόφασης του αν κάποιος ακέραιος είναι πρώτος ώστε να υπολογίζει και πάλι τη λίστα των γνήσιων διαιρετών όταν ο αριθμός είναι σύνθετος. Ο τρόπος που το κάνουμε είναι να παρατηρήσουμε ότι αν ξέρουμε όλους τους διαιρέτες \(k \le \sqrt{n}\) τότε οι μόνοι διαιρέτες που υπάρχουν πέρα από το \(\sqrt{n}\) είναι οι αριθμοί \(n/k\).
Για κάθε λοιπόν ακέραιο \(k \le \sqrt{n}\) που προσθέτουμε στη λίστα διαιρετών divisors
προσθέτουμε και τον ακέραιο \(d = n/k\), αλλά μόνο στην περίπτωση που \(d>k\), ώστε να μη προσθέσουμε δύο φορές τον ίδιο τον \(\sqrt{n}\) αν αυτός τύχει να είναι ακέραιος.
n = int(raw_input("Give me a positive integer > 1: "))
isprime = True
divisors = []
for k in range(2, n):
if k*k>n:
break
if n % k == 0:
isprime = False
divisors.append(k)
d = n/k
if d > k:
divisors.append(d)
if isprime:
print "The number %d is a prime." % (n)
else:
print "The number %d is not a prime." % (n)
print "The list of divisors is: ",
for x in divisors:
print x,
Όμως με το πρόγραμμα στο προηγούμενο κελλί η λίστα διαιρετών δεν βγαίνει ταξινομημένη. Αυτό διορθώνουμε εδώ ώστε η λίστα διαιρετών που υπολογίζουμε να είναι πάντα σε άυξουσα σειρά.
Υπάρχουν πολλοί τρόποι για να γίνει αυτό. Εδώ κρατάμε δύο λίστες διαιρετών, την divisorsS
(οι μικροί διαιρέτες, αυτοί που είναι \(\le\sqrt{n}\)) και την divisorsL
(οι μεγάλοι διαιρέτες, αυτοί που είναι \(>\sqrt{n}\)). Και τις δύο φροντίζουμε να τις κρατάμε σε αύξουσα σειρά. Για τη λίστα divisorsL
, που γεμίζει από το τέλος προς την αρχή, αυτό σημαίνει οτι θα πρέπει τα στοιχεία που προσθέτουμε σε αυτή να τα προσθέτουμε από μπροστά και όχι από πίσω με τη μέθοδο append
όπως κάνουμε με τη λίστα divisorsS
. Για να προσθέσουμε δηλ. τον ακέραιο d
στη λίστα divisorsL
δίνουμε την εντολή
divisorsL = [d] + divisorsL
Στο τέλος του προγράμματος απλά τυπώνουμε τα περιεχόμενα της λίστας divisorsS+divisorsL
.
n = int(raw_input("Give me a positive integer > 1: "))
isprime = True
divisorsS = []
divisorsL = []
for k in range(2, n):
if k*k>n:
break
if n % k == 0:
isprime = False
divisorsS.append(k)
d = n/k
if d > k:
divisorsL = [d] + divisorsL
if isprime:
print "The number %d is a prime." % (n)
else:
print "The number %d is not a prime." % (n)
print "The list of divisors is: ",
for x in divisorsS+divisorsL:
print x,
Στο επόμενο κελλί βλέπουμε πώς μπορούμε από μια λίστα αριθμών L
να εξάγουμε τους αριθμούς εκείνους της L
που είναι \(\ge 0\) και να τους βάλουμε στη λίστα P
και τους αριθμούς που είναι \(< 0\) και να τους βάλουμε στη λίστα N
.
L = input("Please give a list of numbers: ")
P = []
N = []
for x in L:
if x>=0:
P.append(x)
else:
N.append(x)
print "The list of nonnegative elements is:", P
print "The list of negative elements is:",N
Ως προετοιμασία για ζωγράφισμα σχήματος με αστεράκια στην οθόνη βλέπουμε εδώ πώς μπορούμε να τυπώσουμε ένα \(10\times 10\) τετράγωνο από αστεράκια στην οθόνη.
for x in range(10):
for k in range(10):
print '*',
print
Κι εδώ πετυχαίνουμε το ίδιο αλλά μόνο με ένα απλό loop, όχι με διπλό loop όπως στο προηγούμενο παράδειγμα. Απλά κάθε 10 αστεράκια που τυπώνουμε αλλάζουμε γραμμή.
for x in range(100):
print '*',
if x%10==9:
print
Στο παρακάτω πρόγραμμα τυπώνουμε αυτό το "ανθρωπάκι" που βλέπετε ως output του προγράμματος παρακάτω. Η παράμετρος N
που προσδιορίζουμε στην αρχή είναι το μήκος των χεριών. Όλες οι άλλες διαστάσεις προσδιορίζονται από αυτόν τον αριθμό και από σταθερές που δεν τις αλλάζουμε (π.χ. το κεφάλι είναι ένα τετράγωνο \(5 \times 5\)).
Η στρατηγική εδώ είναι ότι προχωράει ο σχεδιασμός από πάνω προς τα κάτω και σε κάθε γραμμή τυπώνουμε τον κατάλληλο συνδυασμό από κενούς χαρακτήρες ' '
αστεράκια '*'
, ανάλογα με το τι θέλουμε να πετύχουμε.
Χρησιμοποιούμε επίσης πολλαπλασιασμό ενός string με αριθμό (αντί για να γράφουμε εσωτερική ανακύκλωση). Έτσι για να γράψουμε 10 αστεράκια το ένα μετά το άλλο τυπώνουμε το string '*'*10
. Ή, για να γράψουμε 5 κενούς χαρακτήρες ακολουθούμενους από 10 αστεράκια γράφουμε το string ' '*5 + '*'*10
.
N = 15 # Μήκος χεριών
# Κεφάλι
for x in range(5):
if x==1:
print ' '*(N+2)+'** * **' # Γραμμή με τα μάτια
elif x==3:
print ' '*(N+2)+'** **' # Γραμμή με το στόμα
else:
print ' '*(N+2)+'*'*7
# Λαιμός
for x in range(3):
print ' '*(N+5)+'*'
# Σώμα
for x in range(3):
print ' '*N+'*'*11
print '*'*(2*N+11) # Γραμμή με τα χέρια
for x in range(7):
print ' '*N+'*'*11
# Πόδια
for x in range(10):
print ' '*(N+3)+'*'+' '*3+'*'