Il Bar dell'Ingegneria

Tre virgola venticinque fattoriale

« Older   Newer »
 
  Share  
.
  1.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    In altro topic, vedi Weibull vs Rayleigh , è spuntata la funzione Gamma di Eulero per la determinazione di uno dei parametri della distribuzione di Weibull.
    Approfondendo quella questione ho visto che la funzione diretta Gamma() di Eulero non è implementata tra le funzioni Built-in di Excel che invece ha la funzione Ln.Gamma().

    Utilizzando quest'ultima è comunque possibile risalire al valore restituito dalla funzione Gamma().

    Adesso vorrei poter scrivere una funzione UDF che implementi direttamente la funzione Gamma di Eulero.
    E' lo scopo di questo topic.
    Attached Image
    GammaFunction_1000

     
    Top
    .
  2.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    3,345
    Reputation
    +213

    Status
    Offline
    i cosiddetti "workaround" senza scrivere una funzione dedicata sono i seguenti:

    Γ(x) = EXP(GAMMALN(x))

    Γ(x) = EXP(-1) / GAMMADIST(1, x, 1, FALSE)

    il primo fa uso della built-in function GAMMALN(x), il secondo fa uso della distribuzione GAMMA.

    non ho volutamente cercato su internet la UDF specifica perché ritengo di notevole interesse l'esposizione che afazio intende fare in questo post.
     
    Top
    .
  3.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    CITAZIONE (reversi @ 18/3/2016, 11:35) 
    i cosiddetti "workaround" senza scrivere una funzione dedicata sono i seguenti:

    Γ(x) = EXP(GAMMALN(x))

    Γ(x) = EXP(-1) / GAMMADIST(1, x, 1, FALSE)

    il primo fa uso della built-in function GAMMALN(x), il secondo fa uso della distribuzione GAMMA.

    non ho volutamente cercato su internet la UDF specifica perché ritengo di notevole interesse l'esposizione che afazio intende fare in questo post.

    Ringraziandoti per l'interesse manifestato, spero di non deludere le tue aspettative. Ti anticipo però che io non sono un esperto e tranne la funzione che è di mia scrittura (e che proporrò alla fine) quanto riferirò lo si può facilmente trovare su internet.
    Per quanto riguarda la UDF in VBA per excel, le mie ricerche non hanno dato esito positivo tranne il fatto di aver trovato la sua implementazione nel pacchetto di Leo Volpi XNumber.dll.
    Essendo una DLL non ho potuto leggere il codice e poi quel pacchetto implementa oggetti matematici con aritmetica a grande precisione.
     
    Top
    .
  4.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    Un po' di storia.

    La prima volta che mi sono imbattuto, con interesse, su Christian Goldbach è stata in occasione della lettura del libro "L'enigma dei numeri primi". Prima forse ne avevo letto il nome ma non si era destato il mio interesse tanto da poterlo ricordare.
    Famosa è la sua congettura sui numeri primi che afferma che ogni naturale maggiore di 2 è sempre esprimibile come somma tra due o più numeri primi.
    Per esempio 28 lo si può esprimere come 23+3+2. Provate con qualsiasi numero abbordabile e troverete sempre una somma tra numeri primi eventualmente anche duplicati che da come risultato il numero dato.
    La congettura non è stata ancora dimostrata e per chi riesce a farlo c'è un premio ancora valido.

    Vi starete chiedendo cosa c'entra Goldbach con la questione della funzione gamma di Eulero.
    Goldbach, che nasce a Königsberg (vi dice niente questa cittadina?) ebbe intenso scambio epistolare con il nostro Eulero e proprio da uno dei quesiti proposti da Goldbach ad Eulero che nasce il famoso problema dei sette ponti di Königsberg.

    Konigsberg_bridges



    Ma oltre alla sua congettura sui numeri primi ed alla questione del percorso unico sui ponti della sua città natale, Goldbach sollecitò Eulero sulla questione dei fattoriali.
    Da qui nasce la funzione Gamma di Eulero.

    In sostanza la funzione Gamma altro non è che il fattoriale di un numero reale. Quindi Eulero ha esteso il concetto di fattoriale oltre che agli interi anche ai numeri reali.

    3! = 1*2*3 = 6
    3.25! =Γ(3.25+1)= 2.54925696671849...

    Edited by afazio - 19/3/2016, 23:44
     
    Top
    .
  5.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    Non riporterò le trattazioni presenti nei numerosi siti di matematica che spiegano la funzione Gamma poiché non è questo lo scopo del topic e poichè potrete tranquillamente leggerle da voi, voglio invece applicare usando excel e la sua funzione EXP(LN.GAMMA(x)] il concetto di fattoriale di un numero reale.

    Costruite, pertanto, una tabella con la prima colonna dedicata al numero reale x di cui vogliamo il GAMMA(x) e la seconda dedicata a contenere la funzione =EXP(LN.GAMMA(x)]

    Proviamo quindi a calcolare GAMMA(3.25).
    Il risultato, come vi ho anticipato, è 2.54925696671849...

    Per capire come spunta il fattoriale, arricchiamo la tabella inserendo i reali precedenti e successivi che differiscono di 1 partendo da 3.25,
    quindi la sequenza 0.25, 1.25; 2.25; 3.25; 4.25; 5.25... basta fermiamoci qui.

    Otteniamo la seguente tabella:

    6KoL98b

    Questa ancora non ci fa notare nulla. Aggiungete una terza colonna col prodotto tra il numero x ed il suo GAMMA(x)

    Otteniamo:

    mOpVH2f

    Da qui notiamo subito che
    0.25*Γ(0.25) =Γ(1.25)

    Completando la colonna otteniamo la seguente matrice:

    mtyAaCA

    Vediamo confermata la relazione:

    Γ(x+1)=x*Γ(x)

    Ma se ci fate caso, il valore di Γ(5.25) lo possiamo ottenere mediante il prodotto di tutti i reali che precedono il numero e che differiscono di 1 a partire da esso, per il Gamma del più piccolo di essi, cioè:

    Γ(5.25) = 4.25*3.25*2.25*1.25*0.25*Γ(0.25)

    Basta quindi conoscere il Gamma della parte decimale del numero dato per determinare mediante prodotto delle sequenza ottenuta partendo dal decimale sommando sempre 1 col gamma della parte decimale , il gamma del reale dato.
    E' più facile comporre la tabella che non a scrivere il concetto.
    Provate.
     
    Top
    .
  6.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    Che succede se invece inseriamo degli interi?
    Dovremmo vedere duplicata la funzione fattoriale che conosciamo. Quindi per n=4 dovremmo trovare 1*2*3*4=24

    Invece otteniamo il fattoriale del precedente cioe 3!=6:

    Questo semplicemente perche la relazione è:

    Γ(n)=(n-1)!
    oppure
    Γ(n+1)=n!

    FPP9pO1
     
    Top
    .
  7.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    E se invece tentiamo di calcolare la funzione Gamma per un reale negativo?

    zAqDURZ

    Nulla. Excel non riesce a calcolarli e questo semplicemente per il fatto che noi siamo dovuti passare attraverso la funzione LN.GAMMA() in mancanza della funzione diretta Gamma():

    Eppure guardando il grafico della funzione postata nel primo messaggio, vediamo che i valori della funzione esistono pure per reali negativi esclusi gli interi negativi.

    gif

    Edited by afazio - 19/3/2016, 23:47
     
    Top
    .
  8.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    Vediamo adesso di iniziare a ragionare con un po' di codice.
    Anche se non è questo lo scopo, penso sia utile iniziare a vedere come poter affrontare la cosa con la funzione gamma applicata agli interi.
    Questo non dovrebbe offrire particolari difficoltà potendo procedere in maniera ricorsiva come per la funziona fattoriale.
    In questo caso la ricorsione si basa sulle seguenti relazioni:

    mS7yjLQ

    La funzione ricorsiva, cioè che chiama se stessa fino a trovare il punto di uscita, è la seguente:

    CODICE
    Private Function Fatt_ricorsivo(n As Long) As Long
    If n <= 1 Then
       Fatt_ricorsivo = 1
    Else
       Fatt_ricorsivo = n * Fatt_ricorsivo(n - 1)
    End If

    End Function


    Una funzione di una estrema semplicità che poi è quella utilizzata nei corsi specifici per spiegare il concetto della "ricorsione".

    Come per il fattoriale, anche per la funzione Gamma() applicata agli interi possiamo individuare un procedimento ricorsivo basato sulle seguenti relazioni:

    MhG1sm6

    con queste è immediato il codice che segue:

    CODICE
    Public Function Gamma_ricorsivo(n As Long) As Long
    If n <= 1 Then
       Gamma_ricorsivo = 1
    Else
       Gamma_ricorsivo = (n - 1) * Gamma_ricorsivo(n - 1)
    End If

    End Function


    Notate che il codice è sostanzialmente uguale a quello del fattoriale ricorsivo tranne l'adattamento dei fattori.

    Ma a noi serve la funzione gamma() applicata ai reali e questa è poco utile allo scopo.

    Edited by afazio - 19/3/2016, 23:47
     
    Top
    .
  9.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    Volendo scrivere un codice ricorsivo per la funzione gamma() applicata ad un reale dovremmo riferirci ad una formula che contiene se stessa anche al secondo membro. Ma gia la definizione di gamma, contiene gamma dato che come abbiamo visto risulta:

    YlmEHgt

    estendendo coi prodotti dei termini successivi abbiamo:

    jPLbpk2

    Ci manca però il punto di uscita della funzione ricorsiva, cioè un valore noto della stessa funzione che lo si dovrebbe determinare attraverso l'integrale che definisce la funzione stessa:

    aOURGft

    Ma questo integrale, salvo casi particolari, non è di facile soluzione.

    Uno dei casi particolari risolti da Eulero è, per esempio, il valore di Γ(1/2)
    In questo caso l'integrale si scrive come:

    0yB5fS2

    Il valore di Γ(1/2)=radq(PI) può essere quindi assunto come punto di uscita per il calcolo di tutti i reali esprimibili come:

    x= n+1/2

    con n= 1, 2 , 3....

    quindi per i numeri reali: 1.5; 2.5; 3.5; 4.5; ....

    In particolare avremo:
    Γ(4.5)= 3.5*2.5*1.5*0.5*Radq(PI) = 11.63173...
    che corrisponde al valore ottenuto con la funzione Excel=EXP(LN.GAMM(4.5))
     
    Top
    .
  10.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    3,345
    Reputation
    +213

    Status
    Offline
    vedo che afazio è partito con la creazione della udf.

    mi inserisco nel topic per postare - con il consenso dello stesso afazio, perché non volevo interferire con il suo sviluppo - una funzione VB che calcola il gamma di eulero:

    CODICE
    Public Function Gamma(ByVal Dou1 As Double) As Double
          Dim I As Integer
          Dim Dou2 As Double
          Dim Dou3 As Double
     
          If Fix(Dou1) = Dou1 Then
              If Dou1 = 0 Or Dou1 = 1 Then
                  Gamma = 1
                  Exit Function
              Else
                  Dou2 = 1
                  For I = 1 To Dou1 - 1
                      Dou2 = Dou2 * I
                  Next
                  Gamma = Dou2
                  Exit Function
              End If
          ElseIf Dou1 > 3 Then
              Dou2 = 1
              For I = 1 To (Fix(Dou1) - 1)
                  Dou2 = Dou2 * (Dou1 - 1)
                  Dou1 = Dou1 - 1
              Next
              Dou3 = Exp(-0.57721566 * Dou1) / Dou1
              For I = 1 To 9999
                  Dou3 = Dou3 * ((1 + (Dou1 / I)) ^ (-1)) * Exp(Dou1 / I)
              Next
              Dou3 = Dou2 * Dou3
              Gamma = Dou3
          Else
              Dou3 = Exp(-0.577215664901533 * Dou1) / Dou1
              For I = 1 To 9999
                  Dou3 = Dou3 * ((1 + (Dou1 / I)) ^ (-1)) * Exp(Dou1 / I)
              Next
              Gamma = Dou3
          End If
      End Function


    afazio nota che questo codice fornisce un risultato che differisce (oltre un certo numero di decimali) da quello fornito dalla funzione:

    Γ(x) = EXP(GAMMALN(x))

    è vero. ma non nel senso che afazio mi ha manifestato.

    cioè, non è Γ(x) = EXP(GAMMALN(x)) a fornire un risultato più preciso, ma è vero l'opposto: questa funzione così costruita fornisce risultati la cui precisione non supera le 9, massimo 10 cifre significative. pare inoltre che abbia problemi anche nell'intervallo 1-2.

    è comunque bene precisare che non è possibile ottenere alcun risultato esatto con qualunque implementazione di gamma per la stessa ragione per cui non è possibile determinare il valore esatto di pi greco.
     
    Top
    .
  11.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    CITAZIONE (reversi @ 18/3/2016, 21:16) 
    è comunque bene precisare che non è possibile ottenere alcun risultato esatto con qualunque implementazione di gamma per la stessa ragione per cui non è possibile determinare il valore esatto di pi greco.

    Giusto. Come per pi.greco o anche e (numero di Nepero), non è possibile ottenere un valore esatto in assoluto per la funzione gamma(x), tuttavia per pigreco sono noti un certo numero di decimali esatti (qualche centinaio o forse migliaio non ricordo) lo stesso dicasi per il numero di Nepero.
    Quindi la corretta dicitura sarebbe "esatto fino alla tot cifra decimale" e possiamo solo parlare di "approssimazione alla tot cifra decimale"

    E' chiaro che non riuscendo a risolvere l'integrale in maniera esatta si deve fare ricorso a qualche metodo numerico o a qualche formula che approssima.

    Edited by afazio - 20/3/2016, 12:37
     
    Top
    .
  12.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    3,345
    Reputation
    +213

    Status
    Offline
    aggiunta

    il numero 0.577215664901533 che compare nel codice che ho postato è la cosiddetta "costante di eulero-mascheroni" legata alla funzione gamma.

    lorenzo mascheroni è stato un matematico che seppe dare un contributo originale ed innovativo anche nel campo della scienza delle costruzioni indicando, per primo, il reale meccanismo di collasso degli archi in muratura, mediante la formazione di cerniere plastiche. meccanismo confermato poi da navier e definitivamente sistematizzato - poco più di 30 anni fa - da heyman.

    CITAZIONE (afazio @ 18/3/2016, 21:24) 
    ... tuttavia per pigreco sono noti un certo numero di decimali esatti (qualche centinaio o forse migliaio non ricordo) lo stesso dicasi per il numero di Nepero.

    centinaia di migliaia.

    una volta mi chiesi: a che pro? la risposta fu: testano la potenza di calcolo dei computer.
     
    Top
    .
  13.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    Le approssimazioni di gamma(x)

    La funzione gamma, salvo casi particolari, non è determinabile con esattezza e questo per il fatto che non possediamo la soluzione dell'integrale che la definisce.

    Per calcolare gamma(x) con x reale dobbiamo quindi fare ricorso ad un qualche metodo numerico che ci permette di valutare l'integrale, oppure in alternativa a qualche formula che lo approssima con una fissata precisione.

    Molti autori hanno proposto delle formule approssimate. La più semplice è quella proposta da Stirling:

    cclMMze

    Ho messo insieme su tre diverse colonne i valori restituiti da EXP(LN.GAMMA(x)), quello restituito dalla funzione postata da Reversi e quello ottenuto con l'approssimazione di Stirling:

    BEsMz2p

    Notiamo che:
    - l'approssimazione di Stirling è troppo grossolana. Tuttavia essa viene tranquillamente applicata come valida approssimazione di Gamma nelle applicazioni statistiche;
    - l'approssimazione di Stirling non calcola il gamma per reali inferiori ad 1
    - la funzione proposta da reversi si scosta da quella di Excel dopo qualche decimale.

    In particolare anche per Γ(1/2) per il quale abbiamo la soluzione esatta [ Γ(1/2)=radq(PI)] i risultati differiscono dalla quinta cifra decimale in poi.

    funzione di reversi: Γ(1/2)=1.77243169463232...
    funzione EXP(LN.Gamma(1/2))=1.77245385102051

    In effetti abbiamo:
    RadQ(PI.GRECO) = 1.77245385090552..

    Sono costretto a smentire Reversi infatti confrontando il primo con il terzo ottengo:
    excel 1.77245385102051
    esatt 1.77245385090552..

    confrontando il secondo col terzo ottengo:
    Rever 1.77243169463232
    esatto 1.77245385090552

    Il numero di cifre decimali uguali nel primo confronto è 8, il numero di cifre decimali uguali nel secondo confronto è 4.

    Si deduce che la funzione excel da un risultato "più preciso" di quello fornito dalla funzione.

    Ho anche voluto fare il calcolo "a mano" dei gamma dei reali proposti ed ecco la tabella riassuntiva:

    L6UCEpX

    Con calcolo a mano intendo l'applicazione della formula:

    Γ(4.5)=3.5*2.5*1.5*0.5*radq(PI.Greco())

    ------
    Purtroppo la precisione di qualsiasi calcolo viene limitata in excel alle prime 15 cifre complessive (parte intera e parte decimale), dopo di che è inutile cercare altro.

    Edited by afazio - 20/3/2016, 12:44
     
    Top
    .
  14.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    Per curiosità ho voluto calcolare gamma(0.5) in WXmaxima con la funzione

    Function: bffac (expr, n)
    Bigfloat version of the factorial (shifted gamma) function. The second argument is how many digits to retain and return, it's a good idea to request a couple of extra.

    Categories: Gamma and factorial functions Numerical evaluation



    bffac(0.5,50); ho praticamente imposto 50 cifre significative e secondo quanto riportato nell'help il risultato dovrebbe essere fedele fino alla 48 esima cifra.

    Il risultato è: 8.8622692545276280387098406224793732052316680157007b-1 che si traduce in:

    Wxmaxima: 0.88622692545276280387098406224793732052316680157007
    Noto che questo però coincide con il gamma(1.5) che abbiamo finora determinato. Ecco spiegato lo "(shifted gamma)" presente nella definizione.

    vediamone l'implacabile confronto con quanto ci restituisce Excel:

    EXP(LN.GAMM(1.5)) = 0.886226925395262
    UDF Reversi..............= 0.88612723053155
    a mano:...................= 0.886226925452758

    Ho evidenziato le cifre coincidenti.

    Avendo compreso solo dopo il significato della shifted gamma, ho fatto determinare il valore bffac(-0.5,50)

    ottenendo: 1.7724538509055064468543668422381998109837106913866b0
    che corrisponderebbe a gamma(0.5)

    Il confronto:
    EXP(LN.GAMM(0.5)) = 1.77245385102051
    UDF Reversi..............= 1.77243169463232
    a mano:...................= 1.77245385090552

    Per poter ottenere risultati con grande numero di cifre superando i limiti imposti da Excel dovremmo utilizzare la libreria XNumber.DLL di Leo volpi che permette di impostare il numero di cifre significative a piacimento (o quasi). Non ho fatto la prova ma se qualcuno ne ha voglia puo' farlo e riportare qui i risultati.

    Edited by afazio - 18/3/2016, 23:10
     
    Top
    .
  15.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,169
    Reputation
    +295

    Status
    Offline
    L'approssimazione Quasi-iperbolica

    Questo metodo di approssimazione è basato sul fatto che la parte di curva nell'intervallo [0 , 1] è quasi una iperbole.

    gO56GgI



    Partendo quindi dall'equazione dell'iperbole gli autori di questo metodo hanno determinatioi coefficienti correttivi da applicare per ottenere la migliore interpolazione di quella parte della curva mediante un polinomio correttivo di settimo grado dell'equazione dell'iperbole 1/x.

    Si sfrutterà il valore determinato con questa approssimazione come punto di uscita di una funzione ricorsiva.

    Per esempio, volendo calcolare Gamma(8.372) possiamo scrivere il seguente prodotto:

    gamm(8.372)=7.372*6.372*5.372*4.372*3.372*2.372*1.372*0.372*gamma(0.372).

    Ecco lo stralcio del documento con riportata la descrizione ed i coefficienti.

    Di questo metodo non ho scritto nulla e forse cercherò di scrivere una funzione che si basa su esso alla fine.

    Edited by afazio - 20/3/2016, 12:57
    Attached Image
    QuasiIperbole

     
    Top
    .
33 replies since 18/3/2016, 10:16   1595 views
  Share  
.