Pop one element from the stack, compare this to I<unknown> respectively
to I<positive or negative infinity>. Returns 1 for true or 0 for false.
-B<IF>
+I<then>,I<else>,I<condition>,B<IF>
Pops three elements from the stack. If the element popped last is 0
(false), the value popped first is pushed back onto the stack,
then the result of the operation will be the other one. If both are
I<unknown>, then the result of the operation is I<unknown>.
-B<LIMIT>
+I<lower-limit>,I<upper-limit>,B<LIMIT>
Pops two elements from the stack and uses them to define a range.
Then it pops another element and if it falls inside the range, it
NAN-safe addition. If one parameter is NAN/UNKNOWN it'll be treated as
zero. If both parameters are NAN/UNKNOWN, NAN/UNKNOWN will be returned.
+
+I<value>,I<power>,B<POW>
+
+Raise I<value> to the power of I<power>.
+
B<SIN, COS, LOG, EXP, SQRT>
Sine and cosine (input in radians), log and exp (natural logarithm),
=item Set Operations
-B<SORT, REV>
+I<count>,B<SORT>
+
+Pop one element from the stack. This is the I<count> of items to be sorted. The top I<count> of the remaining elements are then sorted
+from the smallest to the largest, in place on the stack.
-Pop one element from the stack. This is the I<count> of items to be sorted
-(or reversed). The top I<count> of the remaining elements are then sorted
-(or reversed) in place on the stack.
+ 4,3,22.1,1,4,SORT -> 1,3,4,22.1
+
+I<count>,B<REV>
+
+Reverse the number
Example: C<CDEF:x=v1,v2,v3,v4,v5,v6,6,SORT,POP,5,REV,POP,+,+,+,4,/> will
compute the average of the values v1 to v6 after removing the smallest and
largest.
-B<AVG>
+I<count>,B<AVG>
Pop one element (I<count>) from the stack. Now pop I<count> elements and build the
average, ignoring all UNKNOWN values in the process.
Example: C<CDEF:x=a,b,c,d,4,AVG>
-B<MEDIAN>
+I<count>,B<SMIN> and
+I<count>,B<SMAX>
+
+Pop one element (I<count>) from the stack. Now pop I<count> elements and push the minimum/maximum back onto the stack.
+
+Example: C<CDEF:x=a,b,c,d,4,AVG>
+
+I<count>,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
Example: C<CDEF:x=a,b,c,d,4,MEDIAN>
+I<count>,B<STDEV>
+
+pop one element (I<count>) from the stack. Now pop I<count> elements and calculate the standard deviation over these values (ignoring any NAN values). Push the result back on to the stack.
+
+Example: C<CDEF:x=a,b,c,d,4,STDEV>
+
+I<percent>,I<count>,B<PERCENT>
+
+pop two elements (I<count>,I<percent>) from the stack. Now pop I<count> element, order them by size
+(while the smalles elements are -INF, the largest are INF and NaN is larger than -INF but smaller
+than anything else. No pick the element from the ordered list where I<percent> of the elements
+are equal then the one picked. Push the result back on to the stack.
+
+Example: C<CDEF:x=a,b,c,d,95,4,PERCENT>
-B<TREND, TRENDNAN>
+I<count>,B<TREND, TRENDNAN>
Create a "sliding window" average of another data series.
add_op(OP_ATAN, ATAN)
add_op(OP_SQRT, SQRT)
add_op(OP_SORT, SORT)
+ add_op(OP_COUNT, COUNT)
add_op(OP_REV, REV)
add_op(OP_TREND, TREND)
add_op(OP_TRENDNAN, TRENDNAN)
add_op(OP_ADDNAN, ADDNAN)
add_op(OP_MINNAN, MINNAN)
add_op(OP_MAXNAN, MAXNAN)
+ add_op(OP_MEDIAN, MEDIAN)
+ add_op(OP_PERCENT, PERCENT)
+ add_op(OP_SMAX, SMAX)
+ add_op(OP_SMIN, SMIN)
+ add_op(OP_STDEV, STDEV)
add_op(OP_DEPTH, DEPTH)
add_op(OP_COPY, COPY)
add_op(OP_ROLL, ROLL)
add_op(OP_INDEX, INDEX)
+ add_op(OP_POW, POW)
#undef add_op
}
(*str)[offset] = '\0';
match_op(OP_COPY, COPY)
match_op(OP_ROLL, ROLL)
match_op(OP_INDEX, INDEX)
+ match_op(OP_SMAX, SMAX)
+ match_op(OP_SMIN, SMIN)
+ match_op(OP_STDEV, STDEV)
+ match_op(OP_PERCENT, PERCENT)
+ match_op(OP_POW, POW)
#undef match_op
else if ((sscanf(expr, DEF_NAM_FMT "%n", vname, &pos) == 1)
const void *x,
const void *y)
{
- double diff = *((const double *) x) - *((const double *) y);
-
+ /* First catch NaN values. They are smallest */
+ if (isnan(*(double *) x) && isnan(*(double *) y))
+ return 0;
+ if (isnan(*(double *) x))
+ return -1;
+ if (isnan(*(double *) y))
+ return 1;
+ /* NaN doesn't reach this part so INF and -INF are extremes.
+ * The sign from isinf() is compatible with the sign we return
+ */
+ if (isinf(*(double *) x))
+ return isinf(*(double *) x);
+ if (isinf(*(double *) y))
+ return isinf(*(double *) y);
+
+ double diff = *((const double *) x) - *((const double *) y);
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
, rpnstack->s[stptr]);
stptr--;
break;
+ case OP_POW:
+ stackunderflow(1);
+ rpnstack->s[stptr - 1] = pow(rpnstack->s[stptr - 1]
+ , rpnstack->s[stptr]);
+ stptr--;
+ break;
case OP_SIN:
stackunderflow(0);
rpnstack->s[stptr] = sin(rpnstack->s[stptr]);
}
}
break;
+ case OP_STDEV:
+ stackunderflow(0);
+ {
+ int elements = (int) rpnstack->s[stptr--];
+ stackunderflow(elements-1);
+ int n = 0;
+ rrd_value_t mean = 0;
+ rrd_value_t mean2 = 0;
+ while (elements--){
+ rrd_value_t datum = rpnstack->s[stptr--];
+ rrd_value_t delta;
+ if (isnan(datum)){
+ continue;
+ }
+ n++;
+ delta = datum - mean;
+ mean += delta / n;
+ mean2 += delta * (datum - mean);
+ }
+ rpnstack->s[++stptr] = n < 2 ? DNAN : sqrt(mean2 / ( n - 1));
+ }
+ break;
+ case OP_PERCENT:
+ stackunderflow(2);
+ {
+ int elements = (int) rpnstack->s[stptr--];
+ double percent = rpnstack->s[stptr--];
+ if (! (percent >= 0 && percent <=100)){
+ rrd_set_error("percentile argument must be between 0 and 100");
+ return -1;
+ }
+
+ stackunderflow(elements - 1);
+ qsort(rpnstack->s + stptr - elements + 1, elements, sizeof(double),
+ rpn_compare_double);
+ stptr -= elements;
+ rpnstack->s[stptr+1] = rpnstack->s[stptr+(int)round(percent*(double)(elements)/100.0)];
+ stptr++;
+ }
+ break;
+ case OP_SMAX:
+ stackunderflow(0);
+ {
+ rrd_value_t ximum = DNAN;
+ int elements = (int) rpnstack->s[stptr--];
+ stackunderflow(elements - 1);
+ while(elements--){
+ rrd_value_t element = rpnstack->s[stptr--];
+ if (isnan(ximum) || element > ximum) {
+ ximum = element;
+ }
+ }
+ rpnstack->s[++stptr] = ximum;
+ }
+ break;
+ case OP_SMIN:
+ stackunderflow(0);
+ {
+ rrd_value_t ximum = DNAN;
+ int elements = (int) rpnstack->s[stptr--];
+ stackunderflow(elements - 1);
+ while(elements--){
+ rrd_value_t element = rpnstack->s[stptr--];
+ if (isnan(ximum) || element < ximum) {
+ ximum = element;
+ }
+ }
+ rpnstack->s[++stptr] = ximum;
+ }
+ break;
case OP_ROLL:
stackunderflow(1);
{
OP_MINNAN, OP_MAXNAN,
OP_MEDIAN, OP_PREDICTPERC,
OP_DEPTH, OP_COPY, OP_ROLL, OP_INDEX, OP_STEPWIDTH,
- OP_NEWDAY, OP_NEWWEEK, OP_NEWMONTH, OP_NEWYEAR
+ OP_NEWDAY, OP_NEWWEEK, OP_NEWMONTH, OP_NEWYEAR,
+ OP_SMIN, OP_SMAX, OP_STDEV, OP_PERCENT, OP_POW
};
typedef struct rpnp_t {
CDEF:week=myspeed,STEPWIDTH,*,NEWWEEK,0,PREV,IF,ADDNAN \
CDEF:month=myspeed,STEPWIDTH,*,NEWMONTH,0,PREV,IF,ADDNAN \
CDEF:year=myspeed,STEPWIDTH,*,NEWYEAR,0,PREV,IF,ADDNAN \
+ CDEF:avg=myspeed,POP,1,1,1,17,4,AVG \
+ CDEF:smin=myspeed,POP,3,4,5,2.2,4,SMIN \
+ CDEF:smax=myspeed,POP,3,4,5,2.2,4,SMAX \
+ CDEF:med1=myspeed,POP,3,4,5,2.2,4,MEDIAN \
+ CDEF:med2=myspeed,POP,3,4,5,2.2,11,5,MEDIAN \
+ CDEF:stdev=myspeed,POP,3,4,5,2.2,4,STDEV \
+ CDEF:p9=myspeed,POP,0.5,1,1,1,1,1,1,1,5,10,100,10,PERCENT \
+ CDEF:pow=myspeed,2,POW \
XPORT:myspeed:myspeed \
XPORT:day:day XPORT:rday:rday \
XPORT:week:week XPORT:rweek:rweek \
XPORT:month:month XPORT:rmonth:rmonth \
- XPORT:year:year XPORT:ryear:ryear |\
+ XPORT:year:year XPORT:ryear:ryear \
+ XPORT:avg:avg \
+ XPORT:smin:smin \
+ XPORT:smax:smax \
+ XPORT:med1:med1 \
+ XPORT:med2:med2 \
+ XPORT:p9:p9 \
+ XPORT:pow:pow \
+ XPORT:stdev:stdev |\
+
$DIFF9 - $BASEDIR/rpn2.output
report "xport"