Category Archives: Python

Un quiz, soluzioni con Python e Racket

bach-origTrovare quel numero che diviso per 2 ha come resto 1, diviso per 3 ha sempre resto 1, e ugualmente diviso per 4, per 5 o per 6 ha sempre resto 1, ma se viene divso per sette dà resto zero.
Federico Peiretti, Il matematico si diverte, Longanesi 2010, p.83. riferito a Claude-Gaspard Bachet.

Diophantus-cover

Claude-Gaspard Bachet è un matemeatico (e non solo) importante, che giustifica l’uso del quiz molto semplice ma devo fare pratica; e poi c’era anche il mio amico GG (prossimamente, forse…).

Ancora una cosa: l’immagine iniziale è presa da Gallica, qui.

Sono anche in regola con le condizioni d’uso. E grazie Gallica e Bibliothèque nationale de France :grin:

Ah! il problema lo trovate a p.199 del libro originale corrispondente a p.218 del PDF.

OK, siccome sono niubbo provo prima con Python.
Occorre trovare quel numero divisibile per 7 che ha modulo 1 per il minimo comune multiplo di {2, 3, 4, 5, 6}. La funzione per il calcolo del minimo comune multiplo (lcm) l’ho copiata da Rosetta Code.

Quindi ecco, Python, cgb.py:

#/usr/bin/python3

def lcm(*values):
	values = set([abs(int(v)) for v in values])
	if values and 0 not in values:
		n = n0 = max(values)
		values.remove(n)
		while any( n % m for m in values ):
			n += n0
		return n
	return 0

#main
mcm = lcm(2, 3, 4, 5, 6)
found = False
n = 0
while not found:
	n += 1
	found = ((mcm * n + 1) % 7) == 0
print(mcm * n + 1)

py

E con Racket? bèh, qui sono ancora un po’ (tanto) niubbo ma insomma…

E poi c’è la reference in locale, comodissima:

doc

Sì, bash si lamenta di Firefox ma solo per far vedere che c’è anche lui…

Ma Racket? OK, ecco cgb.rkt:

#lang racket

(define mcm (lcm 2 3 4 5 6))
(define num
  (let cgb ([n 1])
    (if (positive? (modulo (add1 (* n mcm)) 7))
      (cgb (add1 n))
      (add1 (* n mcm)))))
(print num)
(newline)   

rkt
La funzione per il calcolo del minimo comune multiplo (lcm) è predefinita :grin:
Il codice è elementare, da niubbo, costruito traducendo quello di Python. Ho usato troppe variabili; ho ripetuto un calcolo numerico una volta più del necessario. Prometto solennemente che in futuro sarò più funzionale.
Giustificazioni: 1) sono niubbo; 2) stavo propagandando Racket a una possibile vittima; con 3) paura di fare una figuraccia.
Poi a demo fatta ho dimenticato il tutto per una settimana, quasi. Ma devo fare pratica, per questo lo pubblico anche se non ottimale :mrgreen:

Nota: corretto un erroraccio, avevo scritto “divisore” al posto di “multiplo”. Grazie a Roberto Giacomelli :grin:

Più di un hacker, un virtuoso: Peter Deutsch

lwAl solito tutto parte da un tweet, da uno che seguo e mi segue :grin: Lisp World, questo.
replinvTweet eccezionale, l’immagine è fantastica, visto la bici? e il resto, certo. Però –forse– c’è un’esagerazione nel cinguettio: “Inventor of the Lisp REPL“.
Per i non lispers REPL sta per Read, Eval, Print, Loop. E la conoscono e usano in parecchi, non è necessario essere lispers. È la versione interattiva dei linguaggi, quella che trovate se scrivete python, python3, idle, sbcl --noinform, rlwrap sbcl --noinform, racket -il xrepl, gst, irb --simple-prompt, …
Non è che devo continuare vero? Perché se servisse ne avrei tanti altri. D’accordo loro non la chiamano REPL ma versione interattiva o qualcosa di simile ma è quella.

Tornando a Peter una googlata per immagini ha chiarito tutto parecchio.
Ecco: L. Peter Deutsch’s PIVOT program verification system.

OK, c’è tutto. E voi fate come volete ma Dusty Decks io lo RSSisco, anzi già fatto.

