123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- /* NUM.cpp
- *
- * Copyright (C) 2017,2018 Paul Boersma
- *
- * This code is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This code is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this work. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "melder.h"
- double NUMcenterOfGravity (const constVEC& x) noexcept {
- longdouble weightedSumOfIndexes = 0.0, sumOfWeights = 0.0;
- for (integer i = 1; i <= x.size; i ++) {
- weightedSumOfIndexes += i * x [i];
- sumOfWeights += x [i];
- }
- return double (weightedSumOfIndexes / sumOfWeights);
- }
- double NUMcolumnMean (const constMAT& x, integer columnNumber) noexcept {
- Melder_assert (columnNumber > 0 && columnNumber <= x.ncol);
- integer stride = x.ncol;
- PAIRWISE_SUM (longdouble, sum, integer, x.nrow,
- const double *px = & x [1] [columnNumber],
- (longdouble) *px,
- px += stride
- )
- return double (sum / x.nrow);
- }
- double NUMcolumnSum (const constMAT& x, integer columnNumber) noexcept {
- Melder_assert (columnNumber > 0 && columnNumber <= x.nrow);
- integer stride = x.ncol;
- PAIRWISE_SUM (longdouble, sum, integer, x.nrow,
- const double *px = & x [1] [columnNumber],
- (longdouble) *px,
- px += stride
- )
- return double (sum);
- }
- double NUMinner_ (const constVEC& x, const constVEC& y) noexcept {
- PAIRWISE_SUM (longdouble, sum, integer, x.size,
- const double *px = & x [1];
- const double *py = & y [1],
- (longdouble) *px * (longdouble) *py,
- (++ px, ++ py)
- )
- return double (sum);
- }
- double NUMnorm (const constVEC& x, double power) noexcept {
- if (power < 0.0) return undefined;
- if (power == 2.0) {
- PAIRWISE_SUM (longdouble, sum, integer, x.size,
- const double *px = & x [1],
- (longdouble) *px * (longdouble) *px,
- ++ px
- )
- return sqrt ((double) sum);
- } else if (power == 1.0) {
- PAIRWISE_SUM (longdouble, sum, integer, x.size,
- const double *px = & x [1],
- (longdouble) fabs (*px),
- ++ px
- )
- return (double) sum;
- } else {
- PAIRWISE_SUM (longdouble, sum, integer, x.size,
- const double *px = & x [1],
- powl ((longdouble) fabs (*px), power),
- ++ px
- )
- return (double) powl (sum, (longdouble) 1.0 / power);
- }
- }
- integer NUMnumberOfTokens (conststring32 string) noexcept {
- integer numberOfTokens = 0;
- const char32 *p = & string [0];
- for (;;) {
- Melder_skipHorizontalOrVerticalSpace (& p);
- if (*p == U'\0')
- break;
- numberOfTokens ++;
- p ++; // step over first nonspace
- p = Melder_findEndOfInk (p);
- }
- return numberOfTokens;
- }
- double NUMstdev (const constVEC& x) noexcept {
- double stdev;
- NUM_sum_mean_sumsq_variance_stdev (x, nullptr, nullptr, nullptr, nullptr, & stdev);
- return stdev;
- }
- void NUM_sum_mean (const constVEC& x, double *out_sum, double *out_mean) noexcept {
- if (x.size <= 4) {
- switch (x.size) {
- case 0: {
- if (out_sum) *out_sum = 0.0;
- if (out_mean) *out_mean = undefined;
- } break; case 1: {
- if (out_sum) *out_sum = x [1];
- if (out_mean) *out_mean = x [1];
- } break; case 2: {
- longdouble sum = (longdouble) x [1] + (longdouble) x [2];
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = double (0.5 * sum);
- } break; case 3: {
- longdouble sum = (longdouble) x [1] + (longdouble) x [2] + (longdouble) x [3];
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = double ((1.0 / (longdouble) 3.0) * sum);
- } break; case 4: {
- longdouble sum = ((longdouble) x [1] + (longdouble) x [2]) + ((longdouble) x [3] + (longdouble) x [4]);
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = double (0.25 * sum);
- } break; default: {
- if (out_sum) *out_sum = undefined;
- if (out_mean) *out_mean = undefined;
- }
- }
- return;
- }
- if (Melder_debug == 0 || Melder_debug < 48 || Melder_debug > 51) {
- PAIRWISE_SUM (longdouble, sum, integer, x.size, const double *px = & x [1], (longdouble) *px, ++ px)
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = double (sum / x.size); // it helps a bit to perform the division while still in longdouble
- } else if (Melder_debug == 48) {
- SEQUENTIAL_SUM (double, sum, integer, x.size, const double *px = & x [1], *px, ++ px)
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = double (sum / x.size);
- } else if (Melder_debug == 49) {
- SEQUENTIAL_SUM (longdouble, sum, integer, x.size, const double *px = & x [1], *px, ++ px)
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = double (sum / x.size);
- } else if (Melder_debug == 50) {
- KAHAN_SUM (longdouble, sum, integer, x.size, const double *px = & x [1], *px, ++ px)
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = double (sum / x.size);
- } else if (Melder_debug == 51) {
- TWO_LOOP_SUM (longdouble, sum, integer, x.size, const double *px = & x [1], *px, ++ px)
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = double (sum / x.size);
- }
- }
- void NUM_sum_mean_sumsq_variance_stdev (const constVEC& x,
- double *out_sum, double *out_mean, double *out_sumsq, double *out_variance, double *out_stdev) noexcept
- {
- if (x.size < 2) {
- if (x.size <= 0) {
- if (out_sum) *out_sum = 0.0;
- if (out_mean) *out_mean = undefined;
- if (out_sumsq) *out_sumsq = undefined;
- } else {
- if (out_sum) *out_sum = x [1];
- if (out_mean) *out_mean = x [1];
- if (out_sumsq) *out_sumsq = 0.0;
- }
- if (out_variance) *out_variance = undefined;
- if (out_stdev) *out_stdev = undefined;
- return;
- }
- if (Melder_debug != 0) {
- if (Melder_debug == 48) {
- /*
- Naive implementation in double.
- */
- double sum = 0.0; // -> sum in R (invariant) [R is the set of real numbers]
- for (integer i = 1; i <= x.size; i ++)
- sum += x [i]; // sum before in R, x [i] in R -> sum after in R
- if (out_sum) *out_sum = sum;
- double mean = sum / x.size; // sum in R, x.size != 0 -> mean in R
- if (out_mean) *out_mean = mean;
- if (! out_sumsq && ! out_variance && ! out_stdev) return;
- double sumOfSquaredResiduals = 0.0; // -> sumOfSquares >= 0.0 (invariant)
- for (integer i = 1; i <= x.size; i ++) {
- double residual = x [i] - mean; // x [i] in R, mean in R -> residual in R
- double squaredResidual = residual * residual; // residual in R -> squaredResidual >= 0.0
- sumOfSquaredResiduals += squaredResidual; // sumOfSquaredResiduals before >= 0.0, squaredResidual >= 0.0 -> sumOfSquaredResiduals after >= 0.0
- }
- if (out_sumsq) *out_sumsq = sumOfSquaredResiduals;
- integer degreesOfFreedom = x.size - 1; // x.size >= 2 -> degreesOfFreedom >= 1 -> degreesOfFreedom > 0
- double meanSquaredResidual = sumOfSquaredResiduals / degreesOfFreedom; // sumOfSquaredResiduals >= 0.0, degreesOfFreedom > 0 -> meanSquaredResidual >= 0.0
- if (out_variance) *out_variance = (double) meanSquaredResidual;
- if (out_stdev) {
- double rootMeanSquaredResidual = sqrt (meanSquaredResidual); // meanSquaredResidual >= 0.0 -> rootMeanSquaredResidual >= 0.0 (in particular, not NaN)
- *out_stdev = rootMeanSquaredResidual;
- }
- return;
- }
- if (Melder_debug == 49) {
- /*
- Naive implementation in longdouble.
- */
- longdouble sum = 0.0; // -> sum in R (invariant)
- for (integer i = 1; i <= x.size; i ++)
- sum += (longdouble) x [i]; // sum before in R, x [i] in R -> sum after in R
- if (out_sum) *out_sum = (double) sum;
- longdouble mean = sum / x.size; // sum in R, x.size != 0 -> mean in R
- if (out_mean) *out_mean = (double) mean;
- if (! out_sumsq && ! out_variance && ! out_stdev) return;
- longdouble sumOfSquaredResiduals = 0.0; // -> sumOfSquares >= 0.0 (invariant)
- for (integer i = 1; i <= x.size; i ++) {
- longdouble residual = (longdouble) x [i] - mean; // x [i] in R, mean in R -> residual in R
- longdouble squaredResidual = residual * residual; // residual in R -> squaredResidual >= 0.0
- sumOfSquaredResiduals += squaredResidual; // sumOfSquaredResiduals before >= 0.0, squaredResidual >= 0.0 -> sumOfSquaredResiduals after >= 0.0
- }
- if (out_sumsq) *out_sumsq = (double) sumOfSquaredResiduals;
- integer degreesOfFreedom = x.size - 1; // x.size >= 2 -> degreesOfFreedom >= 1 -> degreesOfFreedom > 0
- longdouble meanSquaredResidual = sumOfSquaredResiduals / degreesOfFreedom; // sumOfSquaredResiduals >= 0.0, degreesOfFreedom > 0 -> meanSquaredResidual >= 0.0
- if (out_variance) *out_variance = (double) meanSquaredResidual;
- if (out_stdev) {
- longdouble rootMeanSquaredResidual = sqrtl (meanSquaredResidual); // meanSquaredResidual >= 0.0 -> rootMeanSquaredResidual >= 0.0 (in particular, not NaN)
- *out_stdev = (double) rootMeanSquaredResidual;
- }
- return;
- }
- if (Melder_debug == 50) {
- double mean;
- NUM_sum_mean (x, out_sum, & mean);
- if (out_mean) *out_mean = mean;
- if (! out_sumsq && ! out_variance && ! out_stdev) {
- return;
- }
- KAHAN_SUM (longdouble, sumsq, integer, x.size,
- const double *px = & x [1],
- longdouble (*px - mean) * longdouble (*px - mean),
- ++ px)
- double variance = double (sumsq / (x.size - 1));
- if (out_sumsq) *out_sumsq = (double) sumsq;
- if (out_variance) *out_variance = variance;
- if (out_stdev) *out_stdev = sqrt (variance);
- return;
- }
- if (Melder_debug == 51) {
- double sum, mean;
- NUM_sum_mean (x, & sum, & mean);
- if (out_sum) *out_sum = sum;
- if (out_mean) *out_mean = mean;
- if (! out_sumsq && ! out_variance && ! out_stdev) return;
- double sumOfSquaredResiduals = 0.0; // -> sumOfSquares >= 0.0 (invariant)
- for (integer i = 1; i <= x.size; i ++) {
- double residual = x [i] - mean; // x [i] in R, mean in R -> residual in R
- double squaredResidual = residual * residual; // residual in R -> squaredResidual >= 0.0
- sumOfSquaredResiduals += squaredResidual; // sumOfSquaredResiduals before >= 0.0, squaredResidual >= 0.0 -> sumOfSquaredResiduals after >= 0.0
- }
- if (out_sumsq) *out_sumsq = sumOfSquaredResiduals;
- integer degreesOfFreedom = x.size - 1; // x.size >= 2 -> degreesOfFreedom >= 1 -> degreesOfFreedom > 0
- double meanSquaredResidual = sumOfSquaredResiduals / degreesOfFreedom; // sumOfSquaredResiduals >= 0.0, degreesOfFreedom > 0 -> meanSquaredResidual >= 0.0
- if (out_variance) *out_variance = (double) meanSquaredResidual;
- if (out_stdev) {
- double rootMeanSquaredResidual = sqrt (meanSquaredResidual); // meanSquaredResidual >= 0.0 -> rootMeanSquaredResidual >= 0.0 (in particular, not NaN)
- *out_stdev = rootMeanSquaredResidual;
- }
- return;
- }
- }
- /*
- Our standard: pairwise algorithm with base case 64.
- */
- PAIRWISE_SUM (longdouble, sum, integer, x.size,
- const double *px = & x [1],
- (longdouble) *px,
- px += 1
- )
- double mean = double (sum / x.size); // rounded to double, because this guarantees that x[i] - mean will be zero for constant x[1..size]
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = (double) mean;
- if (! out_sumsq && ! out_variance && ! out_stdev) return;
- PAIRWISE_SUM (longdouble, sumsq, integer, x.size,
- const double *xx = & x [1],
- longdouble (*xx - mean) * longdouble (*xx - mean),
- xx += 1
- )
- longdouble variance = sumsq / (x.size - 1);
- if (out_sumsq) *out_sumsq = (double) sumsq;
- if (out_variance) *out_variance = (double) variance;
- if (out_stdev) *out_stdev = sqrt ((double) variance);
- }
- void NUM_sum_mean_sumsq_variance_stdev (const constMAT& x, integer columnNumber,
- double *out_sum, double *out_mean, double *out_sumsq, double *out_variance, double *out_stdev) noexcept
- {
- if (x.nrow < 2) {
- if (x.nrow <= 0) {
- if (out_sum) *out_sum = 0.0;
- if (out_mean) *out_mean = undefined;
- if (out_sumsq) *out_sumsq = undefined;
- } else {
- if (out_sum) *out_sum = x [1] [columnNumber];
- if (out_mean) *out_mean = x [1] [columnNumber];
- if (out_sumsq) *out_sumsq = 0.0;
- }
- if (out_variance) *out_variance = undefined;
- if (out_stdev) *out_stdev = undefined;
- return;
- }
- PAIRWISE_SUM (longdouble, sum, integer, x.nrow,
- const double *px = & x [1] [columnNumber],
- (longdouble) *px,
- px += x.ncol
- )
- double mean = double (sum / x.nrow); // rounded to double, because this guarantees that x[i] - mean will be zero for constant x[1..size]
- if (out_sum) *out_sum = (double) sum;
- if (out_mean) *out_mean = (double) mean;
- if (! out_sumsq && ! out_variance && ! out_stdev) return;
- PAIRWISE_SUM (longdouble, sumsq, integer, x.nrow,
- const double *px = & x [1] [columnNumber],
- longdouble (*px - mean) * longdouble (*px - mean),
- px += x.ncol
- )
- longdouble variance = sumsq / (x.nrow - 1);
- if (out_sumsq) *out_sumsq = (double) sumsq;
- if (out_variance) *out_variance = (double) variance;
- if (out_stdev) *out_stdev = sqrt ((double) variance);
- }
- double NUMsumsq (const constVEC& x) noexcept {
- double sumsq;
- NUM_sum_mean_sumsq_variance_stdev (x, nullptr, nullptr, & sumsq, nullptr, nullptr);
- return sumsq;
- }
- double NUMvariance (const constVEC& x) noexcept {
- double variance;
- NUM_sum_mean_sumsq_variance_stdev (x, nullptr, nullptr, nullptr, & variance, nullptr);
- return variance;
- }
- /* End of file NUM.cpp */
|