如何使用向量查找均值和标准差

时间:2019-03-24 04:06:03

标签: c++ vector

这是作业:

  

编写两个计算平均值和标准偏差的函数。   您的函数应实现以下原型:

double mean(vector<double>x);
double sd(vector<double>x);
     

b。将这些功能放在名为“ statfun.cpp”的文件中。

     

c。将其功能定义放在名为“ statfun.h”的文件中。

     
      
  1. 在名为“ lab1.cpp”的文件中写入main()函数。

  2.   
  3. 提示用户输入10个浮点值并将其存储在向量v中。

  4.   
  5. 在一行上打印矢量v,每个元素之间用空格隔开。

  6.   
  7. 调用函数mean(v)和sd(v)...

  8.   

我知道如何为均值公式编码,但是我不确定如何使用向量为标准差公式编码。我甚至不知道如何处理涉及的不同文件。我完全知道我的代码是垃圾,但是我不确定很多事情,我不知道首先要解决什么。

编辑:更新了代码

//statfun.h
#include <iostream> 
#include <vector>
#ifndef STATFUN_H
#define STATFUN_H
using namespace std;

double mean(vector<double> v);

double sd(vector<double> v);

#endif

//statfun.cpp
#include <iostream>
#include <cmath>
#include <vector>
#include "statfun.h"
#ifndef STATFUN_CPP
#define STATFUN_CPP
using namespace std;

double mean(const vector<double> v) {

    double result;

    double sumVal = 0.0;            //Calculating sum of all values
for (int i = 0; i < v.size(); ++i) {
    sumVal = sumVal + v.at(i);
}

result = sumVal / v.size(); //Calculating mean

return result; 
}

double sd(const vector<double> v) {
    double total = 0;
    for (int i = 0; i < 10; ++i) {      //Calcuating standard deviation
        double mean_value = mean(v);
        int length = v.size()
        total = total + (val - mean_value)*(val - mean_value);
}

    return sqrt(total / length);
}

#endif 

//lab1.cpp
#include "statfun.cpp"
#include <iomanip>
using namespace std;

vector<double> v;

int main() {

    cout << "Enter 10 numbers: " << endl;

    float userInput = 0;
    for (int i = 0; i < 10; ++i) {
        cin >> userInput;
        v.push_back(userInput);
    }

    for (int i = 0; i < 10; ++i) {
        cout << v.at(i) << " ";
    }

    cout << endl;

cout.precision(3);
cout << mean(v) << " " << sd(v) << endl;

cout.precision(5);
cout << scientific << mean(v) << " " << sd(v) << endl;

    return 0;
}

2 个答案:

答案 0 :(得分:0)

我相信您的第一个问题是了解统计资料分配的文件结构。首先解决这个问题。 Understanding headers. More on headers and function calls from other files.

.cpp文件将包含逻辑实现,.h文件是应声明对象和函数定义的标头。当您将文件包含在代码的顶部时,通常认为这是该文件中的所有代码都位于当前文件的上方。

示例:

statfun.h

double mean(vector<double> v);
// other **declaration** stuff....

lab1.cpp位于文件顶部

#include "statfun.h" // equivalent to copy/pasting 'double mean(vector<double> v); and other declarations' into your lab1.cpp
// This is to help with cleanliness of your file structure. 
// You'll thank yourself when projects become bigger.

注:lab1.cpp包含statfun.cpp,后者包含statfun.h;隐含地,lab1.cpp包含statfun.h,这意味着您不必在lab1中包含statfun.h,尽管通常包含标头,而不包含cpp文件。您必须避免使用ifndef进行循环依赖。

b。 statfun.cpp应该是您对均值和标准差的所有逻辑进行编码的地方。 例如:

statfun.cpp

double mean(vector<double> v) {
    // Your mean calculation logic here.
    return mean;
}

double sd(vector<double> x) {
    // Your standard deviation calculation logic here.
    return sd;
}

c。

  1. 因此,您具有lab1.cpp,它将被编译以生成一些可运行的二进制文件。作为程序的入口,它应该包含一个int main()函数。这个主要功能需要询问用户输入(搜索网络以获取标准输入)。
  2. 将标准输入存储为矢量(这仍在您的主要功能中)。
  3. 使用cout打印到标准输出。 'cout << name_of_variable_with_vector_input_from_user;' (仍在您的int main()中)
  4. 调用/使用您在statfun.cpp中编写的函数(特别是mean()和sd())。也许将它们的返回值存储在变量中以备后用。由于您需要在此处调用statfun函数,因此lab1.cpp条目文件必须包含statfun.h,以便在调用这些函数时知道要执行哪些代码。

现在,此文件结构逻辑已完成。计算伪代码中std偏差的一种简单方法:

statfun.madeuplanguage

type sd(vector<type> values) {
    type total = 0;
    type mean_value = mean(values);
    for val in values {
        total += (val - mean_value)^2;
    }
    total /= values.length;
    return sqrt(total);
}