Però, ora che ci penso. Quando ero giovane anch’io facevo delle REPL, senza sapere che si chiamavano così e erano già state inventate (a me nessuno mi dice mai niente, e anche allora nessuno mi diceva mai niente e non c’era ancora il Web, anzi nemmeno i BBS). Perché fare una REPL non è difficile, la parola chiave è loop, un ciclo indefinito. Con il Fortran si faceva con un GOTO che ti rimandava all’inizio del codice. Il mio collega e amico (più amico che collega) Giorgio aveva riscritto l’editor ED del Prime in GW-Basic (mancava solo il comando gmodify ma tanto quello non lo usava nessuno).

Anzi, sapete che vi dico?
Mi viene voglia di crearne una, un abbozzo, uso Python 3.x anche se … OK, meno conosciuto di Python e io sono un evangelista di Python da sempre, ecco:

Prima versione semplicissima:

#!/usr/bin/python3

while True:
    st = input('-> ')
    print(eval(st))

r0ma …

r1

Bisogna gestire le eccezioni …

#!/usr/bin/python3

while True:
        st = input('-> ')
        try:
                print(eval(st))
        except Exception:
                pass

r2ancora …

#!/usr/bin/python3

stprec = ''
diz ={}
while True:
    st = input('-> ')
    peq = st.find('=')
    print(st, peq)
    try:
        if st == 'st':
            st = stprec
        elif peg >= 0:
            key_ = str(st[:peg].strip())
            dat_ = st[peg:].strip()
            diz[key_] = dat_
        else:
            print(eval(st))
    except Exception:
        pass
    stprec = st

r3e poi

#!/usr/bin/python3

stprec = ''
peg = -1
diz = dict()
while True:
    st = input('-> ')
    if st == 'quit' : quit()
    peg = st.find('=')
    if st == 'st':
        st = stprec
    elif peg >= 0:
        key_ = st[:peg].strip()
        dat_ = st[peg + 1:].strip()
        diz[key_] =dat_
    else:
        try:
            if st in diz:
                st = diz[st]
            print(eval(st))
        except:
            pass
    stprec = st

r4
E si potrebbe continuare, volendo, questo…

:mrgreen:

Functional Programming in Python di David Mertz

1500C’è chi dice che venerdì 17, la versione nazionale del più qualificato e universale venerdì 13 porti spheega. Ma forse no, se non ci credi.

Prendi per esempio l’ultimo, quello di luglio dove è saltato fuori un tweet on writing shorter & less bug-prone Python code, questo.

David è un cubano di San Francisco (quella della Bay Area, certo, in cima a Silicon Valley) che si autodefinisce an ideational bricoleur.  Su Twitter non è che è molto attivo, ma se continua e s’impegna lo followerò, promesso.

Per intanto il malloppo (no, dai sintetico 49 pagine in tutto comprese copertine, legalesismi e simili) moolto accattivante. Roba che mi viene voglia di farne un riassunto, chissà che non riesca a invogliarvi al linguaggio e al modo di codificare funzionalmente.

Parte subito con la definizione di programmazione funzionale (FP) in modo sensato, io non avrei saputo far meglio :lol:

Personally, I would roughly characterize functional programming as
having at least several of the following characteristics. Languages
that get called functional make these things easy, and make other
things either hard or impossible:

  • Functions are first class (objects). That is, everything you can do with “data” can be done with functions themselves (such as passing a function to another function).
  • Recursion is used as a primary control structure. In some languages, no other “loop” construct exists.
  • There is a focus on list processing (for example, it is the source of the name Lisp). Lists are often used with recursion on sublists as a substitute for loops.
    “Pure” functional languages eschew side effects. This excludes the almost ubiquitous pattern in imperative languages of assigning first one, then another value to the same variable to track the program state.
  • Functional programming either discourages or outright disallows statements, and instead works with the evaluation of expressions (in other words, functions plus arguments). In the pure case, one program is one expression (plus supporting definitions).
  • Functional programming worries about what is to be computed rather than how it is to be computed.
  • Much functional programming utilizes “higher order” functions (in other words, functions that operate on functions that operate on functions).

Naturalmente il grado di FP varia, i puristi forse esagerano e comunque Python is most definitely not a “pure functional programming language”; side effects are widespread in most Python programs. That
is, variables are frequently rebound, mutable data collections often
change contents, and I/O is freely interleaved with computation. It is
also not even a “functional programming language” more generally.
However, Python is a multiparadigm language that makes functional
programming easy to do when desired, and easy to mix with other
programming styles.

