X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_rpncalc.c;h=0677b3090634293675342b29c2db0ccae4b9026d;hp=8dd224000824adcd496a636de3dde210c81123ed;hb=8527e903bb76856a16e0f68f73ac11e4e087dfc3;hpb=327c6498066d67dd7b343b2c677c2e7fe1fb7d98 diff --git a/src/rrd_rpncalc.c b/src/rrd_rpncalc.c index 8dd2240..0677b30 100644 --- a/src/rrd_rpncalc.c +++ b/src/rrd_rpncalc.c @@ -33,8 +33,8 @@ short rpn_compact( while (rpnp[*count].op != OP_END) (*count)++; if (++(*count) > DS_CDEF_MAX_RPN_NODES) { - rrd_set_error("Maximum %d RPN nodes permitted", - DS_CDEF_MAX_RPN_NODES); + rrd_set_error("Maximum %d RPN nodes permitted. Got %d RPN nodes at present.", + DS_CDEF_MAX_RPN_NODES-1,(*count)-1); return -1; } @@ -236,9 +236,11 @@ void parseCDEF_DS( * occur too often. */ for (i = 0; rpnp[i].op != OP_END; i++) { if (rpnp[i].op == OP_TIME || rpnp[i].op == OP_LTIME || - rpnp[i].op == OP_PREV || rpnp[i].op == OP_COUNT) { + rpnp[i].op == OP_PREV || rpnp[i].op == OP_COUNT || + rpnp[i].op == OP_TREND || rpnp[i].op == OP_TRENDNAN || + rpnp[i].op == OP_PREDICT || rpnp[i].op == OP_PREDICTSIGMA ) { rrd_set_error - ("operators time, ltime, prev and count not supported with DS COMPUTE"); + ("operators TIME, LTIME, PREV COUNT TREND TRENDNAN PREDICT PREDICTSIGMA are not supported with DS COMPUTE"); free(rpnp); return; } @@ -385,6 +387,7 @@ rpnp_t *rpn_parse( 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)) != @@ -934,6 +937,51 @@ short rpn_calc( 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; }