С ++ Дисперсия и стандартное отклонение - PullRequest
0 голосов
/ 15 апреля 2020

Я создал программу, которая предлагает пользователю ввести набор данных. Программа сохраняет и сортирует данные, затем вычисляет дисперсию и стандартное отклонение массива. Тем не менее, я не получаю правильные вычисления для дисперсии и стандартного отклонения (ответ слегка отклонен). Кто-нибудь знает, в чем проблема?

#include <iostream>
#include <iomanip>
#include <array>

using namespace std;

//function declarations
void GetData(double vals[], int& valCount);
void Sort(double vals[], int& valCount);
void printSort(double vals[], int& valCount);
double Variance(double vals[], int valCount);
double StandardDev(double vals[], int valCount);
double SqRoot(double value); //use for StandardDev function

//function definitions
int main ()
{
    double vals = 0;

    int valCount = 0;        //number of values to be processed

    //ask user how many values
    cout << "Enter the number of values (0 - 100) to be processed: ";
    cin >> valCount;

    //process and store input values
    GetData(&vals, valCount);

    //sort values
    Sort(&vals, valCount);

    //print sort
    cout << "\nValues in Sorted Order: " << endl;
    printSort(&vals, valCount);

    //print variance
    cout << "\nThe variance for the input value list is: " << Variance(&vals, valCount);

    //print standard deviation
    cout << "\nThe standard deviation for the input list is: " <<StandardDev(&vals, valCount)<< endl;

    return 0;
}

//prompt user to get data
void GetData(double vals[], int& valCount)
{
    for(int i = 0; i < valCount; i++)
    {
        cout << "Enter a value: ";
        cin >> vals[i];
    }
}

//bubble sort values
void Sort(double vals[], int& valCount)
{
    for (int i=(valCount-1); i>0; i--)
        for (int j=0; j<i; j++)
    if (vals[j] > vals[j+1])
           swap (vals[j], vals[j+1]);
}

//print sorted values
void printSort(double vals[], int& valCount)
{
    for (int i=0; i < valCount; i++)
        cout << vals[i] << "\n";
}

//compute variance
double Variance(double vals[], int valCount)
{
    //mean
    int sum = 0;
    double mean = 0;
    for (int i = 0; i < valCount; i++)
        sum += vals[i];
        mean = sum / valCount;

    //variance
    double squaredDifference = 0;
    for (int i = 0; i < valCount; i++)
        squaredDifference += (vals[i] - mean) * (vals[i] - mean);
    return squaredDifference / valCount;
}

//compute standard deviation
double StandardDev(double vals[], int valCount)
{
    double stDev;
    stDev = SqRoot(Variance(vals, valCount));
    return stDev;
}

//compute square root
double SqRoot(double value)
{
    double n = 0.00001;
    double s = value;
    while ((s - value / s) > n)
    {
        s = (s + value / s) / 2;
    }

    return s;
}

Ответы [ 2 ]

1 голос
/ 15 апреля 2020

В коде, который вызывал ваши ошибки, было что-то не так. Несоответствия типов, но, что более важно, вы никогда не создавали массив для хранения значений. Вы рассматривали простой дубль как массив, и вам повезло, что ваша программа никогда не зависала на вас.

Ниже приведена рабочая версия вашего кода, проверенная с помощью набора данных и Excel. Я оставил там как можно больше вашего кода, просто закомментировал, когда это уместно. Если я закомментировал это, я не вносил в него никаких изменений, поэтому все еще могут быть ошибки.

В этом случае массив векторов. Вы не знаете размер заранее (во время компиляции), а векторы проще, чем динамические массивы c. У вас также никогда не было массива. Векторы также знают, насколько они велики, поэтому вам не нужно передавать размер.

Несоответствия типов. Ваши функции продолжают ожидать массив значений типа double, но ваша сумма была int, среди многих других несоответствий. Вы также передавали простой дубль, как будто это был массив, записывая в память, что вы не могли так измениться.

Лучшие практики, которые нужно начинать сейчас. Стоп с using namespace std;. Просто уточните ваши имена, когда это необходимо, или укажите более точно c с такими строками, как using std::cout; в верхней части функции. Ваше имя было повсюду. Выберите схему именования и придерживайтесь ее. Имена, начинающиеся с заглавной буквы, обычно зарезервированы для классов или типов.

#include <iomanip>
#include <iostream>
// #include <array>  // You never actually declared a std::array
#include <vector>  // You don't know the size ahead of time, vectors are the
                   // right tool for that job.

