HOWTO · C++

Definir a precisão dos números de ponto flutuante em C++

Este artigo demonstra como definir a precisão de números de ponto flutuante em C++

Nesta página

Para controlar como um valor de ponto flutuante é escrito em um fluxo de saída C++, use std::setprecision. No formato padrão, ele define os algarismos significativos; combine-o com std::fixed quando quiser fixar o número de casas após o separador decimal. Esses manipuladores alteram a representação exibida, não o valor armazenado. Use as funções de arredondamento de <cmath> quando precisar alterar o próprio valor.

Formate a saída de ponto flutuante com std::setprecision

std::setprecision, quando recebe um argumento inteiro, define a precisão das próximas inserções de valores de ponto flutuante no fluxo. Inclua <iomanip> para usar o manipulador. No formato padrão de ponto flutuante do fluxo, a precisão indica o número de algarismos significativos, e o valor padrão é seis. Para valores muito pequenos ou muito grandes, o fluxo pode escolher a notação científica. A configuração de precisão permanece ativa nas inserções seguintes nesse fluxo até ser alterada.

O exemplo completo a seguir compara a formatação padrão, três algarismos significativos, três casas após o separador decimal e o arredondamento de um valor antes de escrevê-lo. std::defaultfloat restaura a formatação padrão do fluxo; a precisão selecionada continua em vigor. A saída observada para este exemplo é:

Os rótulos textuais exibidos no exemplo permanecem em inglês, pois o bloco de código deve ser preservado exatamente.

Execute este exemplo:

#include <cmath>
#include <iomanip>
#include <iostream>

int main() {
  const double value = 123.4567;

  std::cout << std::defaultfloat << std::setprecision(6)
            << "default: " << value << '\n';
  std::cout << std::setprecision(3)
            << "three significant digits: " << value << '\n';
  std::cout << std::fixed << std::setprecision(3)
            << "three decimal places: " << value << '\n';
  std::cout << std::defaultfloat << std::setprecision(6)
            << "rounded value: " << std::round(value) << '\n';
}
default: 123.457
three significant digits: 123
three decimal places: 123.457
rounded value: 123

Escolha entre algarismos significativos e casas decimais

Use std::setprecision(n) para definir algarismos significativos somente quando o fluxo estiver no formato padrão de ponto flutuante. Esse é o formato inicial, e std::defaultfloat o restaura depois que outro formato é selecionado. Os sinalizadores de formatação do fluxo persistem; portanto, se std::fixed tiver sido usado antes, ele continuará ativo e fará com que a precisão conte as casas após o separador decimal. Insira std::defaultfloat antes de std::setprecision(n) quando precisar voltar a contar algarismos significativos. Essa contagem inclui os algarismos dos dois lados do separador decimal. Por exemplo, três algarismos significativos podem exibir 123.4567 como aproximadamente 123 e 0.01234567 como aproximadamente 0.0123; o fluxo pode usar notação exponencial quando ela for mais adequada.

Use std::fixed << std::setprecision(n) para fixar o número de casas após o separador decimal, como na apresentação de valores monetários. Com três casas decimais, um valor como 2.5 é exibido com três casas fracionárias. Isso afeta apenas a formatação: o double subjacente continua armazenando seu valor original em ponto flutuante binário. Para alterar o número de algarismos exibidos, defina novamente a precisão no mesmo fluxo.

Arredonde valores com antes de formatá-los

As funções std::floor, std::ceil e std::round, de <cmath>, calculam valores diferentes. std::floor(x) retorna o maior valor inteiro que não excede x, enquanto std::ceil(x) retorna o menor valor inteiro que não é menor que x. std::round(x) arredonda para o valor inteiro mais próximo; nos casos exatamente a meio caminho, arredonda para longe de zero. Essas funções não configuram a precisão da saída do fluxo.

std::lround(x) segue a mesma regra de arredondamento para o inteiro mais próximo, afastando-se de zero nos casos a meio caminho, e retorna um long. Use-a quando precisar de um resultado inteiro e o valor arredondado puder ser representado como long; std::round retorna um valor de ponto flutuante. Depois de calcular um valor arredondado, use os manipuladores de fluxo separadamente se também precisar controlar sua formatação na saída.

Evite erros comuns de precisão e arredondamento

Não presuma que std::setprecision(2) significa duas casas após o separador decimal: sem std::fixed, significa dois algarismos significativos. Por outro lado, std::fixed pode fazer um valor muito pequeno aparecer como 0.000 quando são usadas três casas decimais. A exibição foi arredondada para o formato selecionado, mas a variável original não se tornou zero.

Mantenha distintas as duas operações: os manipuladores controlam a apresentação, enquanto as funções de <cmath> calculam um novo valor. Se precisar tanto de um valor arredondado quanto de um número específico de casas decimais na exibição, aplique a função de arredondamento ao valor e, em seguida, formate o fluxo com std::fixed e std::setprecision.