stddev.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "stddev.h"
  3. // ----------------------------------------------------------------------------
  4. // stddev
  5. // this implementation comes from:
  6. // https://www.johndcook.com/blog/standard_deviation/
  7. struct grouping_stddev {
  8. long count;
  9. NETDATA_DOUBLE m_oldM, m_newM, m_oldS, m_newS;
  10. };
  11. void grouping_create_stddev(RRDR *r, const char *options __maybe_unused) {
  12. r->internal.grouping_data = onewayalloc_callocz(r->internal.owa, 1, sizeof(struct grouping_stddev));
  13. }
  14. // resets when switches dimensions
  15. // so, clear everything to restart
  16. void grouping_reset_stddev(RRDR *r) {
  17. struct grouping_stddev *g = (struct grouping_stddev *)r->internal.grouping_data;
  18. g->count = 0;
  19. }
  20. void grouping_free_stddev(RRDR *r) {
  21. onewayalloc_freez(r->internal.owa, r->internal.grouping_data);
  22. r->internal.grouping_data = NULL;
  23. }
  24. void grouping_add_stddev(RRDR *r, NETDATA_DOUBLE value) {
  25. struct grouping_stddev *g = (struct grouping_stddev *)r->internal.grouping_data;
  26. g->count++;
  27. // See Knuth TAOCP vol 2, 3rd edition, page 232
  28. if (g->count == 1) {
  29. g->m_oldM = g->m_newM = value;
  30. g->m_oldS = 0.0;
  31. }
  32. else {
  33. g->m_newM = g->m_oldM + (value - g->m_oldM) / g->count;
  34. g->m_newS = g->m_oldS + (value - g->m_oldM) * (value - g->m_newM);
  35. // set up for next iteration
  36. g->m_oldM = g->m_newM;
  37. g->m_oldS = g->m_newS;
  38. }
  39. }
  40. static inline NETDATA_DOUBLE mean(struct grouping_stddev *g) {
  41. return (g->count > 0) ? g->m_newM : 0.0;
  42. }
  43. static inline NETDATA_DOUBLE variance(struct grouping_stddev *g) {
  44. return ( (g->count > 1) ? g->m_newS/(NETDATA_DOUBLE)(g->count - 1) : 0.0 );
  45. }
  46. static inline NETDATA_DOUBLE stddev(struct grouping_stddev *g) {
  47. return sqrtndd(variance(g));
  48. }
  49. NETDATA_DOUBLE grouping_flush_stddev(RRDR *r, RRDR_VALUE_FLAGS *rrdr_value_options_ptr) {
  50. struct grouping_stddev *g = (struct grouping_stddev *)r->internal.grouping_data;
  51. NETDATA_DOUBLE value;
  52. if(likely(g->count > 1)) {
  53. value = stddev(g);
  54. if(!netdata_double_isnumber(value)) {
  55. value = 0.0;
  56. *rrdr_value_options_ptr |= RRDR_VALUE_EMPTY;
  57. }
  58. }
  59. else if(g->count == 1) {
  60. value = 0.0;
  61. }
  62. else {
  63. value = 0.0;
  64. *rrdr_value_options_ptr |= RRDR_VALUE_EMPTY;
  65. }
  66. grouping_reset_stddev(r);
  67. return value;
  68. }
  69. // https://en.wikipedia.org/wiki/Coefficient_of_variation
  70. NETDATA_DOUBLE grouping_flush_coefficient_of_variation(RRDR *r, RRDR_VALUE_FLAGS *rrdr_value_options_ptr) {
  71. struct grouping_stddev *g = (struct grouping_stddev *)r->internal.grouping_data;
  72. NETDATA_DOUBLE value;
  73. if(likely(g->count > 1)) {
  74. NETDATA_DOUBLE m = mean(g);
  75. value = 100.0 * stddev(g) / ((m < 0)? -m : m);
  76. if(unlikely(!netdata_double_isnumber(value))) {
  77. value = 0.0;
  78. *rrdr_value_options_ptr |= RRDR_VALUE_EMPTY;
  79. }
  80. }
  81. else if(g->count == 1) {
  82. // one value collected
  83. value = 0.0;
  84. }
  85. else {
  86. // no values collected
  87. value = 0.0;
  88. *rrdr_value_options_ptr |= RRDR_VALUE_EMPTY;
  89. }
  90. grouping_reset_stddev(r);
  91. return value;
  92. }
  93. /*
  94. * Mean = average
  95. *
  96. NETDATA_DOUBLE grouping_flush_mean(RRDR *r, RRDR_VALUE_FLAGS *rrdr_value_options_ptr) {
  97. struct grouping_stddev *g = (struct grouping_stddev *)r->internal.grouping_data;
  98. NETDATA_DOUBLE value;
  99. if(unlikely(!g->count)) {
  100. value = 0.0;
  101. *rrdr_value_options_ptr |= RRDR_VALUE_EMPTY;
  102. }
  103. else {
  104. value = mean(g);
  105. if(!isnormal(value)) {
  106. value = 0.0;
  107. *rrdr_value_options_ptr |= RRDR_VALUE_EMPTY;
  108. }
  109. }
  110. grouping_reset_stddev(r);
  111. return value;
  112. }
  113. */
  114. /*
  115. * It is not advised to use this version of variance directly
  116. *
  117. NETDATA_DOUBLE grouping_flush_variance(RRDR *r, RRDR_VALUE_FLAGS *rrdr_value_options_ptr) {
  118. struct grouping_stddev *g = (struct grouping_stddev *)r->internal.grouping_data;
  119. NETDATA_DOUBLE value;
  120. if(unlikely(!g->count)) {
  121. value = 0.0;
  122. *rrdr_value_options_ptr |= RRDR_VALUE_EMPTY;
  123. }
  124. else {
  125. value = variance(g);
  126. if(!isnormal(value)) {
  127. value = 0.0;
  128. *rrdr_value_options_ptr |= RRDR_VALUE_EMPTY;
  129. }
  130. }
  131. grouping_reset_stddev(r);
  132. return value;
  133. }
  134. */