Ma per chi non è un purista estremista (dai io vengo (nel senso che ho cominciato) dal Fortran per dire!) e allora … :grin:

David ci introduce a Multiple Dispatch di Matthew Rocklin, credo di averla già indicata, se no lo faccio adesso, come the best current implementation of the concept it implements.

Adesso andate a leggere di là ma prima vorrei farvi notare che certe licenze ortografiche che uso non sono mie, p.es. pyrsisten, toolz et al.

Poi una ciliegia tira l’altra e in men che non si dica ci troviamo in Charming Python (no, non metto il link, è di là).

Tutto questo nella prefazione, in attesa del primo capitolo con un titolo non meno astoundingcente: (Avoiding) Flow Control. Forse sapete già da come ho cominciato, e qui vi confesso che sono contento che ero seduto quando l’ho visto :wink:

Qui si illustrano i costrutti tipici di FP, con esempi, quali l’encapsulation, la comprehension, la ricorsione, come eliminare i cicli (loops) con la funzione map().
Anche la ricorsione si può a volte fare senza ricorsione, p.es. con reduce().

Il capitolo 2, Callables passa in rassegna i diversi modi di chiamata di funzione (con Python), ci sono le lambda, i @decoratori, le closures e altre bestie che voi imperativi… Ma che diventano presto cose sensate e indispensabili.

Siamo così pronti alla Lazy Evaluation, fare solo quando serve, proprio come Haskell (e me).

Qui per non non haskellisti c’è da masterizzare un po’ di cose nuove, here is a quick example of combining a few things. Rather than the stateful Fibonacci class to let us keep a running sum, we might simply create a single lazy iterator to generate both the current number and this sum:

def fibonacci():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b

from itertools import tee, accumulate
s, t = tee(fibonacci())
pairs = zip(t, accumulate(s))
for _, (fib, total) in zip(range(7), pairs):
    print(fib, total)

fp-fib

Figuring out exactly how to use functions in itertools correctly and optimally often requires careful thought, but once combined, remarkable power is obtained for dealing with large, or even infinite, iterators that could not be done with concrete collections.

The documentation for the itertools module contain details on its combinatorial functions as well as a number of short recipes for combining them.

Tutto da assimilare, diverse funzioni che devono diventare abituali :grin.

E adesso siamo pronti per le Higher-Order Functions (HOFs). In general, a higher-order function is simply a function that takes one or more functions as arguments and/or produces a function as a result. Many interesting abstractions are available here. They allow chaining and combining higher-order functions in a manner analogous to how we can combine functions in itertools to produce new iterables.

E si finisce con i @decorators, ecco questi per me sono ancora un po’ nuovi; ma ci sto lavorando, nèh!

Intanto il book finisce con indicazioni più sensate su David, rockz!

:mrgreen:

Spyder, un IDE per Python

Spyder_logo

Sapete la serendipity, ricorsiva in questo caso. Recentemente un giovane volonteroso mi chiedeva quale IDE semplice usare per impratichirsi con Python. Io, dopo avergli ricordato che essedo vecchio uso un editor normale (Gedit, sì lo so che c’è di meglio) ho consigliato Geany. Che ogni tanto uso anch’io. E sì, c’è anche per Windows, cosa che in quel caso era necessaria.
Giovedì pomeriggio mi viene ripetuta la stessa richiesta. E io insisto con Geany.

E adesso chi glielo dice ai due? Sì perché ho trovato di meglio, grazie a un post che raccomanda Emacs: Emacs for Data Science.

Ma non voglio propagandare Emacs. Anche se è il migliore in assoluto, senza paragoni. Solo che per imparare a usarlo e sfruttare le sue possibilità ci vuole tempo e costanza e poi forse per le cose piccole non è necessario :roll: (Dai non infierite, a volte lo uso, per esempio con SLIME).

Spyder (formerly Pydee) is an open source cross-platform IDE for scientific programming in the Python language. Spyder integrates NumPy, SciPy, Matplotlib and IPython, as well as other open source software, dice la Wiki.

Una rapida occhiata alla pagina degli screenshots mi ha convinto a provarlo.

