这是作业:
编写两个计算平均值和标准偏差的函数。 您的函数应实现以下原型:
double mean(vector<double>x); double sd(vector<double>x);
b。将这些功能放在名为“ statfun.cpp”的文件中。
c。将其功能定义放在名为“ statfun.h”的文件中。
在名为“ lab1.cpp”的文件中写入main()函数。
提示用户输入10个浮点值并将其存储在向量v中。
在一行上打印矢量v,每个元素之间用空格隔开。
调用函数mean(v)和sd(v)...
我知道如何为均值公式编码,但是我不确定如何使用向量为标准差公式编码。我甚至不知道如何处理涉及的不同文件。我完全知道我的代码是垃圾,但是我不确定很多事情,我不知道首先要解决什么。
编辑:更新了代码
//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;
}
答案 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。
现在,此文件结构逻辑已完成。计算伪代码中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)
您犯了很多错误,代码也有很多改进。
让我陪我看看。
由于一个文件可以多次包含头文件,因此,为了避免产生任何副作用,每个头文件都需要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可以缩写参数的名称。
您犯的第二个错误是您没有使用reference。在c++
中,默认情况下按值传递对象。
注意:这与R
相似,但它没有语言级别的copy-on-write
语义,但是用户定义的类可以实现此目的,在std
命名空间中定义的类也可以实现实施。
因此,为了防止进行昂贵的复制,请制作reference。
double mean(const std::vector<double>&);
在这里我使用了const left-value reference
(const &
),因为mean
不会修改传入的向量。
在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));
}
您可能已经在上面的代码中注意到了,我使用了auto len = v.size()
,它是c++11 language feature -- auto。
由于c++11
,c++
可以推断出编译时函数调用的返回类型。因此,我们现在有了typename std::vector<double>::size_type len = v.size()
。而不是像auto len = v.size()
这样的变量。
如果您已学习python
,那么您必须了解range-for
。由于c++11
,c++
也可以这样做:
for (auto &each: v) {
// Loop body
}
其中v
可以是std::vector
或c++
中的任何其他容器。
最后但并非最不重要的一点是,您没有检查在IO
或std::cout
上执行的任何std::cin
是否成功!
使用std::cout
或std::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::cout
和std::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