// Use what's available
#include <algorithm>  // std::sort()
#include <cmath>      // std::sqrt()
#include <numeric>    // std::accumulate()

// function declarations
// Commented out redundant functions, and changed arguments to match
void get_data(std::vector<double>& vals);
// void Sort(double vals[], int& valCount);
void print(const std::vector<double>& vals);
double variance(const std::vector<double>& vals);
double standard_dev(const std::vector<double>& vals);
// double SqRoot(double value); //use for StandardDev function

// function definitions
int main() {
  int valCount = 0;  // number of values to be processed

  // ask user how many values
  std::cout << "Enter the number of values (0 - 100) to be processed: ";
  std::cin >> valCount;
  std::vector<double> vals(valCount, 0);
  // Was just a double, but you pass it around like it's an array. That's
  // really bad. Either allocate the array on the heap, or use a vector.
  // Moved to after getting the count so I could declare the vector with
  // that size up front instead of reserving later; personal preference.

  // process and store input values
  get_data(vals);

  // sort values
  // Sort(&vals, valCount);
  std::sort(vals.begin(), vals.end(), std::less<double>());
  // The third argument can be omitted as it's the default behavior, but
  // I prefer being explicit. If compiling with C++17, the <double> can
  // also be omitted due to a feature called CTAD

  // print sort
  std::cout << "\nValues in Sorted Order: " << '\n';
  print(vals);

  // print variance
  std::cout << "\nThe variance for the input value list is: " << variance(vals);

  // print standard deviation
  std::cout << "\nThe standard deviation for the input list is: "
            << standard_dev(vals) << '\n';

  return 0;
}

// prompt user to get data
void get_data(std::vector<double>& vals) {
  for (unsigned int i = 0; i < vals.size(); i++) {
    std::cout << "Enter a value: ";
    std::cin >> vals[i];
  }
}

// //bubble sort values
// void Sort(double vals[], int& valCount)
// {
//     for (int i=(valCount-1); i>0; i--)
//         for (int j=0; j<i; j++)
//     if (vals[j] > vals[j+1])
//            swap (vals[j], vals[j+1]);
// }

// print sorted values
void print(const std::vector<double>& vals) {
  for (auto i : vals) {
    std::cout << i << ' ';
  }
  std::cout << '\n';
}

// compute variance
double variance(const std::vector<double>& vals) {
  // was int, but your now vector is of type double
  double sum = std::accumulate(vals.begin(), vals.end(), 0);
  double mean = sum / static_cast<double>(vals.size());

  // variance
  double squaredDifference = 0;
  for (unsigned int i = 0; i < vals.size(); i++)
    squaredDifference += std::pow(vals[i] - mean, 2);
  // Might be possible to get this with std::accumulate, but my first go didn't
  // work.

  return squaredDifference / static_cast<double>(vals.size());
}

// compute standard deviation
double standard_dev(const std::vector<double>& vals) {
  return std::sqrt(variance(vals));
}

// //compute square root
// double SqRoot(double value)
// {
//     double n = 0.00001;
//     double s = value;
//     while ((s - value / s) > n)
//     {
//         s = (s + value / s) / 2;
//     }

//     return s;
// }

РЕДАКТИРОВАТЬ : Я выяснил разницу с аккумулятором. Это требует знания лямбд (анонимные функции, функторы). Я скомпилировал в стандарт C ++ 14, который некоторое время был по умолчанию для основных компиляторов.

double variance(const std::vector<double>& vals) {
  auto meanOp = [valSize = vals.size()](double accumulator, double val) {
    return accumulator += (val / static_cast<double>(valSize));
  };
  double mean = std::accumulate(vals.begin(), vals.end(), 0.0, meanOp);

  auto varianceOp = [mean, valSize = vals.size()](double accumulator,
                                                  double val) {
    return accumulator +=
           (std::pow(val - mean, 2) / static_cast<double>(valSize));
  };

  return std::accumulate(vals.begin(), vals.end(), 0.0, varianceOp);
}
0 голосов
/ 15 апреля 2020

mean = sum / valCount; в Variance будет вычислено с использованием целочисленной математики, а затем преобразовано в двойное число. Сначала необходимо преобразовать в удвоение:

mean = double(sum) / valCount;

Ваша функция SqRoot вычисляет приблизительное значение. Вместо этого вы должны использовать std::sqrt, что будет быстрее и точнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...