Per Ubuntu c’è nel Software Center, installo (per la versione 2.x ma c’è anche per la 3), 51 MB, ed ecco:

click per ingrandire

click per ingrandire

Nel terminale (ma non sono più obbligato a usarlo, cosa che genera lamentele per i windowsiani) ottengo:

con-fib

OK, l’esempio è semplicissimo, questo è il codice (fib.py):

# -*- coding: utf-8 -*-

def fibGen(n, a=0, b=1):
    print a, b,
    while n > 0:
        yield a
        a, b, n = b, a+b, n - 1
        print b,
        if (n % 5) == 0: print
#main
[i for i in fibGen(50)]

Ovviamente c’è molto di più, conviene leggere la documentazione, qui: Spyder – Documentation.
Il sito di Spyder è su GitHub.
E sì, dice come installarlo su Windows :grin:

Il problema dell’ora con Python

lazare-clocksUn post di Julien Danjou, Timezones and Python risolve forse, o forse no…
Julien la sa lunga su tante cose, guarda qui.

Recently, I’ve been fighting with the never ending issue of timezones

D’ho, me too! più volte; chissà se oggi si arriva a a qualcosa di utile?

tz0
Ecco, a cosa si riferisce? UTC o locale? Perso.
Julien riporta che Armin Ronacher dice di considerare gli oggetti datetime non specificati diversamente sempre come UTC; è la soluzione che avevo adottato anch’io.
Ma Julien va oltre, forse, vediamo.
Raccomanda di usare sempre oggetti datetime completi di informazione timezone. Per questo c’è pytz.
Inoltre usare il formato ISO8601 sia in input che output.

tz1

OOPS! :oops: pytz mi manca!

provo a installarlo! ATZ! solo per Python 2.7.x, OK, tanto vale fino al 2020.

Devo installare easy_install con

sudo apt-get install python-setuptools

e quindi pytz

sudo easy_install --upgrade pytz

ed ecco:

tz2

Adesso manca iso8601, installo con

sudo easy_install iso8601

tz3

Però non finisce qui; la documentazione di pytz riporta cose interessanti.

The preferred way of dealing with times is to always work in UTC, converting to localtime only when generating output to be read by humans.

Ed è un pasticcio, proprio come quello che avevo fatto io, senza pytz, bocciato :evil:

Ci sono però parecchie cose, forse anche quello che serve:

tz4

Ma forse no. E se… sì Stack Overflow :grin:
Risulta che si può, ma è tutt’altro che facile, non so nemmeno se mettere il link. Lo metto solo per i più avventurosi, qui: Converting datetime.date to UTC timestamp in Python.

Quindi:

  • Python correggi altrimenti lo dico in giro;
  • Usare sempre UTC se avete a che fare con gente lontana, mettendo l’offset a UTC. Pensa te che per certe zone (India, parte del Canada) si va a mezz’ore.

Intanto Ok, panico :mrgreen:

Lisp – cl-launch – 1

1200x400Continuo da (indovina?) qui: Lisp – cl-launch – 0.
Sì ho problemi di titolazione, ma ci sto lavorando, prossimamente… forse… :wink:

Sono sempre alle prese con cl-launch, voglio provare con un esempio pratico. Pensa che ti ripensa mi è venuto di pensare che potrebbe essere una bella pensata la sequenza di Leonardo Pisano, Fibonacci per gli amici.

Adesso se uno volesse fare le cose per bene seguirebbe François-René, Faré. Questo è come la racconta lui.
Panico :evil:

OK, a frequentare i nerd non ti capita mai e poi mai (assolutamente mai) di trovarti nella stanza sbagliata (che sarebbe poi quella dove il più nerd sei tu). Vista così va meglio e mi da la forza di continuare.

La mia versione è decisamente più realistica:

(defvar n)
(defun fib (x &optional (y 0) (z 1))
   (if (< x z)
     nil
     (append (list z) (fib x z (+ y z)))))

(defun start (n)
   (format t "~a~%" (fib n)))

che gira così:

cl9

Con qualche piccola aggiunta diventa la versione per cl-launch:

#!/usr/bin/cl --entry start
(defvar n)
(defun fib (x &optional (y 0) (z 1))
   (if (< x z)
     nil
     (append (list z) (fib x z (+ y z)))))

(defun start (argv)
   (setf n (parse-integer (car argv)))
   (format t "~a~%" (fib n)))

