Funzioni di Classificazione e Manipolazione per i Numeri in Virgola Mobile in Linguaggio C

Concetti Chiave
  • Lo standard C fornisce macro per classificare i numeri in virgola mobile in categorie come normali, subnormali, infiniti e NaN.
  • Le macro di classificazione includono fpclassify, isfinite, isinf, isnan, isnormal e signbit.
  • Lo standard C offre anche funzioni per manipolare i numeri in virgola mobile a basso livello, come copysign, scalbn, nextafter e nexttoward.
  • Le funzioni di manipolazione consentono di copiare il segno, moltiplicare per potenze di due e trovare il numero rappresentabile più vicino a un dato numero in virgola mobile.

Macro di Classificazione dei Numeri in Virgola Mobile

Lo standard C fornisce diverse macro per classificare i numeri in virgola mobile. Queste macro sono definite nell'header <math.h>.

Lo scopo di queste macro parametriche è quello di determinare se un numero in virgola mobile è un numero normale oppure rappresenta un valore speciale come infinito o NaN (Not a Number).

Tali macro prendono in ingresso un argomento di tipo double, float o long double e restituiscono un valore intero che indica la classificazione del numero.

Tali macro sono:

  • int fpclassify(real x);

    Questa macro prende in ingresso un numero in virgola mobile x di qualsiasi tipo (double, float o long double) e restituisce un valore intero che indica la classificazione del numero. I valori di ritorno possibili sono:

    • FP_INFINITE: se x rappresenta l'infinito positivo o negativo.
    • FP_NAN: se x rappresenta un valore NaN (Not a Number).
    • FP_NORMAL: se x è un numero normale.
    • FP_SUBNORMAL: se x è un numero subnormale (denormalizzato).
    • FP_ZERO: se x è zero (positivo o negativo).
  • int isfinite(real x);

    Questa macro restituisce un valore diverso da zero (vero) se il numero in virgola mobile x è finito (cioè non è infinito né NaN), altrimenti restituisce zero (falso).

  • int isinf(real x);

    Questa macro restituisce un valore diverso da zero (vero) se il numero in virgola mobile x rappresenta l'infinito positivo o negativo, altrimenti restituisce zero (falso).

  • int isnan(real x);

    Questa macro restituisce un valore diverso da zero (vero) se il numero in virgola mobile x rappresenta un valore NaN (Not a Number), altrimenti restituisce zero (falso).

  • int isnormal(real x);

    Questa macro restituisce un valore diverso da zero (vero) se il numero in virgola mobile x è un numero normale, altrimenti restituisce zero (falso).

  • int signbit(real x);

    Quest'ultima macro è leggermente differente rispetto alle altre. Essa restituisce un valore diverso da zero (vero) se il bit di segno del numero in virgola mobile x è impostato (cioè se x è negativo), altrimenti restituisce zero (falso). Questa macro può essere utilizzata per determinare il segno di numeri speciali come zero, infinito e NaN.

Queste macro sono utili per gestire correttamente i numeri in virgola mobile in situazioni in cui è necessario distinguere tra numeri normali, subnormali, infiniti e NaN, garantendo così un comportamento prevedibile e sicuro nelle operazioni matematiche.

Funzioni di Manipolazione dei Numeri in Virgola Mobile

Oltre alle macro di classificazione, lo standard C fornisce anche diverse funzioni per manipolare i numeri in virgola mobile.

Con il verbo "manipolare" si intende eseguire operazioni che lavorano a basso livello sui numeri in virgola mobile.

Le operazioni di manipolazione includono:

  • Copia del segno:

    Le funzioni:

    • double copysign(double x, double y);
    • float copysignf(float x, float y);
    • long double copysignl(long double x, long double y);

    Queste funzioni restituiscono un numero in virgola mobile con il valore assoluto di x e il segno di y. In altre parole, il risultato avrà lo stesso valore numerico di x, ma il segno (positivo o negativo) sarà quello di y.

  • Moltiplicazione per potenze di due:

    Le funzioni:

    • double scalbn(double x, int n);
    • float scalbnf(float x, int n);
    • long double scalbnl(long double x, int n);

    Queste funzioni restituiscono il risultato di x moltiplicato per 2 elevato alla potenza di n. In pratica, queste funzioni modificano l'esponente del numero in virgola mobile x aggiungendo n all'esponente corrente.

    Ad esempio, se x è 1.5 (che è rappresentato come 1.5 \cdot 2^0) e n è 2, il risultato sarà 6.0 (che è rappresentato come 1.5 \cdot 2^2).

    Questa operazione è molto più efficiente rispetto alla moltiplicazione diretta per potenze di due, poiché agisce direttamente sull'esponente del numero in virgola mobile che è in base 2.

  • Funzioni di ricerca dei numeri rappresentabili:

    Anche se i numeri in virgola mobile vengono usati per rappresentare numeri reali, non tutti i numeri reali possono essere rappresentati esattamente in questo formato a causa delle limitazioni di precisione. Anzi, una quantità infinita di numeri reali non può essere rappresentata esattamente in virgola mobile.

    Dato che i numeri double, float e long double hanno un numero di bit limitato per rappresentare la mantissa e l'esponente, esistono solo un numero finito di valori che possono essere rappresentati esattamente. Quindi, dato un numero floating point è sempre possibile trovare il numero rappresentabile più vicino ad esso.

    In tal senso, lo standard C fornisce le seguenti funzioni:

    • double nextafter(double x, double y);
    • float nextafterf(float x, float y);
    • long double nextafterl(long double x, long double y);
    • double nexttoward(double x, long double y);
    • float nexttowardf(float x, long double y);
    • long double nexttowardl(long double x, long double y);

    Le funzioni nextafter e nexttoward restituiscono il numero in virgola mobile rappresentabile più vicino a x nella direzione di y. Se x è uguale a y, viene restituito y.

    La differenza tra le due funzioni è che nextafter accetta entrambi gli argomenti dello stesso tipo (ad esempio, entrambi double), mentre nexttoward accetta il primo argomento di tipo double, float o long double, e il secondo argomento di tipo long double. Questo permette a nexttoward di fornire una maggiore precisione nella direzione verso cui si desidera trovare il numero rappresentabile più vicino.