summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 9bcac13)
raw | patch | inline | side by side (parent: 9bcac13)
author | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Fri, 1 Jun 2012 10:04:59 +0000 (10:04 +0000) | ||
committer | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Fri, 1 Jun 2012 10:04:59 +0000 (10:04 +0000) |
CONTRIBUTORS | patch | blob | history | |
doc/rrdgraph_rpn.pod | patch | blob | history | |
src/rrd_rpncalc.c | patch | blob | history | |
src/rrd_rpncalc.h | patch | blob | history |
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 6c651eb98d6e30023c231d6f112df395996ff132..5b004df561d10eac273e1e4f22be750eafccb00a 100644 (file)
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
Amos Shapira <amos with gezernet.co.il>
Andreas Kroomaa <andre with ml.ee>
Andrew Turner <turner with mint.net> (LAST consolidator)
+Aaron Gallagher <_ with habnab.it> MEDIAN operator
Benny Baumann <benbe with geshi.org) rrd_dump with callback support
Bernard Fischer <bfischer with syslog.ch> 64bit stuff, --alt-autoscale-max
Bernhard Fischer <rep dot dot dot nop with gmail.com> MMAP rewrite
diff --git a/doc/rrdgraph_rpn.pod b/doc/rrdgraph_rpn.pod
index 894fef16bbabcf42215946a1f880d8241d954f38..87fc8e666132a57524885f6f8e7ac7a49302078f 100644 (file)
--- a/doc/rrdgraph_rpn.pod
+++ b/doc/rrdgraph_rpn.pod
Example: C<CDEF:x=a,b,c,d,4,AVG>
+B<MEDIAN>
+
+pop one element (I<count>) from the stack. Now pop I<count> elements and find
+the median, ignoring all UNKNOWN values in the process. If there are an even
+number of non-UNKNOWN values, the average of the middle two will be pushed on
+the stack.
+
+Example: C<CDEF:x=a,b,c,d,4,MEDIAN>
+
+
B<TREND, TRENDNAN>
Create a "sliding window" average of another data series.
diff --git a/src/rrd_rpncalc.c b/src/rrd_rpncalc.c
index 2bd1474e67c92b72686e43fc49629060db85a5b0..0677b3090634293675342b29c2db0ccae4b9026d 100644 (file)
--- a/src/rrd_rpncalc.c
+++ b/src/rrd_rpncalc.c
match_op(OP_AVG, AVG)
match_op(OP_ABS, ABS)
match_op(OP_ADDNAN, ADDNAN)
+ match_op(OP_MEDIAN, MEDIAN)
#undef match_op
else if ((sscanf(expr, DEF_NAM_FMT "%n", vname, &pos) == 1)
&& ((rpnp[steps].ptr = (*lookup) (key_hash, vname)) !=
stackunderflow(0);
rpnstack->s[stptr] = fabs(rpnstack->s[stptr]);
break;
+ case OP_MEDIAN:
+ stackunderflow(0);
+ {
+ int elements = (int) rpnstack->s[stptr--];
+ int final_elements = elements;
+ double *element_ptr = rpnstack->s + stptr - elements + 1;
+ double *goodvals = element_ptr;
+ double *badvals = element_ptr + elements - 1;
+
+ stackunderflow(elements - 1);
+
+ /* move values to consolidate the non-NANs for sorting, keeping
+ * track of how many NANs we encounter. */
+ while (goodvals < badvals) {
+ if (isnan(*goodvals)) {
+ *goodvals = *badvals--;
+ --final_elements;
+ } else {
+ ++goodvals;
+ }
+ }
+
+ stptr -= elements;
+ if (!final_elements) {
+ /* no non-NAN elements; push NAN */
+ rpnstack->s[++stptr] = DNAN;
+ } else {
+ /* when goodvals and badvals meet, they might have met on a
+ * NAN, which wouldn't decrease final_elements. so, check
+ * that now. */
+ if (isnan(*goodvals)) --final_elements;
+ /* and finally, take the median of the remaining non-NAN
+ * elements. */
+ qsort(element_ptr, final_elements, sizeof(double),
+ rpn_compare_double);
+ if (final_elements % 2 == 1){
+ rpnstack->s[++stptr] = element_ptr[ final_elements / 2 ];
+ }
+ else {
+ rpnstack->s[++stptr] = 0.5 * ( element_ptr[ final_elements / 2 ] + element_ptr[ final_elements / 2 - 1 ] );
+ }
+ }
+ }
+ break;
+
case OP_END:
break;
}
diff --git a/src/rrd_rpncalc.h b/src/rrd_rpncalc.h
index ab990b2204bd1e61024a150495552ea23a5125e8..d27ff4c06fc8025172d758e39e11cb3cbd9f96d1 100644 (file)
--- a/src/rrd_rpncalc.h
+++ b/src/rrd_rpncalc.h
OP_ATAN, OP_SQRT, OP_SORT, OP_REV, OP_TREND, OP_TRENDNAN,
OP_ATAN2, OP_RAD2DEG, OP_DEG2RAD,
OP_PREDICT,OP_PREDICTSIGMA,
- OP_AVG, OP_ABS, OP_ADDNAN
+ OP_AVG, OP_ABS, OP_ADDNAN, OP_MEDIAN
};
typedef struct rpnp_t {