Notare la shebang con l’opzione --entry e la variabile speciale argv. argv è una lista di stringhe (si vede nel post precedente) per cui devo fare un cast e –pensa te!– mi è venuto car invece di first (chi va con lo zoppo il nerd…).

cl10

Ahemmm… no :evil:
Si deve abilitare (stavo per scrivere chmodare ma poi Sergio…):

cl11

OK :grin:

Ho provato anche a creare l’immagine ma ottengo un errore, eventualmente una cosa per il futuro. Ho anche installato Quicklisp, dal suo sito.

Da parecchio tempo ormai sono conosciuto come pythonista. Anzi agli albori del blog gli amici blogger (quasi tutti passati a cose diverse, più serie, remunerative) mi avevano anche affibbiato un cognome subclassando dal Guido, m’è rimasto (con problemi di pronuncia: van si dice fan e Juhan Giu-an, nèh). Allora da pythonista mi viene da scrivere:

#!/usr/bin/python3
import sys

lim = int(sys.argv[1])
a, b = 1, 1
fib = [a, b]
while b < lim:
	a, b = b, a + b
	fib.append(b)
fib.pop(-1)
print(fib)

cl12

Ecco, non so se sono solo io ma mi viene da ragionare in modo differente. E se per il Lisp posso essere ripreso per aver usato una variabile globale –sarebbe bastato un let— qui la lista viene troppo lunga e devo rimuovere l’ultimo elemento :oops: Sì, si può fare di meglio in entrambi i casi ma ho messo quello che mi è venuto in mente al volo.

cl13

Un confronto impietoso. Facendo la media tra 7 run, eliminando i casi migliore e peggiore, è risultato che il tempo richiesto da cl-launch è 14 volte quello richiesto da Python 3.
E, a rincarare le cose anche la RAM, guarda qua (tre lanci in rapida sequenza):

cpu

Faré ne parla, purtroppo la documentazione è dispersa e non sempre lineare, vedi il link sopra.

Continua, forse… anche perché OOPS! :oops: non posso ancora dirlo :mrgreen:

Programmazione funzionale – si può fare con Python?

bbOK, forse non è l’attrezzo migliore ma vorrei affrontare l’argomento un po’ alla larga. E questo è solo l’inizio. Probabilmente continuerò per questo argomento — forse, chissà :wink: :mrgreen:

Per un caso di pura serendipity trovo questa definizione:

Functional programming (FP) is based on a simple premise with far-reaching implications: we construct our programs using only pure functions—in other words, functions that have no side effects. What are side effects? A function has a side effect if it does something other than simply return a result, for example:

  • Modifying a variable;
  • Modifying a data structure in place;
  • Setting a field on an object;
  • Throwing an exception or halting with an error;
  • Printing to the console or reading user input;
  • Reading from or writing to a file;
  • Drawing on the screen.

È l’inizio di Functional Programming in Scala di Paul Chiusano e Rúnar Bjarnason — grazie a Luis Souto Graña che me l’ha segnalato :grin:
Ecco messo in questi termini non è che si può andare molto lontano. Ma se invece ammettiamo che non tutte le funzioni siano pure forse qualcosa si può fare.

Una richiesta in proposito su Stack Overflow è stata chiusa da tutto un gruppo di amministratori: We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion.

Questa query functional programming in python dimostra un caso pratico. Ma Python per queste cose si dimostra particolarmente inefficiente.

f0E poi un pythonista userebbe probabilmente la list comprehension:

f1Seguono poi un paio (abbondante) di discussioni chiuse per vari motivi. E anche questa richiesta How to construct such a functional-programming tool in Python? molto specifica, imho, ha un paio di risposte pythoniche non semplicissime, anzi :evil:

La mia preferita è questa: Why program functionally in Python?
Anche perché Paul, fa ha la mia questione:  I understand that functional languages are good for concurrency but does programming Python functionally really help with concurrency?
La risposta più quotata, di Alex, è lunga e non riassumibile. E mi sembra che non sia tanto positiva. Io sono per beardedprojamz (la terza): I have to say that too much ‘bandwagoning’ toward OO or functional could lead toward missing elegant solutions.

