HOWTO · C

Imprimir Números em Notação Científica em C

Este artigo apresenta como imprimir números em notação científica em C

Nesta página

Use a conversão %e ou %E de printf para exibir um valor de ponto flutuante em notação científica. A conversão em minúsculas imprime o marcador do expoente em minúsculas; a conversão em maiúsculas o imprime em maiúsculas. Uma precisão como %.3e define o número de dígitos após o separador decimal no significando.

Execute este exemplo:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

#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;
}

Como funciona a notação científica em C

A notação científica representa um valor diferente de zero como um significando multiplicado por uma potência de dez. O significando tem um dígito diferente de zero antes do separador decimal; o expoente indica quantas casas a vírgula se desloca. Por exemplo, 123456 pode ser escrito como 1.23456 × 10^5, enquanto 0.0000123 pode ser escrito como 1.23 × 10^-5.

Essa notação muda a forma como um valor é exibido, mas não a maneira como o float ou o double subjacente o armazena. Os tipos de ponto flutuante binário têm precisão finita, por isso muitas frações decimais são aproximações na memória. Imprimir mais dígitos pode revelar melhor a aproximação armazenada; isso não aumenta a precisão do valor armazenado.

Imprima notação científica com printf

As conversões e e E formatam um argumento double em notação científica. A letra do marcador de expoente acompanha a conversão: %e usa e e %E usa E. O expoente inclui um sinal, e as implementações imprimem dígitos suficientes para representá-lo. Use %f quando quiser comparar com a notação de ponto fixo. A especificação POSIX de fprintf define as conversões e e E e o comportamento da precisão.

No exemplo de abertura, %.3e e %.3E mostram três dígitos após o separador decimal no significando. O sinal do valor continua fazendo parte do número formatado. Para valores cuja magnitude torna difícil ler a saída em ponto fixo, a notação científica mantém o significando compacto e deixa o expoente indicar a escala.

A conversão espera um argumento double. Um float passado para printf é promovido a double, mas um inteiro não. Para formatar um valor inteiro em notação científica, converta-o explicitamente, por exemplo com (double)count, e use %e ou %E. Inteiros grandes podem perder dígitos menos significativos na conversão se ultrapassarem a precisão representável por double.

Controle o número de dígitos após o separador decimal

Para %e e %E, a precisão conta os dígitos após o separador decimal, não o total de algarismos significativos. Assim, %.2e imprime dois dígitos fracionários no significando, geralmente três algarismos significativos ao todo. Se você omitir a precisão, o padrão é de seis dígitos após o separador decimal. O valor é arredondado para exibição conforme a precisão solicitada; o valor armazenado não muda. A especificação POSIX de fprintf descreve a regra de precisão e o padrão de seis dígitos.

Escolha a precisão de acordo com a exibição ou o formato de intercâmbio de que sua aplicação precisa. Imprimir mais dígitos não garante que a string decimal represente exatamente o valor de ponto flutuante binário. Se você precisa de um número específico de algarismos significativos, considere o dígito inicial do significando ao escolher a precisão.

Formate strings em notação científica com segurança

Quando for necessário armazenar o número formatado ou passá-lo a outra função, use snprintf com a capacidade do buffer. Essa capacidade inclui o caractere nulo de terminação. A função retorna o número de caracteres que teria escrito, sem contar esse terminador; um valor de retorno maior ou igual à capacidade indica que a saída foi truncada. Um valor de retorno negativo indica um erro de formatação. A especificação POSIX de fprintf define o valor de retorno de snprintf e o comportamento de truncamento.

Execute este exemplo independente:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

#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 escreve no máximo até a capacidade disponível e termina o buffer com um caractere nulo quando sua capacidade é maior que zero. Verifique o valor de retorno antes de tratar o buffer como um resultado formatado completo. Evite sprintf sem limite quando não houver garantia de que o buffer terá espaço suficiente.

Vale a pena escrever uma função própria para notação científica?

Em geral, não. %e e %E já tratam o significando, o expoente, o sinal, o arredondamento e o valor zero de acordo com as regras de formatação da biblioteca de C. Uma conversão escrita à mão precisa tratar o zero separadamente e normalizar valores menores que um, assim como valores iguais ou maiores que dez. Também precisa considerar valores negativos, arredondamentos que alterem o significando e os limites do tipo numérico. Um laço que apenas divide valores positivos por dez não cobre esses casos corretamente.

Prefira printf para exibir diretamente e snprintf para formatar strings com limite de tamanho. Escreva um formatador próprio somente quando precisar de uma representação específica que as conversões padrão não oferecem, e defina e verifique seu comportamento para toda a faixa de entradas. Para a notação científica comum, as conversões padrão são mais curtas e menos sujeitas a erros.