mercoledì 14 marzo 2018

Pi Day, questa volta io

Eddài, su, possibile che nessuno dei cervelloni e matematici del Tamburo voglia ricordare il giorno del Pi greco?

Dovrò farlo io, l'ultima ruota del carro...

(confesso, l'ho scopiazzato in internet, spero che nessuno ci denunci per questo)


giovedì 13 marzo 2014

I decimali di π

A grande richiesta, cioè no, a piccola richiesta, Archimede, Ponder Stibbons, me e --forse-- qualcun altro ecco le cifre decimali di π.
Non tutte, i primi 1000.

             5    10    15    20    25    30    35    40    45    50    55    60    65    70    75    80    85    90    95   100 
       0 14159 26535 89793 23846 26433 83279 50288 41971 69399 37510 58209 74944 59230 78164 06286 20899 86280 34825 34211 70679
     100 82148 08651 32823 06647 09384 46095 50582 23172 53594 08128 48111 74502 84102 70193 85211 05559 64462 29489 54930 38196
     200 44288 10975 66593 34461 28475 64823 37867 83165 27120 19091 45648 56692 34603 48610 45432 66482 13393 60726 02491 41273
     300 72458 70066 06315 58817 48815 20920 96282 92540 91715 36436 78925 90360 01133 05305 48820 46652 13841 46951 94151 16094
     400 33057 27036 57595 91953 09218 61173 81932 61179 31051 18548 07446 23799 62749 56735 18857 52724 89122 79381 83011 94912
     500 98336 73362 44065 66430 86021 39494 63952 24737 19070 21798 60943 70277 05392 17176 29317 67523 84674 81846 76694 05132
     600 00056 81271 45263 56082 77857 71342 75778 96091 73637 17872 14684 40901 22495 34301 46549 58537 10507 92279 68925 89235
     700 42019 95611 21290 21960 86403 44181 59813 62977 47713 09960 51870 72113 49999 99837 29780 49951 05973 17328 16096 31859
     800 50244 59455 34690 83026 42522 30825 33446 85035 26193 11881 71010 00313 78387 52886 58753 32083 81420 61717 76691 47303
     900 59825 34904 28755 46873 11595 62863 88235 37875 93751 95778 18577 80532 17122 68066 13001 92787 66111 95909 21642 01989
Volendo c'è e, √(2), φ, altri ancora. Uh, lo script Python è questo (modificare il numero di riga 15):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/python
# -*- coding: utf-8 -*-

import subprocess

def riga_numeri(bl, n):
    f.write(bl + ' ')
    for c in range(n / 5):
        f.write('{:>5} '.format((c + 1) * 5))
    f.write('\n')
    
def num_col(n):
    f.write('{:>8} '.format(n))

p = subprocess.Popen("pi 1000001", shell=True, 
                stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
st = p.stdout.read()
    
f = open("pag", "w")

#lunriga = 20 #per prova
#lunriga = 50 #per OKp
lunriga = 100 #per TR

bl = " " * 8
riga_numeri(bl, lunriga)
n = 0
for c in st[2:-1]:
    if (n % lunriga) == 0:
        num_col(n)
    f.write(c)
    n += 1
    if (n % lunriga) == 0:
        f.write("\n")
    elif (n % 5) == 0:
        f.write(" ")
f.close()

domenica 2 marzo 2014

Contare le cifre di PI

Uh! marzo e tra un po', il 14, ritorna il Pi Day. Che è una cosa bellissima, piace ad Archimede e allo spammer che perseguita questo blog, ce ne sono tanti ma lui vince alla grande, sappiamo che viene dalla 'Merica, Dirk Gently sta indagando, prossimamente...

Che ne dite di un piccolo esercizio da info-mate-matto? "Calculemus" direbbe il nosto amico Herr Doktor Gottfried Wilhelm von Leibnitz, "Ja, machen wir es selbst!" risponderebbe in coro lo stuolo dei Bernoulli. "OK" dico io (me).

Io uso Linux, si può fare con qualche piccola modifica anche con Windows ma non ho un 'puter con quello sopra, prossimamente chissà, qualche volonteroso?

Per non sembrare troppo banale userò una pipe, quelle inventate dall'amico Douglas McIlroy e Python. Python lo consiglio da sempre, anche per quelli costretti a convivere con Windows (è uguale-uguale).

Userò pi, un programmino che compute decimal Archimedes' constant Pi to arbitrary accuracy. È un demo della libreria CLN di Bruno Haible e Richard Kreckel.


Bello vero? Vediamo come si comporta con l'arrotondamento


OK, proprio come vogliamo, non arrotonda. Perché se dobbiamo contare possiamo arrivare fino in fondo alla stringa. Vado? Ecco:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys, subprocess

ndec = int(sys.argv[1]) + 1
cmd = "pi " + str(ndec)

p = subprocess.Popen(cmd, shell=True, 
                     stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
pi_str = p.stdout.read()

pi_dig = [0 for i in range(10)]
for c in pi_str[2:-1]:     #pi_str termina con un \n
    pi_dig[int(c)] += 1

somma = 0
s_delta = 0
media = ndec / 10
for n in range(10):
    somma += pi_dig[n]
    delta = pi_dig[n] - media
    d_rel = float(delta) / media
    s_delta += delta
    print "{0:1} {1:6} {2:6} {3:10.2E}".format(n, pi_dig[n], delta, d_rel)

print "\n", "numero di cifre =", somma, "  controllo =", s_delta

Serve qualche chiarimento? Eccolo!
La prima riga (inizia con # quindi è un commento) è speciale per Linux; indica con quale programma eseguire lo script, se abilitato. Ha anche un nome difficile, shebang.
La seconda riga (commento anche questo: # e tutto quello il resto della riga è un commento, non ve lo dico più, nèh!) abilita il set di caratteri UTF-8; in questo caso è inutile, come pure per la versione 3.x di Python. Io sono talmente abituato a inserire queste due righe che lo faccio senza neanche accorgermene.

Alla riga 4 elenco i moduli che verranno utilizzati.
Riga 6: sys.argv[1] contiene il primo parametro passato allo script, è una stringa, quindi devo trasformarlo in intero con int(). pi considera il numero come numero totale di cifre, compreso il 3 iniziale, per questo aumento il parametro passato di 1.
Riga 7: cmd è il comando che chiederò a Python di eseguire, è formato dalla stringa "pi " + il numero costruito alla riga precedente. Ma, attenzione, devo passarglielo come stringa, quindi uso str().

Righe 9 e 10: sarebbero una riga sola ma troppo lunga (per me, non per Python) e allora l'ho spezzata. Creo l'oggetto p come sottoprocesso di Python. Importante la cattura dell'output (stdout) e dell'eventuale errore (stderr) con una pipe.
Riga 11: metto nella variabile (stringa) pi_str l'output di pi che si trova per quanto detto sopra nell'oggetto p.

Le cifre che conterò le metto in una lista (in altri programmi si userebbe un array, chiamato a volte vettore). La riga 13 crea appunto la lista pi_dig che contiene 10 elementi, interi posti uguali a 0. Potevo scriverla anche come pi_dig = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ma sarebbe stato meno elegante (e poi avrei dovuto contare fino a 10).

Un paio di osservazioni: con Python una variabile viene creata quando la usi e il tipo (intero, numero-con-la-virgola, stringa, oggetto-di-tipo-X) viene inferito da Python stesso. Si può sempre cambiare, vedi righe 6 e 7.
Per liste e array gli indici partono sempre da 0, quindi per pi_dig saranno compresi nell'intervallo [0, 9], toh! proprio le cifre che stiamo trattando.
Altra particolarità di Python (e di altri linguaggi moderni, p.es. Go) nei cicli l'elemento finale s'intende escluso, quindi range(10) sarà l'intervallo [0, 9]. Qui i nuovi sbagliano; poi con la pratica continueranno a sbagliare ma solo di tanto in tanto.
Ci siamo quasi, abbiamo la stringa lunghissima pi_str = 3.14159265... che termina con il carattere a-capo, di solito ^L, (quasi) universalmente indicato con \n (newline). Ricordandoci che gli indici partono sempre da 0 dovremo saltare lo 0 e l'1 (3.), quindi partire dal 2 e finire non all'ultimo ma uno prima, quindi -1.
Cosa che facciamo nel ciclo di riga 14, c è il carattere corrente della sottostringa pi_dig[2:-1].
Il ciclo definito alla riga 14 viene svolto alla riga 15. c è un carattere che viene convertito in intero. Questo intero aumenta di 1 l'elemento della lista pi_dig.

Fatto. Non ci resta che scrivere i risultati dell'elaborazione.
Definisco la variabile somma che conterrà il numero totale di cifre, cioè il parametro passato allo script. Se la distribuzione fosse perfettamente omogenea ogni cifra risulterebbe pari a un decimo del totale, pari alla variabile chiamata media di riga 19. In realtà ci saranno delle variazioni (delta di riga 22) e la loro somma verrà memorizzata in s_delta (riga 18), che dovrebbe risultare pari a 0. Per avere un'indicazione meno rozza di questo scostamento dalla media per le singole cifre ne calcolo il valore come rapporto rispetto al valore previsto, riga 23.
È tutto, non resta che scriverlo, con un ciclo di print (riga 25) per le 10 cifre e una print ulteriore (riga 27) per i due dati di controllo.
Perché la tabella risulti ordinata sono ricorso a format() ma è un dettaglio.
Facile vero?
Nel frattempo ho trovato un modo per verificare la bontà dell'elaborazione; pare sia tutto OK (ma resto in attesa di osservazioni). Se non ci sono minacce troppo persuasive ci sarà un secondo post. Temo.




Non ho fatto verifiche mano (forse prossimamente) chissà se è tutto OK?
Ed è velocissimo, su un PC 32 bit, 2.4 GHz, 2 GB di RAM, 2 CPU:



Non so se sia necessaria una spegazione del programma, se sì ditemelo. E benvenute le segnalazioni di errore, miglioramenti e quant'altro, nèh!

Una verifica con un metodo completamente differente, qui: Look ma no progs!

giovedì 14 marzo 2013

Pi Day 2013



Non si può fare a meno di partecipare in qualche modo al Pi Day!
Poiché però oggi non ho tempo, mi limito a ricordare un piccolo aneddoto che risale al '600.
Il filosofo Thomas Hobbes (“homo homini lupus”) nella maturità si appassionò di geometria, al punto di convincersi di aver trovato con i suoi studi la sfuggente e agognata “quadratura del cerchio”. Pubblicò allora una ponderosa opera in latino, con il valore esatto di Pi da lui calcolato (3,125).
Il matematico John Wallis rispose con un pamphlet ironico, smontando matematicamente i suoi argomenti.
Il filosofo, piccato, rispose difendendo il proprio lavoro e i due rapidamente si coinvolsero in una diatriba dai toni sempre più accesi. Hobbes non si convinse e non si ritrattò mai del suo errore.


Vi invito poi a visitare  questo sito

e ad ascoltare questa canzone






Buon Pi Day a tutti!