Ecco, adesso il post sembra ridursi a poca cosa, molto meno di quello che lascia intravedere il titolo. Colpa mia lo ammetto. Ma concludo lo stesso con come la penso, una cosa scontata.
Se rileggo la definizione riportata all’inizio e mi accontento di cose possibili di quelle che riesco a fare anch’io posso arrivare al compromesso di avere funzioni FP (ecco, qui avrei dovuto dire funzioni funzionali) dove possibile, che fanno una sola cosa, senza effetti collaterali, non usano variabili globali (OK, è lo stesso di prima ma così mi capisco), in modo possibilmente efficiente. E che sono facili da capire dagli umani (pensate alla manutenzione). Anche quelli come me che arrivano solo fino a un certo punto (sapete ho cominciato con il Fortran (ma non ditelo a EWD)).

catAl di là di questo ambito non mi sembra che Python sia usabile. O sbaglio? :mrgreen:

Aggiornamento: sono stato precipitoso e pasticcione (assay!). Mi sono dimenticato che avevo materiaale qui nel blog (roba del prof Lipari (rockz)), è passato un po’ di tempo e poi –OK, niente scuse :oops: :cry: :evil:
Ecco un paio di link:

Poi forse continuo, tentando di rimediare :mrgreen:

Risorse Python

python-logoUn commento dell’amico Flavio, the Man from Mars (da quando se n’è andato Marte è l’unico pianeta conosciuto abitato interamente da robots) mi fa una domanda impegnativa, qui:

volendo imparare il Python 3.x, la risorsa (libro, pdf, web) definitiva ed unica che mi consigli di seguire

Mica facile. Anzi, il contrario. Vi faccio un esempio metaforico di una cosa che avete forse già vissuto tutti quanti, probabilmente più e più volte.
Ma prima un avvertimento, un disclaimer: non sono responsabile in alcun modo di eventuali effetti collaterali (side effects) e/o conseguenze immediate, future e protratte nel tempo. Questo va inteso virtualmente, un Gedankenexperiment, nèh!
OK! allora immaginate di entrare in una pasticceria. Ecco, capito? Mica è facile. Nel senso che come si fa a limitarsi a uno, o due, o –ok, QED.

In ogni caso un PDF disponibile liberamente sul web che mi sembra buono è Think Python – How to Think Like a Computer Scientist di Allen B. Downey.
Giù in fondo c’è l’URL per la versione 3.x (versione adattata da Michael Kart) in PDF.
Mi sembra che si possa partire da lì.

Poi naturalmente –avete presente la metafora della pasticceria?– scoprirete che Ce n’est qu’un début, quindi aggiungo un po’ di roba.
Intanto la documentazione sul sito ufficiale di Python, qui: Python 3.4.3 documentation, trovate l’elenco di altre risorse, tante. E quelle raccomandate da loro.
Ci sono i corsi online, per esempio Codecademy, elementare e versione 2.x (è ancora la prevalente, anche se sono d’accordo per insistere con la 3) oppure qui Centre for Education in Mathematics and Computing at the University of Waterloo, 3.x ma molto basico, un assaggino.
Sempre sui corsi online c’è una discussione su Quora: Which online Python course is the best?
C’è un Wikibook: Python Programming, 2-x con indicazioni variazioni 3.x, sembra bello.
Un altro testo vecchio ma usabile, anche questo con parecchi link è Dive Into Python. Come mi fa notare Stefania nei commenti c’è anche la versione per 3.x: Dive Into Python 3.
Una comunità pythonista su G+.
Infine una cosa che ho scoperto sono ultimamente: ZEEF – Find information through people, nel nosto caso Python by Alan Richmond.
Trovate tante cose, anzi avrei potuto rispondere a Flavio, the MfM, comunicandogli solo questo link (ma il mio blog ne avrebbe sofferto). Per esempio utilissimo il CheatSheet e le espressioni regolari e millemila cose ancora.

Due cose ancora:

  • ci sarebbe tutto il discorso di NumPy/SciPy –prossimamente forse;
  • sì, ho problemi di peso.

Mission-Accomplished

:mrgreen:

Lo dice anche Nature: Python

Illustration by the Project Twins

Illustration by the Project Twins

