annotate maths/MathUtilities.cpp @ 515:08bcc06c38ec tip master

Remove fast-math
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 28 Jan 2020 15:27:37 +0000
parents fa407c1d9923
children
rev   line source
c@241 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@241 2
c@241 3 /*
c@241 4 QM DSP Library
c@241 5
c@241 6 Centre for Digital Music, Queen Mary, University of London.
c@309 7 This file 2005-2006 Christian Landone.
c@309 8
c@309 9 This program is free software; you can redistribute it and/or
c@309 10 modify it under the terms of the GNU General Public License as
c@309 11 published by the Free Software Foundation; either version 2 of the
c@309 12 License, or (at your option) any later version. See the file
c@309 13 COPYING included with this distribution for more information.
c@241 14 */
c@241 15
c@241 16 #include "MathUtilities.h"
c@241 17
c@241 18 #include <iostream>
c@348 19 #include <algorithm>
c@348 20 #include <vector>
c@241 21 #include <cmath>
c@241 22
c@418 23 using namespace std;
c@241 24
c@241 25 double MathUtilities::mod(double x, double y)
c@241 26 {
c@241 27 double a = floor( x / y );
c@241 28
c@241 29 double b = x - ( y * a );
c@241 30 return b;
c@241 31 }
c@241 32
c@241 33 double MathUtilities::princarg(double ang)
c@241 34 {
c@241 35 double ValOut;
c@241 36
c@241 37 ValOut = mod( ang + M_PI, -2 * M_PI ) + M_PI;
c@241 38
c@241 39 return ValOut;
c@241 40 }
c@241 41
c@414 42 void MathUtilities::getAlphaNorm(const double *data, int len, int alpha, double* ANorm)
c@241 43 {
c@414 44 int i;
c@241 45 double temp = 0.0;
c@241 46 double a=0.0;
cannam@477 47
cannam@477 48 for( i = 0; i < len; i++) {
cannam@477 49 temp = data[ i ];
cannam@477 50 a += ::pow( fabs(temp), double(alpha) );
c@241 51 }
c@241 52 a /= ( double )len;
c@241 53 a = ::pow( a, ( 1.0 / (double) alpha ) );
c@241 54
c@241 55 *ANorm = a;
c@241 56 }
c@241 57
c@418 58 double MathUtilities::getAlphaNorm( const vector <double> &data, int alpha )
c@241 59 {
c@414 60 int i;
c@414 61 int len = data.size();
c@241 62 double temp = 0.0;
c@241 63 double a=0.0;
cannam@477 64
cannam@477 65 for( i = 0; i < len; i++) {
cannam@477 66 temp = data[ i ];
cannam@477 67 a += ::pow( fabs(temp), double(alpha) );
c@241 68 }
c@241 69 a /= ( double )len;
c@241 70 a = ::pow( a, ( 1.0 / (double) alpha ) );
c@241 71
c@241 72 return a;
c@241 73 }
c@241 74
c@241 75 double MathUtilities::round(double x)
c@241 76 {
c@348 77 if (x < 0) {
c@348 78 return -floor(-x + 0.5);
c@348 79 } else {
c@348 80 return floor(x + 0.5);
c@348 81 }
c@241 82 }
c@241 83
c@414 84 double MathUtilities::median(const double *src, int len)
c@241 85 {
c@348 86 if (len == 0) return 0;
c@348 87
c@418 88 vector<double> scratch;
c@348 89 for (int i = 0; i < len; ++i) scratch.push_back(src[i]);
c@418 90 sort(scratch.begin(), scratch.end());
c@241 91
c@348 92 int middle = len/2;
c@348 93 if (len % 2 == 0) {
c@348 94 return (scratch[middle] + scratch[middle - 1]) / 2;
c@348 95 } else {
c@348 96 return scratch[middle];
c@241 97 }
c@241 98 }
c@241 99
c@414 100 double MathUtilities::sum(const double *src, int len)
c@241 101 {
c@414 102 int i ;
c@241 103 double retVal =0.0;
c@241 104
cannam@477 105 for( i = 0; i < len; i++) {
cannam@477 106 retVal += src[ i ];
c@241 107 }
c@241 108
c@241 109 return retVal;
c@241 110 }
c@241 111
c@414 112 double MathUtilities::mean(const double *src, int len)
c@241 113 {
c@241 114 double retVal =0.0;
c@241 115
c@348 116 if (len == 0) return 0;
c@348 117
c@241 118 double s = sum( src, len );
cannam@477 119
c@241 120 retVal = s / (double)len;
c@241 121
c@241 122 return retVal;
c@241 123 }
c@241 124
c@418 125 double MathUtilities::mean(const vector<double> &src,
c@414 126 int start,
c@414 127 int count)
c@279 128 {
c@279 129 double sum = 0.;
cannam@477 130
c@348 131 if (count == 0) return 0;
c@348 132
cannam@477 133 for (int i = 0; i < (int)count; ++i) {
c@279 134 sum += src[start + i];
c@279 135 }
c@279 136
c@279 137 return sum / count;
c@279 138 }
c@279 139
c@414 140 void MathUtilities::getFrameMinMax(const double *data, int len, double *min, double *max)
c@241 141 {
c@414 142 int i;
c@241 143 double temp = 0.0;
c@283 144
c@283 145 if (len == 0) {
c@283 146 *min = *max = 0;
c@283 147 return;
c@283 148 }
cannam@477 149
c@241 150 *min = data[0];
c@241 151 *max = data[0];
c@241 152
cannam@477 153 for( i = 0; i < len; i++) {
cannam@477 154 temp = data[ i ];
c@241 155
cannam@477 156 if( temp < *min ) {
cannam@477 157 *min = temp ;
cannam@477 158 }
cannam@477 159 if( temp > *max ) {
cannam@477 160 *max = temp ;
cannam@477 161 }
c@241 162 }
c@241 163 }
c@241 164
c@414 165 int MathUtilities::getMax( double* pData, int Length, double* pMax )
c@241 166 {
cannam@477 167 int index = 0;
cannam@477 168 int i;
cannam@477 169 double temp = 0.0;
cannam@477 170
cannam@477 171 double max = pData[0];
c@241 172
cannam@477 173 for( i = 0; i < Length; i++) {
cannam@477 174 temp = pData[ i ];
c@241 175
cannam@477 176 if( temp > max ) {
cannam@477 177 max = temp ;
cannam@477 178 index = i;
cannam@477 179 }
cannam@477 180 }
c@241 181
cannam@477 182 if (pMax) *pMax = max;
c@279 183
c@279 184
cannam@477 185 return index;
c@279 186 }
c@279 187
c@418 188 int MathUtilities::getMax( const vector<double> & data, double* pMax )
c@279 189 {
cannam@477 190 int index = 0;
cannam@477 191 int i;
cannam@477 192 double temp = 0.0;
cannam@477 193
cannam@477 194 double max = data[0];
c@279 195
cannam@477 196 for( i = 0; i < int(data.size()); i++) {
c@279 197
cannam@477 198 temp = data[ i ];
c@279 199
cannam@477 200 if( temp > max ) {
cannam@477 201 max = temp ;
cannam@477 202 index = i;
cannam@477 203 }
cannam@477 204 }
c@241 205
cannam@477 206 if (pMax) *pMax = max;
c@241 207
cannam@477 208
cannam@477 209 return index;
c@241 210 }
c@241 211
c@241 212 void MathUtilities::circShift( double* pData, int length, int shift)
c@241 213 {
cannam@477 214 shift = shift % length;
cannam@477 215 double temp;
cannam@477 216 int i,n;
c@241 217
cannam@477 218 for( i = 0; i < shift; i++) {
cannam@477 219
cannam@477 220 temp=*(pData + length - 1);
c@241 221
cannam@477 222 for( n = length-2; n >= 0; n--) {
cannam@477 223 *(pData+n+1)=*(pData+n);
cannam@477 224 }
c@241 225
c@241 226 *pData = temp;
c@241 227 }
c@241 228 }
c@241 229
c@241 230 int MathUtilities::compareInt (const void * a, const void * b)
c@241 231 {
cannam@477 232 return ( *(int*)a - *(int*)b );
c@241 233 }
c@241 234
c@259 235 void MathUtilities::normalise(double *data, int length, NormaliseType type)
c@259 236 {
c@259 237 switch (type) {
c@259 238
c@259 239 case NormaliseNone: return;
c@259 240
c@259 241 case NormaliseUnitSum:
c@259 242 {
c@259 243 double sum = 0.0;
c@259 244 for (int i = 0; i < length; ++i) {
c@259 245 sum += data[i];
c@259 246 }
c@259 247 if (sum != 0.0) {
c@259 248 for (int i = 0; i < length; ++i) {
c@259 249 data[i] /= sum;
c@259 250 }
c@259 251 }
c@259 252 }
c@259 253 break;
c@259 254
c@259 255 case NormaliseUnitMax:
c@259 256 {
c@259 257 double max = 0.0;
c@259 258 for (int i = 0; i < length; ++i) {
c@259 259 if (fabs(data[i]) > max) {
c@259 260 max = fabs(data[i]);
c@259 261 }
c@259 262 }
c@259 263 if (max != 0.0) {
c@259 264 for (int i = 0; i < length; ++i) {
c@259 265 data[i] /= max;
c@259 266 }
c@259 267 }
c@259 268 }
c@259 269 break;
c@259 270
c@259 271 }
c@259 272 }
c@259 273
c@418 274 void MathUtilities::normalise(vector<double> &data, NormaliseType type)
c@259 275 {
c@259 276 switch (type) {
c@259 277
c@259 278 case NormaliseNone: return;
c@259 279
c@259 280 case NormaliseUnitSum:
c@259 281 {
c@259 282 double sum = 0.0;
c@325 283 for (int i = 0; i < (int)data.size(); ++i) sum += data[i];
c@259 284 if (sum != 0.0) {
c@325 285 for (int i = 0; i < (int)data.size(); ++i) data[i] /= sum;
c@259 286 }
c@259 287 }
c@259 288 break;
c@259 289
c@259 290 case NormaliseUnitMax:
c@259 291 {
c@259 292 double max = 0.0;
c@325 293 for (int i = 0; i < (int)data.size(); ++i) {
c@259 294 if (fabs(data[i]) > max) max = fabs(data[i]);
c@259 295 }
c@259 296 if (max != 0.0) {
c@325 297 for (int i = 0; i < (int)data.size(); ++i) data[i] /= max;
c@259 298 }
c@259 299 }
c@259 300 break;
c@259 301
c@259 302 }
c@259 303 }
c@259 304
c@418 305 double MathUtilities::getLpNorm(const vector<double> &data, int p)
c@418 306 {
c@418 307 double tot = 0.0;
c@418 308 for (int i = 0; i < int(data.size()); ++i) {
c@418 309 tot += abs(pow(data[i], p));
c@418 310 }
c@418 311 return pow(tot, 1.0 / p);
c@418 312 }
c@418 313
c@418 314 vector<double> MathUtilities::normaliseLp(const vector<double> &data,
cannam@477 315 int p,
cannam@477 316 double threshold)
c@418 317 {
c@418 318 int n = int(data.size());
c@418 319 if (n == 0 || p == 0) return data;
c@418 320 double norm = getLpNorm(data, p);
c@418 321 if (norm < threshold) {
c@418 322 return vector<double>(n, 1.0 / pow(n, 1.0 / p)); // unit vector
c@418 323 }
c@418 324 vector<double> out(n);
c@418 325 for (int i = 0; i < n; ++i) {
c@418 326 out[i] = data[i] / norm;
c@418 327 }
c@418 328 return out;
c@418 329 }
c@418 330
c@418 331 void MathUtilities::adaptiveThreshold(vector<double> &data)
c@279 332 {
c@279 333 int sz = int(data.size());
c@279 334 if (sz == 0) return;
c@279 335
c@418 336 vector<double> smoothed(sz);
cannam@477 337
c@279 338 int p_pre = 8;
c@279 339 int p_post = 7;
c@279 340
c@279 341 for (int i = 0; i < sz; ++i) {
c@279 342
c@418 343 int first = max(0, i - p_pre);
c@418 344 int last = min(sz - 1, i + p_post);
c@279 345
c@279 346 smoothed[i] = mean(data, first, last - first + 1);
c@279 347 }
c@279 348
c@279 349 for (int i = 0; i < sz; i++) {
c@279 350 data[i] -= smoothed[i];
c@279 351 if (data[i] < 0.0) data[i] = 0.0;
c@279 352 }
c@279 353 }
c@259 354
c@280 355 bool
c@280 356 MathUtilities::isPowerOfTwo(int x)
c@280 357 {
c@348 358 if (x < 1) return false;
c@280 359 if (x & (x-1)) return false;
c@280 360 return true;
c@280 361 }
c@280 362
c@280 363 int
c@280 364 MathUtilities::nextPowerOfTwo(int x)
c@280 365 {
c@280 366 if (isPowerOfTwo(x)) return x;
c@348 367 if (x < 1) return 1;
c@280 368 int n = 1;
c@280 369 while (x) { x >>= 1; n <<= 1; }
c@280 370 return n;
c@280 371 }
c@280 372
c@280 373 int
c@280 374 MathUtilities::previousPowerOfTwo(int x)
c@280 375 {
c@280 376 if (isPowerOfTwo(x)) return x;
c@348 377 if (x < 1) return 1;
c@280 378 int n = 1;
c@280 379 x >>= 1;
c@280 380 while (x) { x >>= 1; n <<= 1; }
c@280 381 return n;
c@280 382 }
c@280 383
c@280 384 int
c@280 385 MathUtilities::nearestPowerOfTwo(int x)
c@280 386 {
c@280 387 if (isPowerOfTwo(x)) return x;
cannam@477 388 int n0 = previousPowerOfTwo(x);
cannam@477 389 int n1 = nextPowerOfTwo(x);
c@280 390 if (x - n0 < n1 - x) return n0;
c@280 391 else return n1;
c@280 392 }
c@280 393
c@360 394 double
c@348 395 MathUtilities::factorial(int x)
c@348 396 {
c@348 397 if (x < 0) return 0;
c@360 398 double f = 1;
c@348 399 for (int i = 1; i <= x; ++i) {
cannam@477 400 f = f * i;
c@348 401 }
c@348 402 return f;
c@348 403 }
c@348 404
c@350 405 int
c@350 406 MathUtilities::gcd(int a, int b)
c@350 407 {
c@350 408 int c = a % b;
c@350 409 if (c == 0) {
c@350 410 return b;
c@350 411 } else {
c@350 412 return gcd(b, c);
c@350 413 }
c@350 414 }
c@350 415