请记住,我将按以下方式构造lab1.cpp。

lab1.cpp

int main() {
    vector<double> v;
    // take input and store in v.
    // std out - v

    double mean_val = mean(v);    
    double std_dev = sd(v);

    // std out - mean_val and std_dev
}

如果您对在C ++中实现上述伪代码有任何疑问,那就太好了!这是您的作业/班级,因此请注意搜索网络,以使用C ++进行极其具体的操作(例如,对向量进行迭代,平方,平方根等)。祝你好运。

答案 1 :(得分:0)

您犯了很多错误,代码也有很多改进。

让我陪我看看。

  1. 标题

由于一个文件可以多次包含头文件,因此,为了避免产生任何副作用,每个头文件都需要include guard

// statfun.h
#ifndef  __statfun_H__
# define __statfun_H__

# include <vector>

double mean(const std::vector<double>&);
double sd(const std::vector<double>&);

#endif

顺便说一句,function declaration可以缩写参数的名称。

  1. 参考

您犯的第二个错误是您没有使用reference。在c++中,默认情况下按值传递对象。

注意:这与R相似,但它没有语言级别的copy-on-write语义,但是用户定义的类可以实现此目的,在std命名空间中定义的类也可以实现实施。

因此,为了防止进行昂贵的复制,请制作reference

double mean(const std::vector<double>&);

在这里我使用了const left-value referenceconst &),因为mean不会修改传入的向量。

  1. 功能块。

c++中,函数定义如下:

return_value func_name(type1 arg1 /* , type2 arg2, ... */)
{
    // The function body goes here:
}

所以

// statfun.cpp
// c++11
#include "statfun.h"
#include <cmath>

double mean(const std::vector<double> &v)
{
    double sum = 0;

    for (auto &each: v)
        sum += each;

    return sum / v.size();
}

double sd(const std::vector<double> &v)
{
    double square_sum_of_difference = 0;
    double mean_var = mean(v);
    auto len = v.size();

    double tmp;
    for (auto &each: v) {
        tmp = each - mean_var;
        square_sum_of_difference += tmp * tmp;
    }

    return std::sqrt(square_sum_of_difference / (len - 1));
}
  1. 编译时变量类型推导

您可能已经在上面的代码中注意到了,我使用了auto len = v.size(),它是c++11 language feature -- auto

由于c++11c++可以推断出编译时函数调用的返回类型。因此,我们现在有了typename std::vector<double>::size_type len = v.size()。而不是像auto len = v.size()这样的变量。

  1. range-for循环

如果您已学习python,那么您必须了解range-for。由于c++11c++也可以这样做:

for (auto &each: v) {
    // Loop body
}

其中v可以是std::vectorc++中的任何其他容器。

  1. IO错误检查

最后但并非最不重要的一点是,您没有检查在IOstd::cout上执行的任何std::cin是否成功!

使用std::coutstd::cin,每次执行IO后,您都必须按std::cout.fail()来检查流状态,或使用以下代码:

std::cout.exceptions(std::ios_base::failbit | std::ios_base::badbit);
std::cin.exceptions(std::ios_base::failbit | std::ios_base::badbit);

在IO发生故障时抛出std::coutstd::cin

我个人不想处理此错误,而是让异常终止程序,因为您无能为力,无法清理并恢复程序的控制流。

下面是最后一段代码:

// lab1.cpp
// c++11
#include "statfun.h"
#include <iostream>

auto get_use_input() -> std::vector<double>
{
    std::vector<double> v;
    v.reserve(10);

    double userInput;
    for (int i = 0; i != 10; ++i) {
        std::cout << "Please enter the " << i + 1 << " number: ";
        std::cin >> userInput;
        std::cout << std::endl;

        v.push_back(userInput);
    }

    return v;
}

void print_vec(const std::vector<double> &v)
{
    std::cout << "Vector: ";

    for (auto &each: v)
        std::cout << each << " ";

    std::cout << std::endl;
}

int main() {
    // Configure std::cout and std::cin to throw if io fails.
    std::cout.exceptions(std::ios_base::failbit | std::ios_base::badbit);
    std::cin.exceptions(std::ios_base::failbit | std::ios_base::badbit);

    /*
     * With "-O3" or [c++17, copy elision](https://en.cppreference.com/w/cpp/language/copy_elision), 
     * the cost of initializing an object using the return value of anther function is nearly zero.
     */
    std::vector<double> v = get_use_input();

    print_vec(v);

    std::cout.precision(3);
    std::cout << "mean: " << mean(v) << " sd: " << sd(v) << std::endl;

    std::cout.precision(5);
    std::cout <<std::scientific << "mean: " << mean(v) << " sd: " << sd(v) << std::endl;

    return 0;
}

要构建此程序,您必须具有支持c++的{​​{1}}编译器并将c++11传递给编译器。

PS:您也可以使用-std=c++11-std=c++14

一个简单的-std=c++17来构建程序:

Makefile