HOWTO · C

Stampa numeri in notazione scientifica in C

Questo articolo introduce come stampare i numeri in notazione scientifica in C.

In questa pagina

Usa la conversione %e o %E di printf per visualizzare un valore in virgola mobile in notazione scientifica. La conversione minuscola stampa il simbolo dell’esponente in minuscolo, mentre quella maiuscola lo stampa in maiuscolo. Una precisione come %.3e imposta il numero di cifre dopo la virgola nella mantissa.

Esegui questo esempio:

Il codice e le etichette o gli output visibili in questa sezione restano in inglese.

#include <stdio.h>

int main(void) {
    double values[] = {123456.789, -0.000012345};

    printf("lowercase: %.3e\n", values[0]);
    printf("uppercase: %.3E\n", values[1]);
    return 0;
}

Come funziona la notazione scientifica in C

La notazione scientifica rappresenta un valore diverso da zero come il prodotto di una mantissa e una potenza di dieci. La mantissa ha una sola cifra diversa da zero prima della virgola; l’esponente indica di quante posizioni si sposta la virgola. Per esempio, 123456 si può scrivere come 1.23456 × 10^5, mentre 0.0000123 si può scrivere come 1.23 × 10^-5.

Questa notazione modifica il modo in cui viene visualizzato un valore, non il modo in cui il valore sottostante viene memorizzato da float o double. I tipi a virgola mobile binaria hanno una precisione finita, quindi molte frazioni decimali sono approssimazioni in memoria. Stampare più cifre può mostrare meglio l’approssimazione memorizzata, ma non rende più preciso il valore memorizzato.

Stampare la notazione scientifica con printf

Le conversioni e ed E formattano un argomento double in notazione scientifica. La maiuscola o minuscola del simbolo dell’esponente dipende dalla conversione: %e usa e, mentre %E usa E. L’esponente include un segno e le implementazioni stampano un numero di cifre sufficiente a rappresentarlo. Se vuoi confrontare con la notazione a virgola fissa, usa %f. La specifica POSIX di fprintf definisce le conversioni e ed E e il comportamento della precisione.

Nell’esempio iniziale, %.3e e %.3E mostrano entrambe tre cifre dopo la virgola nella mantissa. Il segno del valore resta parte del numero formattato. Per i valori per cui la notazione a virgola fissa è difficile da leggere, la notazione scientifica mantiene compatta la mantissa e lascia all’esponente il compito di indicare la scala.

La conversione richiede un argomento di tipo double. Un valore float passato a printf viene promosso a double, ma un intero no. Per formattare un intero in notazione scientifica, convertilo esplicitamente, per esempio con (double)count, e usa %e o %E. Gli interi grandi possono perdere le cifre meno significative durante la conversione se superano la precisione rappresentabile da double.

Controllare il numero di cifre dopo la virgola

Per %e e %E, la precisione indica le cifre dopo la virgola, non il numero totale di cifre significative. Quindi %.2e stampa due cifre decimali nella mantissa, di solito tre cifre significative in totale. Se ometti la precisione, il valore predefinito è di sei cifre dopo la virgola. Il valore viene arrotondato per la visualizzazione alla precisione richiesta; il valore memorizzato non cambia. La specifica POSIX di fprintf descrive questa regola e il valore predefinito di sei cifre.

Scegli la precisione in base alle esigenze di visualizzazione o al formato di scambio usato dall’applicazione. Stampare più cifre non garantisce che la stringa decimale rappresenti esattamente il valore in virgola mobile binaria. Se ti serve un numero specifico di cifre significative, considera la cifra iniziale della mantissa quando scegli la precisione.

Formattare stringhe in notazione scientifica in modo sicuro

Quando devi memorizzare il numero formattato o passarlo a un’altra funzione, usa snprintf specificando la capacità del buffer. La capacità include il carattere nullo terminatore. La funzione restituisce il numero di caratteri che sarebbero stati scritti, senza contare il terminatore; un valore di ritorno maggiore o uguale alla capacità indica che l’output è stato troncato. Un valore di ritorno negativo indica un errore di formattazione. La specifica POSIX di fprintf definisce il valore restituito da snprintf e il comportamento in caso di troncamento.

Esegui questo esempio completo:

Il codice e le etichette o gli output visibili in questa sezione restano in inglese.

#include <stdio.h>

int main(void) {
    double measurement = 0.000012345;
    char text[64];
    int length = snprintf(text, sizeof text, "%.3e", measurement);

    if (length < 0) {
        puts("formatting error");
        return 1;
    }
    if ((size_t)length >= sizeof text) {
        puts("buffer too small");
        return 1;
    }

    printf("value: %s\n", text);
    return 0;
}

snprintf scrive al massimo entro la capacità disponibile e termina il buffer con il carattere nullo quando la sua capacità è maggiore di zero. Controlla il valore restituito prima di considerare il buffer come un risultato formattato completo. Evita sprintf senza limiti se non hai la certezza che il buffer sia abbastanza grande.

Conviene scrivere una funzione personalizzata per la notazione scientifica?

Di solito, no. In base alle regole di formattazione della libreria C, %e e %E gestiscono già la mantissa, l’esponente, il segno, l’arrotondamento e il valore zero. Una conversione scritta a mano deve trattare separatamente lo zero e normalizzare sia i valori inferiori a uno sia quelli pari o superiori a dieci. Deve inoltre considerare i valori negativi, gli arrotondamenti che modificano la mantissa e i limiti del tipo numerico. Un ciclo che divide per dieci soltanto i valori positivi non gestisce correttamente questi casi.

Per visualizzare direttamente un valore, preferisci printf; per formattare una stringa entro limiti definiti, usa snprintf. Scrivi un formattatore personalizzato solo se ti serve una rappresentazione specifica che le conversioni standard non possono fornire, e definisci e verifica il suo comportamento per l’intero intervallo di input. Per la normale notazione scientifica, le conversioni standard sono più brevi e meno soggette a errori.