#include #include #include #include #include #include #include #include #include #include // Alguns tipos especiais: // Representação do vetor de dados a analisar. using DataVector = std::vector; // Representação de uma caixa (bin) do histograma using HistogramBin = std::pair; // Representação de um histograma. using Histogram = std::vector; // Tipo para erro de acesso a arquivo de dados. struct DataFileError { // Razão do erro. std::string reason; }; // Tipo para erro por falta de dados. struct InsufficientData { // Quantos dados havia. DataVector::size_type how_many; }; // Funções auxiliares. // Lê dados de arquivo com nome filename e retorna em um vetor. DataVector read_file(std::string filename); // Calcula média e desvio padrão dos dados em data. // Retorna nessa ordem. std::tuple mean_stdev(DataVector data); // Calcula um histograma de num_bins caixas entre o mínimo e o máximo dos dados // em data. Histogram histogram(DataVector data, int num_bins); // Código para ler os dados de um arquivo e calcular algumas estatísticas: // - Média // - Desvio padrão amostral // - Um histogram entre o menor e o maior valores dos dados com um especificado // número de caixas (bins). // // Argumentos: // - nome do arquivo de dados // - número de caixas no histograma int main(int argc, char *argv[]) { // Verifica se os argumentos necessários foram fornecidos. if (argc != 3) { std::cerr << "Usage: " << argv[0] << " \n"; return 1; } // Le os argumentos de linha de comando e coloca em variáveis adequadas. // Nome do arquivo std::string const filename{argv[1]}; // Número da caixas. int const num_bins = std::stod(argv[2]); // Verifica se o número de caixas fornecidas foi adequado. if (num_bins < 1) { std::cerr << "You should specify at least 1 bin, and not " << num_bins << std::endl; return 1; } try { // Lê os dados. auto const data = read_file(filename); // Calcula média e desvio padrão. auto const [m, st] = mean_stdev(data); // Escreve na tela. std::cout << m << " " << st << std::endl; // Calcula o histograma. auto const hist = histogram(data, num_bins); // Escreve o histograma na tela: centro da caixa seguido de número de // valores. for (auto const &bindata : hist) { std::cout << bindata.first << " " << bindata.second << std::endl; } } catch (DataFileError e) { std::cerr << "Error reading data file: " << e.reason << std::endl; return 1; } catch (InsufficientData e) { std::cerr << "Insufficient data for statistics: Only " << e.how_many << " point(s)\n"; return 1; } return 0; } // Implementação das funções auxiliares. // Lê dados de arquivo com nome filename e retorna em um vetor. DataVector read_file(std::string filename) { // Abre arquivo para leitura. std::ifstream datafile(filename); // Verifica se conseguiu abrir. if (!datafile.is_open()) { throw DataFileError{"Could not open file"}; } // Cria vetor para guardar dados lidos. DataVector data; // Cria iteradores para leitura dos dados. // data_it é um iterador para o começo do arquivo. std::istream_iterator data_it(datafile); // end_it é um iterador que caracteriza o final de um arquivo. std::istream_iterator end_it; // Copia os dados do arquivo para o vetor data, usando push_back para inserir // novos valores. std::copy(data_it, end_it, std::back_inserter(data)); // Verifica se houve falha na tentativa de escrita, antes de terminar. if (datafile.fail() && !datafile.eof()) { throw DataFileError{"Read error"}; } return data; } // Função auxiliar para calcular o quadrado de um valor. inline double square(double x) { return x * x; } // Calcula média e desvio padrão dos dados em data. // Retorna nessa ordem. std::tuple mean_stdev(DataVector data) { // Verifica se o vetor possui dados suficientes para calcular desvio padrão. auto const N = data.size(); if (N < 2) { throw InsufficientData{N}; } // Calcula a média (soma todos os elementos e divide por N). auto const total = std::accumulate(begin(data), end(data), 0.0); auto const mean = total / N; // Calcula o desvio padrão. double d_sum{0.0}; for (auto x : data) { d_sum += square(x - mean); } auto stdev = std::sqrt(d_sum / (N - 1)); return {mean, stdev}; } // Calcula um histograma de num_bins caixas entre o mínimo e o máximo dos dados // em data. Histogram histogram(DataVector data, int num_bins) { // Cria um histograma com o número de bins desejado. Histogram h(num_bins); // Encontra o menor e o maior valor em data. auto const minmax_it = std::minmax_element(begin(data), end(data)); auto const min_value = *(minmax_it.first); auto const max_value = *(minmax_it.second); // Calcula o tamanho de uma caixa. auto delta = (max_value - min_value) / num_bins; // Incializa todas as caixas com o valor do centro da caixa e 0 valores no // contador. for (int i = 0; i < num_bins; ++i) { h[i].first = min_value + i * delta + delta / 2; h[i].second = 0; } // Percorre cada valor em data e verifica em qual caixa ele cai. for (DataVector::size_type j = 0; j < data.size(); ++j) { // Índice da caixa onde o valor cai. auto bin = static_cast(std::floor((data[j] - min_value) / delta)); // Se data[i] == max_value, contamos ele na última caixa. if (bin == num_bins) { bin = num_bins - 1; }; // Incrementa contador da caixa correspondente. h[bin].second++; } return h; }