OK, sto scrivendo un altro post ma questo devo segnalarvelo assolutamente. Non perché dica una cosa nuova, anzi dice quello che io sto dicendo da una ventina d’anni, anche sul blog (ma da meno tempo, non è così vecchio). Ma un conto è se lo dico io (me) un altro se compare su Nature.
Esamina il caso di Adina Howe, assistant professor of agricultural and biosystems engineering. Non è una programmatrice, non ha fatto informatica ma ingegneria ambientale. Ma programmare è importante. E sapete cosa dice? Trovate tutto qui: Programming: Pick up Python.

Da oggi manderò a questo post parecchi (non solo MATLABer), mi sa –ritenetevi avvisati nèh! :mrgreen:

E non manca un commento che rimarca la superiorità della programmazione funzionale, uhmmm:wink:

Python è impazzito!! (oppure no)

Picture 1

Girovagando per Facebook ( .. ) mi imbatto in un post: “ehi, qual è il risultato di (-5%4) in python??”

E che sarà? -1 mi dico io.

Invece python sbaglia, e toh! sbaglia anche google, mentre la calcolatrice di windows restituisce correttamente -1 e così anche, riporto fedelmente dal thread, “every programming language”.

Ce n’è abbastanza per porsi qualche domanda e verificare come stanno le cose, e capire se veramente qualcuno sbaglia e qualcun altro no.

Istantanea - 24012015 - 18:22:57

Stiamo parlando dell’operazione di “modulo”, che in informatica è definita come resto r della divisione intera tra due numeri a e b:

a/b=q  con resto  r

tali che b*q+r=a con 0 \leq r <b.

Se a  e b sono entrambi numeri naturali (interi positivi) tutti i linguaggi concordano: 5 modulo 4, o 5%4, restituisce 1. Il risultato della divisione, cioè 1.25 viene arrotondato verso il basso (“floor”) ad 1 ed il resto della divisione risulta 1.

Le cose cambiano se uno dei due termini è negativo: -5/4 restituisce -1.25. Se arrotondo ancora verso lo zero, non compio più un’operazione “floor” ma “ceiling”, cioè arrotondo verso l’alto q e gli assegno valore -1:

q=-1 \Rightarrow r=-1 ed otteniamo ciò che ci aspettiamo istintivamente e che restituisce un compilatore C.

Abbiamo però perso la condizione su r, che deve essere rettificata introducendo un valore assoluto:

0 \leq |r| <b

Python (e google!) mantengono invece l’operazione “floor” ed arrotondano ancora -1.25 verso il basso, cioè verso l’infinito negativo, quindi a -2. Questo permette di lasciare a r il suo segno positivo ma restituisce un risultato meno intuitivo:

4*(-2) +r = -5  \Rightarrow r=3.

Beh, allora chi ha ragione? Entrambi, perché entrambe le definizioni di modulo sono accettate. La scelta di implementare l’una o l’altra dipende da chi definisce il linguaggio.

Ecco come Guido Van Rossum spiega la scelta di mantenere l’operazione “floor” in Python:

I matematici che si occupano di teoria dei numeri preferiscono questa soluzione (Wikipedia). In Python ho deciso di fare lo stesso perché esistono alcune applicazioni interessanti della funzione modulo nelle quali il segno di a è irrilevante.  Supponiamo di avere un “francobollo” POSIX, cioè una data espressa come numero di secondi trascorsi dal primo gennaio 1970, e di voler estrarre da esso l’ora del giorno. Siccome ci sono 24*3600 = 86400 secondi in un giorno, l’orario (espresso in secondi) è semplicemente il risultato dell’operazione t%86400. Se però ci troviamo con una data antecedente il 01/01/1970 abbiamo un operando negativo, e se eseguiamo l’operazione “modulo di 86400” arrotondando verso lo zero otteniamo un risultato senza significato. Arrotondando verso il basso invece tutto torna a posto ed estraiamo l’ora corretta.

E perché non fa la stessa cosa anche il C? Lo spiega ancora Guido:

Probabilmente era l’hardware a non fare questa operazione quando il C è stato progettato. E l’hardware non faceva l’operazione perché i numeri negativi erano rappresentati all’epoca come  “segno” più “ampiezza”, invece delle due rappresentazioni “a complemento” utilizzate ai giorni nostri.

Bene, mi fermo qui. Mi rendo conto di aver messo molta, troppa carne al fuoco…

Qualche riferimento:

Iscriviti

Ricevi al tuo indirizzo email tutti i nuovi post del sito.

Unisciti agli altri 88 follower