#include "stdafx.h"
#include "stdev.h"
#include <map>
int _tmain(int argc, _TCHAR* argv[])
{
std::map<int, int> map_test;
map_test[0] = 100;
map_test[5] = 80;
map_test[2] = 10;
map_test[8] = 99;
map_test[4] = 102;
StdevInfo stdev_info;
stdev_info.init();
stdev_info.caculate_stdev_info(map_test.begin(), map_test.end(),
[](const std::pair<int, int> &pr) { return pr.second; });
//if (value > stdev_info._ave * 2) { ... }
return 0;
}
stdev.h
#ifndef _UTILITY_STDEV_H_
#define _UTILITY_STDEV_H_
/*
* 计算统计特征的函数
*/
#define _USE_MATH_DEFINES
#include <algorithm>
#include <math.h>
#include <float.h>
#include <crtdbg.h>
#include <vector>
struct StdevInfo
{
static const double MAX_VAR;
double _ave;
//double _var;
double _sam_stdev;
double _all_stdev;
double _sum;
double _sum_2;
int _count;
double _min_v;
double _max_v;
StdevInfo()
: _ave(0.0)
//, _var(MAX_VAR)
, _sam_stdev(sqrt(MAX_VAR))
, _all_stdev(0.0)
, _sum(0.0)
, _sum_2(0.0)
, _count(0)
, _min_v(0.0)
, _max_v(0.0)
{}
void init(void)
{
_ave = 0.0;
//_var = 0.0;
//_stdev = 0.0;
_sum = 0.0;
_sum_2 = 0.0;
_count = 0;
_min_v = 0.0;
_max_v = 0.0;
//_var = MAX_VAR;
_all_stdev = 0.0;
_sam_stdev = sqrt(MAX_VAR);
}
template<typename I, typename F, typename FILTER>
inline void caculate_stdev_info(I b, I e, const F &f, const FILTER &filter);
template<typename I, typename F>
inline void caculate_stdev_info(I b, I e, const F &f);
inline void add_value(double v);
inline void del_value(double v);
inline void change_value(double v1, double v2)
{
del_value(v1);
add_value(v2);
}
inline double sam_var(void) const { return _sam_stdev * _sam_stdev; }
inline double all_var(void) const { return _all_stdev * _all_stdev; }
};
class StdevCaculator {
public:
static void add_value(StdevInfo &info, double v);
static void del_value(StdevInfo &info, double v);
template<typename I, typename F, typename FILTER>
static void caculate_stdev_info(StdevInfo &info, I b, I e, const F &f, const FILTER &filter)
{
info.init();
int count = 0;
double sum_v = 0.0, sum_2_v = 0.0;
double max_v = -10000000000.0;
double min_v = 10000000000.0;
double v;
for (auto i = b; i != e; ++i) {
if (!filter(*i))
continue;
++count;
v = f(*i);
if (v > max_v)
max_v = v;
if (v < min_v)
min_v = v;
sum_v += v;
sum_2_v += v * v;
}
if (count < 1)
return;
double ave_v = sum_v / count;
info._sum = sum_v;
info._sum_2 = sum_2_v;
info._count = count;
info._ave = ave_v;
info._max_v = max_v;
info._min_v = min_v;
if (count < 2) {
//info._var = StdevInfo::MAX_VAR;
//info._all_stdev = 0.0;
//info._sam_stdev = sqrt(StdevInfo::MAX_VAR);
return;
}
double sum_diff2 = 0.0;
for (auto i = b; i != e; ++i) {
if (!filter(*i))
continue;
v = f(*i);
double diff_v = v - ave_v;
sum_diff2 += diff_v * diff_v;
}
info._sam_stdev = sqrt(sum_diff2 / (count - 1)); // 样本标准差要减1
info._all_stdev = sqrt(sum_diff2 / count);
}
template<typename I, typename F>
static void caculate_stdev_info(StdevInfo &info, I b, I e, const F &f)
{
info.init();
int count = 0;
double sum_v = 0.0, sum_2_v = 0.0;
double max_v = -10000000000.0;
double min_v = 10000000000.0;
double v;
for (auto i = b; i != e; ++i) {
++count;
v = f(*i);
if (v > max_v)
max_v = v;
if (v < min_v)
min_v = v;
sum_v += v;
sum_2_v += v * v;
}
if (count < 1)
return;
double ave_v = sum_v / count;
info._sum = sum_v;
info._sum_2 = sum_2_v;
info._count = count;
info._ave = ave_v;
info._max_v = max_v;
info._min_v = min_v;
if (count < 2) {
//info._var = StdevInfo::MAX_VAR;
//info._all_stdev = 0.0;
//info._sam_stdev = sqrt(StdevInfo::MAX_VAR);
return;
}
double sum_diff2 = 0.0;
for (auto i = b; i != e; ++i) {
v = f(*i);
double diff_v = v - ave_v;
sum_diff2 += diff_v * diff_v;
}
info._sam_stdev = sqrt(sum_diff2 / (count - 1)); // 样本标准差要减1
info._all_stdev = sqrt(sum_diff2 / count);
}
};
template<typename I, typename F, typename FILTER>
inline void StdevInfo::caculate_stdev_info(I b, I e, const F &f, const FILTER &filter)
{
StdevCaculator::caculate_stdev_info(*this, b, e, f, filter);
}
template<typename I, typename F>
inline void StdevInfo::caculate_stdev_info(I b, I e, const F &f)
{
StdevCaculator::caculate_stdev_info(*this, b, e, f);
}
inline void StdevInfo::add_value(double v)
{
StdevCaculator::add_value(*this, v);
}
inline void StdevInfo::del_value(double v)
{
StdevCaculator::del_value(*this, v);
}
#endif // !_UTILITY_STDEV_H_
stdev.cpp
#include "stdev.h"
const double StdevInfo::MAX_VAR = DBL_MAX / 100.0;
void StdevCaculator::add_value(StdevInfo &info, double v)
{
double sum = info._sum;
double sum_2 = info._sum_2;
info._sum += v;
info._sum_2 += v * v;
++info._count;
if (info._count > 1) {
if (v > info._max_v)
info._max_v = v;
if (v < info._min_v)
info._min_v = v;
} else {
info._max_v = info._min_v = v;
}
info._ave = info._sum / info._count;
if (info._count < 2) {
//info._var = StdevInfo::MAX_VAR;
info._all_stdev = 0.0;
info._sam_stdev = sqrt(StdevInfo::MAX_VAR);
return;
}
double var_sum = sum_2 + v * v + info._count * info._ave * info._ave - 2 * info._ave * (sum + v);
//_ASSERTE(var_sum >= -DBL_EPSILON * 100);
if (var_sum < 0.0)
var_sum = 0.0;
//info._var = var_sum / (info._count - 1);
info._sam_stdev = sqrt(var_sum / (info._count - 1));
info._all_stdev = sqrt(var_sum / (info._count));
_ASSERTE(_finite(info._sam_stdev));
_ASSERTE(_finite(info._all_stdev));
_ASSERTE(_finite(info._ave));
}
void StdevCaculator::del_value(StdevInfo &info, double v)
{
double sum = info._sum;
double sum_2 = info._sum_2;
info._sum -= v;
info._sum_2 -= v * v;
--info._count;
if (info._count > 1) {
/* NOTE: 删除时, 最大最小值无法还原 */
/*
if (v > info._max_v)
info._max_v = v;
if (v < info._min_v)
info._min_v = v;
*/
} else {
info._max_v = info._min_v = v;
}
if (info._count > 0)
info._ave = info._sum / info._count;
else
info._ave = 0.0;
if (info._count < 2) {
info._all_stdev = 0.0;
info._sam_stdev = sqrt(StdevInfo::MAX_VAR);
return;
}
double var_sum = sum_2 - v * v + info._count * info._ave * info._ave - 2 * info._ave * (sum - v);
info._sam_stdev = sqrt(var_sum / (info._count - 1));
info._all_stdev = sqrt(var_sum / (info._count));
}