Skip to content

Instantly share code, notes, and snippets.

@royratcliffe
Last active September 6, 2024 21:22
Show Gist options
  • Save royratcliffe/670884e9d763f6ead09a50fb5121cd09 to your computer and use it in GitHub Desktop.
Save royratcliffe/670884e9d763f6ead09a50fb5121cd09 to your computer and use it in GitHub Desktop.
C++
#include <cassert>
/*!
* \brief True if the first string ends with the second string.
* \param ends String with some required ending for which to test.
* \param with Ending to test the first string against.
*/
bool ends_with(const std::string &ends, const std::string &with) {
return ends.length() >= with.length() &&
ends.compare(ends.length() - with.length(), with.length(), with) == 0;
}
int ends_with_test(int argc, char **argv) {
assert(ends_with("abc", "c"));
assert(ends_with("abc", ""));
assert(!ends_with("abc", "z"));
assert(ends_with("a.bmp", ".bmp"));
return EXIT_SUCCESS;
}
//** $Id: SAC.hpp,v 1.2 2000/11/01 07:57:06 royr Exp $
//
//** Name
//
// sac.h -- statistical accumulator
//
//** Description
//
// Objects of the StatisticalAccumulator<T> class emulate a
// scientific calculator in statistical mode. You can use it to
// compute the following statistics:
//
// arithmetic mean (average)
// standard deviation, sample-based
// standard deviation, population-based
// minimum
// maximum
//
// Use the += operator to add data to the accumulator. This is
// equivalent to the M+ button on a calculator. The statistics are
// updated to reflect the new data value.
//
// All the accumulator's behaviors involve floating-point
// operations if your template type is float or double. So these
// objects should not normally be used in interrupt handlers unless
// the floating-point unit permits re-entrancy. The statistics are
// only partially computed when the data are added to the
// accumulator. The mean and standard deviation statistics are
// calculated from the sum of the data and the sum of the data
// squared only when the caller invokes the member functions. The
// getAverage, getStDev and getStDevP operations are therefore
// relatively slow.
//
// The class provides the following interface:
//
// StatisticalAccumulator()
// StatisticalAccumulator& operator+=(T x)
// StatisticalAccumulator& operator-=(T x)
// void clear()
// unsigned int getCount() const
// T getAverage() const
// T getStDev() const
// T getStDevP() const
// T getVar() const
// T getMin() const
// T getMax() const
//
// The first four modify the state of an accumulator. The get*
// member functions access the statistical information.
//
// Accumulator objects do not throw exceptions. The quiet SAC_NaN
// constant is returned to indicate an error.
//
//** Example
//
// #include "sac.h"
// #include <iostream>
//
// . . .
//
// StatisticalAccumulator<double> sac;
// ((sac += 1) += 2) += 3;
// cout << "Average = " << sac.getAverage() << endl
// << "StDev = " << sac.getStDev() << endl
// << "StDevP = " << sac.getStDevP() << endl
// << "Min = " << sac.getMin() << endl
// << "Max = " << sac.getMax() << endl;
//
//**********************************************************************
#pragma once
#ifndef __cplusplus
////////////////////////////////////////////////////////////////////////
template <typename T> class StatisticalAccumulator {
// interface
public:
StatisticalAccumulator();
StatisticalAccumulator &operator+=(T x);
StatisticalAccumulator &operator-=(T x);
void clear();
size_t getCount() const;
T getSum() const { return sigmaX; }
T getSum2() const { return sigmaX2; }
T getAverage() const;
T getStDev() const;
T getStDevP() const;
T getVar() const;
T getMin() const;
T getMax() const;
// implementation
private:
size_t n; // n
T sigmaX; // sum of x
T sigmaX2; // sum of x * x
T min; // minimum of x
T max; // maximum of x
};
////////////////////////////////////////////////////////////////////////
#include <limits> // numeric_limits
//**********************************************************************
// StatisticalAccumulator::StatisticalAccumulator
//**********************************************************************
//
//** Synopsis
//
// StatisticalAccumulator()
//
//** Description
//
// The StatisticalAccumulator constructor puts a new accumulator
// object into an initial state by calling clear.
//
//**********************************************************************
template <typename T> StatisticalAccumulator<T>::StatisticalAccumulator() {
clear();
}
//**********************************************************************
// StatisticalAccumulator::operator+=
//**********************************************************************
//
//** Synopsis
//
// StatisticalAccumulator& operator+=(T x)
//
//** Description
//
// The += operator adds a value to the accumulator.
//
//**********************************************************************
template <typename T>
StatisticalAccumulator<T> &StatisticalAccumulator<T>::operator+=(T x) {
// Update the counter, the sum of X, the sum of X squared, and the
// minimum and maximum values.
++n;
sigmaX += x;
sigmaX2 += x * x;
if (n == 1) {
min = x;
max = x;
} else {
if (x < min) {
min = x;
}
if (x > max) {
max = x;
}
}
return *this;
}
//**********************************************************************
// StatisticalAccumulator::operator-=
//**********************************************************************
//
//** Synopsis
//
// StatisticalAccumulator& operator-=(T x)
//
//** Description
//
// The -= operator subtracts a value from the accumulator. This
// assumes that the given value has previously been added to the
// accumulator with the += operator.
//
// This operator does not modify the minimum and maximum. The
// values returned by getMin and getMax are invalid when the -=
// operator is used.
//
//**********************************************************************
template <typename T>
StatisticalAccumulator<T> &StatisticalAccumulator<T>::operator-=(T x) {
if (n) {
--n;
sigmaX -= x;
sigmaX2 -= x * x;
// min and max are now invalid!
}
return *this;
}
//**********************************************************************
// StatisticalAccumulator::clear
//**********************************************************************
//
//** Synopsis
//
// void clear()
//
//** Description
//
// The clear operation resets the statistical accumulator. The
// number of data values is cleared to zero.
//
//**********************************************************************
template <typename T> void StatisticalAccumulator<T>::clear() {
n = 0;
sigmaX = 0;
sigmaX2 = 0;
min = numeric_limits<T>::quiet_NaN();
max = numeric_limits<T>::quiet_NaN();
}
//**********************************************************************
// StatisticalAccumulator::getCount
//**********************************************************************
//
//** Synopsis
//
// unsigned int getCount() const
//
//** Description
//
// The getCount member function tells how many numbers have been
// added so far.
//
//**********************************************************************
template <typename T> unsigned int StatisticalAccumulator<T>::getCount() const {
return n;
}
//**********************************************************************
// StatisticalAccumulator::getAverage
//**********************************************************************
//
//** Synopsis
//
// T getAverage() const
//
//** Description
//
// GetAverage returns the average, or arithmetic mean, of the data.
//
//** Return Value
//
// The return value is not-a-number if the accumulator is clear.
//
//**********************************************************************
template <typename T> T StatisticalAccumulator<T>::getAverage() const {
if (n == 0) {
return numeric_limits<T>::quiet_NaN();
}
return sigmaX / n;
}
//**********************************************************************
// StatisticalAccumulator::getStDev
//**********************************************************************
//
//** Synopsis
//
// T getStDev() const
//
//** Description
//
// The getStDev function calculates and returns the standard
// deviation of a sample.
//
// GetStDev assumes that the accumulated data are just a sample of
// the whole population.
//
//** Return Value
//
// Not-a-number is returned if the accumulator contains less than
// two values.
//
//**********************************************************************
template <typename T> T StatisticalAccumulator<T>::getStDev() const {
if (n < 2) {
return numeric_limits<T>::quiet_NaN();
}
return sqrt((n * sigmaX2 - sigmaX * sigmaX) / (n * (n - 1)));
}
//**********************************************************************
// StatisticalAccumulator::getStDevP
//**********************************************************************
//
//** Synopsis
//
// T getStDevP() const
//
//** Description
//
// The getStDevP function calculates the standard deviation of an
// entire population.
//
// GetStDevP assumes that the accumulated data are the entire
// population, not just a sample.
//
//** Return Value
//
// Not-a-number is returned if the accumulator is empty.
//
//**********************************************************************
template <typename T> T StatisticalAccumulator<T>::getStDevP() const {
if (n < 1) {
return numeric_limits<T>::quiet_NaN();
}
return sqrt((n * sigmaX2 - sigmaX * sigmaX) / (n * n));
}
//**********************************************************************
// StatisticalAccumulator::getVar
//**********************************************************************
//
//** Synopsis
//
// T getVar() const
//
//** Description
//
// The getVar function calculates the statistical variance, or
// standard deviation squared.
//
//** Return Value
//
// Not-a-number is returned if the accumulator is empty.
//
//**********************************************************************
template <typename T> T StatisticalAccumulator<T>::getVar() const {
if (n < 1) {
return numeric_limits<T>::quiet_NaN();
}
return (n * sigmaX2 - sigmaX * sigmaX) / (n * n);
}
//**********************************************************************
// StatisticalAccumulator::getMin
//**********************************************************************
//
//** Synopsis
//
// T getMin() const
//
//** Description
//
// The getMin member function returns the value of the smallest
// number that has been added to the accumulator.
//
//**********************************************************************
template <typename T> T StatisticalAccumulator<T>::getMin() const {
if (n == 0) {
return numeric_limits<T>::quiet_NaN();
}
return min;
}
//**********************************************************************
// StatisticalAccumulator::getMax
//**********************************************************************
//
//** Synopsis
//
// T getMax() const
//
//** Description
//
// The getMax member function returns the value of the largest
// number that has been added to the accumulator.
//
//**********************************************************************
template <typename T> T StatisticalAccumulator<T>::getMax() const {
if (n == 0) {
return numeric_limits<T>::quiet_NaN();
}
return max;
}
#endif // __cplusplus
#include <limits.h>
#include <math.h>
#ifndef SAC_SCALAR_TYPE
#define SAC_SCALAR_TYPE double
#endif
#ifndef SAC_SIZE_TYPE
#define SAC_SIZE_TYPE size_t
#endif
#ifndef SAC_NAN
#define SAC_NAN NAN
#endif
#ifndef SAC_SQRT
#define SAC_SQRT sqrt
#endif
struct statistical_accumulator {
SAC_SIZE_TYPE n; // n
SAC_SCALAR_TYPE sigmaX; // sum of x
SAC_SCALAR_TYPE sigmaX2; // sum of x * x
SAC_SCALAR_TYPE min; // minimum of x
SAC_SCALAR_TYPE max; // maximum of x
};
static inline struct statistical_accumulator *
sac_add(struct statistical_accumulator *sac, SAC_SCALAR_TYPE x) {
// Update the counter, the sum of X, the sum of X squared, and the
// minimum and maximum values.
sac->sigmaX += x;
sac->sigmaX2 += x * x;
if (++sac->n == 1) {
sac->min = x;
sac->max = x;
} else {
if (x < sac->min)
sac->min = x;
if (x > sac->max)
sac->max = x;
}
return sac;
}
static inline struct statistical_accumulator *
sac_clear(struct statistical_accumulator *sac) {
sac->n = 0;
sac->sigmaX = 0;
sac->sigmaX2 = 0;
sac->min = SAC_NAN;
sac->max = SAC_NAN;
return sac;
}
static inline SAC_SIZE_TYPE
sac_count(const struct statistical_accumulator *sac) {
return sac->n;
}
static inline SAC_SCALAR_TYPE
sac_average(const struct statistical_accumulator *sac) {
const SAC_SIZE_TYPE n = sac->n;
if (n == 0)
return SAC_NAN;
return sac->sigmaX / n;
}
static inline SAC_SCALAR_TYPE
sac_st_dev(const struct statistical_accumulator *sac) {
const SAC_SIZE_TYPE n = sac->n;
if (n < 2)
return SAC_NAN;
const SAC_SCALAR_TYPE sigmaX = sac->sigmaX;
return SAC_SQRT((sac->n * sac->sigmaX2 - sigmaX * sigmaX) / (n * (n - 1)));
}
static inline SAC_SCALAR_TYPE
sac_st_dev_p(const struct statistical_accumulator *sac) {
const SAC_SIZE_TYPE n = sac->n;
if (n < 1)
return SAC_NAN;
const SAC_SCALAR_TYPE sigmaX = sac->sigmaX;
return SAC_SQRT((n * sac->sigmaX2 - sigmaX * sigmaX) / (n * n));
}
static inline SAC_SCALAR_TYPE
sac_var(const struct statistical_accumulator *sac) {
const SAC_SIZE_TYPE n = sac->n;
if (n < 1)
return SAC_NAN;
const SAC_SCALAR_TYPE sigmaX = sac->sigmaX;
return (n * sac->sigmaX2 - sigmaX * sigmaX) / (n * n);
}
static inline SAC_SCALAR_TYPE
sac_min(const struct statistical_accumulator *sac) {
if (sac->n == 0)
return SAC_NAN;
return sac->min;
}
static inline SAC_SCALAR_TYPE
sac_max(const struct statistical_accumulator *sac) {
if (sac->n == 0)
return SAC_NAN;
return sac->max;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment