Successivo: , Precedente: , Su: Calcolo con precisione arbitraria   [Contenuti][Indice]


15.5 Aritmetica dei numeri interi a precisione arbitraria con gawk

Quando viene specificata l’opzione -M, gawk esegue tutti i calcoli sui numeri interi usando gli interi a precisione arbitraria della libreria GMP. Qualsiasi numero che appaia come un intero in un sorgente o in un file-dati è memorizzato come intero a precisione arbitraria. La dimensione del numero intero ha come limite solo la memoria disponibile. Per esempio, il seguente programma calcola 5432, il cui risultato è oltre i limiti degli ordinari valori a virgola mobile a doppia precisione dei processori:

$ gawk -M 'BEGIN {
>   x = 5^4^3^2
>   print "numero di cifre =", length(x)
>   print substr(x, 1, 20), "...", substr(x, length(x) - 19, 20)
> }'
-| numero di cifre = 183231
-| 62060698786608744707 ... 92256259918212890625

Se invece si dovesse calcolare lo stesso valore usando valori a virgola mobile con precisione arbitraria, la precisione necessaria per il risultato corretto (usando la formula ‘prec = 3.322 * dps’) sarebbe 3.322 x 183231, o 608693.

Il risultato di un’operazione aritmetica tra un intero e un valore a virgola mobile è un valore a virgola mobile con precisione uguale alla precisione di lavoro. Il seguente programma calcola l’ottavo termine nella successione di Sylvester104 usando una ricorrenza:

$ gawk -M 'BEGIN {
>   s = 2.0
>   for (i = 1; i <= 7; i++)
>       s = s * (s - 1) + 1
>   print s
> }'
-| 113423713055421845118910464

Il risultato mostrato differisce dal numero effettivo, 113.423.713.055.421.844.361.000.443, perché la precisione di default di 53 bit non è suffciente per rappresentare esattamente il risultato in virgola mobile. Si può o aumentare la precisione (in questo caso bastano 100 bit), o sostituire la costante in virgola mobile ‘2.0’ con un intero, per eseguire tutti i calcoli usando l’aritmetica con gli interi per ottenere l’output corretto.

A volte gawk deve convertire implicitamente un intero con precisione arbitraria in un valore a virgola mobile con precisione arbitraria. Ciò si rende necessario principalmente perché la libreria MPFR non sempre prevede l’interfaccia necessaria per elaborare interi a precisione arbitraria o numeri di tipo eterogeneo come richiesto da un’operazione o funzione. In tal caso, la precisione viene impostata al minimo valore necessario per una conversione esatta, e non viene usata la precisione di lavoro. Se questo non è quello di cui si ha bisogno o che si vuole, si può ricorrere a un sotterfugio e convertire preventivamente l’intero in un valore a virgola mobile, come qui di seguito:

gawk -M 'BEGIN { n = 13; print (n + 0.0) % 2.0 }'

Si può evitare completamente questo passaggio specificando il numero come valore a virgola mobile fin dall’inizio:

gawk -M 'BEGIN { n = 13.0; print n % 2.0 }'

Si noti che, per questo specifico esempio, probabilmente è meglio semplicemente specificare:

gawk -M 'BEGIN { n = 13; print n % 2 }'

Dividendo due interi a precisione arbitraria con ‘/’ o con ‘%’, il risultato è tipicamente un valore a virgola mobile con precisione arbitraria (a meno che il risultato non sia un numero intero esatto). Per eseguire divisioni intere o calcolare moduli con interi a precisione arbitraria, usare la funzione predefinita intdiv() (vedi Funzioni numeriche).

Si può simulare la funzione intdiv() in awk standard usando questa funzione definita dall’utente:

# intdiv --- fa una divisione intera

function intdiv(numerator, denominator, result)
{
    split("", result)

    numerator = int(numerator)
    denominator = int(denominator)
    result["quotient"] = int(numerator / denominator)
    result["remainder"] = int(numerator % denominator)

    return 0.0
}

Il seguente programma d’esempio, proposto da Katie Wasserman, usa intdiv() per calcolare le cifre di pi al numero di cifre significative che si è scelto di impostare:

# pi.awk --- calcola le cifre di pi

BEGIN {
    cifre = 100000
    due = 2 * 10 ^ cifre
    pi = due
    for (m = cifre * 4; m > 0; --m) {
        d = m * 2 + 1
        x = pi * m
        intdiv(x, d, risultato)
        pi = risultato["quotient"]
        pi = pi + due
    }
    print pi
}

Quando gli fu chiesto dell’algoritmo usato, Katie rispose:

Non è quello più noto ma nemmeno quello più incomprensibile. È la variante di Eulero al metodo di Newton per il calcolo del Pi greco. Si vedano le righe (23) - (25) nel sito: http://mathworld.wolfram.com/PiFormulas.html.

L’algoritmo che ho scritto semplicemente espande il moltiplicare per 2 e lavora dall’espressione più interna verso l’esterno. Ho usato questo per programmare delle calcolatrici HP perché è piuttosto facile da adattare ai dispositivi di scarsa memoria con dimensioni di parola piuttosto piccole. Si veda http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=899.


Note a piè di pagina

(104)

Weisstein, Eric W. Sylvester’s Sequence. From MathWorld—A Wolfram Web Resource (http://mathworld.wolfram.com/SylvestersSequence.html).


Successivo: , Precedente: , Su: Calcolo con precisione arbitraria   [Contenuti][Indice]