继续为前面提到的数学库编写的代码。链接。为模式和标准偏差编写模板化函数。(对前几次审查的一些修改尚未作出。请看同样的内容。
注意:我收到了一些关于包含标题的评论。这是visual studio项目的一部分,一些标头被移到pch.h。
#include <vector>
#include <numeric>
#include <string>
#include <functional>
#include <unordered_map>
namespace Statistics
{
template <typename T>
T average(const std::vector<T> &distributionVector)
{
if (distributionVector.size() == 0)
{
throw std::invalid_argument("Statistics::average - The distribution provided is empty");
}
return std::accumulate(distributionVector.begin(), distributionVector.end(), T())
/ (distributionVector.size());
}
template <typename T>
T variance(const std::vector<T> &distributionVector)
{
if (distributionVector.size() == 0)
{
throw std::invalid_argument("Statistics::expectation - The distribution provided is empty");
}
T meanOfSquare = average(distributionVector);
return (std::accumulate(distributionVector.begin(), distributionVector.end(), T(), [=](T a,T b) { return a + (b - meanOfSquare )*(b - meanOfSquare); })/distributionVector.size());
}
template <typename T>
T standardDeviation(const std::vector<T>& distributionVector)
{
return pow(variance(distributionVector), 0.5);
}
template<typename T>
T mode(const std::vector<T>& distributionVector)
{
std::unordered_map<T, int> frequencyMap;
std::for_each(distributionVector.begin(), distributionVector.end(), [&](T a) { frequencyMap[a]++; });
int maxCount = 0;
std::for_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { maxCount = std::max(maxCount, a.second); });
T answer;
std::for_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { if (maxCount == a.second) { answer = a.first; } });
return answer;
}
}#include "pch.h"
#include <vector>
#include "../MathLibrary/Combinatorics.h"
#include "../MathLibrary/Statistics.h"
void compareDoubles(double a, double b)
{
const double THRESHOLD = 0.01;
ASSERT_TRUE(abs(a - b) < THRESHOLD);
}
TEST(Combinatorial_Factorial, small_ints)
{
EXPECT_EQ(Combinatorics::factorial(0), 1);
EXPECT_EQ(Combinatorics::factorial(1), 1);
EXPECT_EQ(Combinatorics::factorial(5), 120);
EXPECT_EQ(Combinatorics::factorial(20), 2432902008176640000);
}
TEST(Combinatorial_Factorial, too_big)
{
EXPECT_THROW(Combinatorics::factorial(500), std::invalid_argument);
}
TEST(Combinatorial_Combinations, small_ints)
{
EXPECT_EQ(Combinatorics::combinations(5,5), 1);
EXPECT_EQ(Combinatorics::combinations(5, 0), 1);
EXPECT_EQ(Combinatorics::combinations(5, 1), 5);
EXPECT_EQ(Combinatorics::combinations(20,10),184756);
EXPECT_EQ(Combinatorics::combinations(40, 35),658008);
}
TEST(Combinatorial_Combinations, negative_n)
{
EXPECT_THROW(Combinatorics::combinations(-5, 5), std::invalid_argument);
}
TEST(Combinatorial_Combinations, r_greater_than_n)
{
EXPECT_THROW(Combinatorics::combinations(4, 5), std::invalid_argument);
}
TEST(Combinatorial_Combinations, overflow)
{
EXPECT_THROW(Combinatorics::combinations(100, 50), std::invalid_argument);
}
TEST(Combinatorial_Permutations, small_ints)
{
EXPECT_EQ(Combinatorics::permutations(5, 5), 120);
EXPECT_EQ(Combinatorics::permutations(5, 0), 1);
EXPECT_EQ(Combinatorics::permutations(5, 2), 20);
EXPECT_EQ(Combinatorics::permutations(10, 2), 90);
EXPECT_EQ(Combinatorics::permutations(40, 3), 59280);
EXPECT_EQ(Combinatorics::permutations(40, 7), 93963542400);
EXPECT_EQ(Combinatorics::permutations(50, 4), 5527200);
}
TEST(Combinatorial_Permutations, r_negative)
{
EXPECT_THROW(Combinatorics::permutations(5, -5), std::invalid_argument);
}
TEST(Combinatorial_Permutations, n_negative)
{
EXPECT_THROW(Combinatorics::permutations(-5, 5), std::invalid_argument);
}
TEST(Combinatorial_Permutations,r_greater)
{
EXPECT_THROW(Combinatorics::permutations(5, 6), std::invalid_argument);
}
TEST(Combinatorial_Permutations,overflow)
{
EXPECT_THROW(Combinatorics::permutations(50,46), std::invalid_argument);
}
TEST(Statistics_mean, small_distributions)
{
std::vector<int> testVector = { -2,-1,0,1,2 };
EXPECT_EQ(Statistics::average(testVector), 0);
std::vector<double> testVectorDouble = {5,5,6,6};
compareDoubles(Statistics::average(testVectorDouble), 5.5);
}
TEST(Statistics_mean, empty_distribution)
{
std::vector<int> testVector;
EXPECT_THROW(Statistics::average(testVector), std::invalid_argument);
}
TEST(Statistics_variance, small_distribution)
{
std::vector<double> testVector = { 0,0 };
compareDoubles(Statistics::variance(testVector), 0);
std::vector<double> testVector2 = {1,2,3,4};
compareDoubles(Statistics::variance(testVector2), 1.25);
std::vector<double> testVectorRandom = { 1,2,3,4,6,8,9,34,45,78,89 };
compareDoubles(Statistics::variance(testVectorRandom), 938.2314);
}
TEST(Statistics_standarddev, small_distribution)
{
std::vector<double> testVector = { 0,0 };
compareDoubles(Statistics::standardDeviation(testVector), 0);
std::vector<double> testVector2 = { 1,2,3,4 };
compareDoubles(Statistics::standardDeviation(testVector2), 1.11803);
std::vector<double> testVectorRandom = { 1,2,3,4,6,8,9,34,45,78,89 };
compareDoubles(Statistics::standardDeviation(testVectorRandom), 30.6305);
}
TEST(Statistics_mode, small_distribution)
{
std::vector<int> testVector = { 32,32, 45, 12,32};
EXPECT_EQ(Statistics::mode(testVector), 32);
std::vector<int> testVector1 = { 32,32,32 };
EXPECT_EQ(Statistics::mode(testVector1), 32);
std::vector<int> testVector2 = {0};
EXPECT_EQ(Statistics::mode(testVector2), 0);
}发布于 2021-08-10 14:06:56
std::for_each(distributionVector.begin(), distributionVector.end(), [&](T a) { frequencyMap[a]++; });使用前缀++而不是后缀。如果T不是基本整数类型,则后缀的一般实现是复制参数并调用前缀version,然后返回参数。养成使用++x而不是x++的习惯。
int maxCount = 0;
std::for_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { maxCount = std::max(maxCount, a.second); });
T answer;
std::for_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { if (maxCount == a.second) { answer = a.first; } });你做了两次传球为什么?第一个找到最大计数,第二个找到最后一个具有该计数的元素。您可以简单地记住第一个循环中的最大值和相关的值。第二个循环的另一个缺陷不是在找到匹配时立即返回,而是始终在整个集合中运行。
您只需使用传入lambda的max_element来比较.second。它返回整个对,其中您返回.first。
更普遍地说,内置的基于范围的for循环比(原始的、基于开始/结束迭代器的) for_each算法更简单、更灵活。
发布于 2021-08-10 10:23:58
throw std::invalid\_argument("Statistics::average - The distribution provided is empty");
噢-我们不包括<stdexcept>。
return pow(variance(distributionVector), 0.5);
pow()是什么?如果我们指的是std::pow(),我们需要包括<cmath>。std::sqrt()会比std::pow( , 0.5)更清晰、更地道。
现在我们有了代码编译,让我们来看看里面。
模板 T average(const std::vector &distributionVector)
我认为之前的一篇评论建议,T可能是一个糟糕的返回类型选择。例如,我们可能需要一个double来表示int向量的平均值。对许多用户来说,只接受向量而不是接受任何范围太不灵活了。
int maxCount = 0; std::for\_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { maxCount = std::max(maxCount, a.second); }); T answer; std::for\_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { if (maxCount == a.second) { answer = a.first; } });
在这里,我们要遍历向量两次。我们应该只使用std::max_element()遍历列表一次,然后从该元素返回值。
空列表的模式是什么?这个函数在列表为空时不会抛出,这是令人惊讶和不一致的,因为其他函数会抛出。
https://codereview.stackexchange.com/questions/265900
复制相似问题