X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Frrd_rpncalc.c;h=ab01c8ad12aed2687e1b2325fe6a0f504709e488;hb=HEAD;hp=b563db40a8c5154c96dfb57badec4379187fd334;hpb=4544c97f2699490bdfef560e6dbcd71de09db7b2;p=rrdtool.git diff --git a/src/rrd_rpncalc.c b/src/rrd_rpncalc.c index b563db4..ab01c8a 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; } @@ -77,7 +77,7 @@ rpnp_t *rpn_expand( return NULL; } for (i = 0; rpnc[i].op != OP_END; ++i) { - rpnp[i].op = (op_en)rpnc[i].op; + rpnp[i].op = (enum op_en)rpnc[i].op; if (rpnp[i].op == OP_NUMBER) { rpnp[i].val = (double) rpnc[i].val; } else if (rpnp[i].op == OP_VARIABLE || rpnp[i].op == OP_PREV_OTHER) { @@ -117,7 +117,7 @@ void rpn_compact2str( #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) _itoa(rpnc[i].val, buffer, 10); #else - sprintf(buffer, "%d", rpnc[i].val); + snprintf(buffer, sizeof buffer, "%d", rpnc[i].val); #endif add_op(OP_NUMBER, buffer) } @@ -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; } @@ -297,7 +299,8 @@ rpnp_t *rpn_parse( char vname[MAX_VNAME_LEN + 10]; char *old_locale; - old_locale = setlocale(LC_NUMERIC, "C"); + old_locale = setlocale(LC_NUMERIC, NULL); + setlocale(LC_NUMERIC, "C"); rpnp = NULL; expr = (char *) expr_const; @@ -384,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)) != @@ -880,7 +884,7 @@ short rpn_calc( time_t dur = (time_t) rpnstack->s[stptr]; time_t step = (time_t) rpnp[rpi - 2].step; - if (output_idx > (int) ceil((float) dur / (float) step)) { + if (output_idx + 1 >= (int) ceil((float) dur / (float) step)) { int ignorenan = (rpnp[rpi].op == OP_TREND); double accum = 0.0; int i = 0; @@ -933,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; }