[rrd-developers] Wrong behaviour or not?
Alex van den Bogaerdt
alex at ergens.op.het.net
Fri Mar 7 05:38:05 CET 2008
Hi,
This seems wrong to me:
CDEF:y=x,b,c,IF
When x is anything but zero, b is returned. Anything includes NaN here.
The problem seems to be in the way C handles NaN comparisons in
combination with this code:
if (x != 0.0) ...
which does indeed branch to TRUE.
(similar code is in rrd_rpncalc.c, case OP_IF: )
I did a quick test:
(crappy C code attached)
Using != 0:
x==nan -> True
x==inf -> True
x==-inf -> True
x==1.000000 -> True
x==0.500000 -> True
x==0.000000 -> False
x==-0.500000 -> True
Comparing to greater than zero also doesn't work out nicely,
as it doesn't handle negative numbers. Otherwise it is much
better (IMHO!) than the current situation.
Using > 0:
x==nan -> False
x==inf -> True
x==-inf -> False
x==1.000000 -> True
x==0.500000 -> True
x==0.000000 -> False
x==-0.500000 -> False
If we only look at NaN, True or False (UNKN,0,1), we get:
Using != 0:
x==nan -> True
x==1.000000 -> True
x==0.000000 -> False
Using any of the three alternatives in my code:
x==nan -> False
x==1.000000 -> True
x==0.000000 -> False
I believe the latter to be more correct. As mentioned, this does
not handle "negative true".
There's an even better alternative. Replace "x!=0.0?true:false"
with "finite(x)?x?true:false:false"
Using finite and boolean:
x==nan -> False
x==inf -> False
x==-inf -> False
x==1.000000 -> True
x==0.500000 -> True
x==0.000000 -> False
x==-0.500000 -> True
A variant which considers infinite to be boolean true:
"isnan(x)?false:x?true:false"
Using isnan and boolean:
x==nan -> False
x==inf -> True
x==-inf -> True
x==1.000000 -> True
x==0.500000 -> True
x==0.000000 -> False
x==-0.500000 -> True
Another obvious alternative is to propagate NaN, perhaps something
like this (untested!):
case OP_IF:
if (! isnan(rpnstack -> s[stptr-2]))
rpnstack->s[stptr-2] = rpnstack->s[stptr-2] != 0.0 ?
rpnstack->s[stptr-1] : rpnstack->s[stptr];
stptr-=2;
break;
Comments?
-------------- next part --------------
#include <stdio.h>
#include <math.h>
#define NAN_FUNC (double)(0.0/0.0)
#define INF_FUNC (double)(1.0/0.0)
#define NEGINF_FUNC (double)(-1.0/0.0)
void do_test1(double input) {
printf("x==%lf -> %s\n",input,input!=0.0?"True":"False");
}
void do_test2(double input) {
printf("x==%lf -> %s\n",input,input>0.0?"True":"False");
}
void do_test3(double input) {
printf("x==%lf -> %s\n",input,finite(input)?input?"True":"False":"False");
}
void do_test4(double input) {
printf("x==%lf -> %s\n",input,isnan(input)?"False":input?"True":"False");
}
int main(void) {
double x;
printf("Using != 0:\n");
do_test1(NAN_FUNC);
do_test1(INF_FUNC);
do_test1(NEGINF_FUNC);
do_test1(2.0/2.0);
do_test1(1.0/2.0);
do_test1(0.0/2.0);
do_test1(-1.0/2.0);
printf("\nUsing > 0:\n");
do_test2(NAN_FUNC);
do_test2(INF_FUNC);
do_test2(NEGINF_FUNC);
do_test2(2.0/2.0);
do_test2(1.0/2.0);
do_test2(0.0/2.0);
do_test2(-1.0/2.0);
printf("\nUsing finite and boolean:\n");
do_test3(NAN_FUNC);
do_test3(INF_FUNC);
do_test3(NEGINF_FUNC);
do_test3(2.0/2.0);
do_test3(1.0/2.0);
do_test3(0.0/2.0);
do_test3(-1.0/2.0);
printf("\nUsing isnan and boolean:\n");
do_test4(NAN_FUNC);
do_test4(INF_FUNC);
do_test4(NEGINF_FUNC);
do_test4(2.0/2.0);
do_test4(1.0/2.0);
do_test4(0.0/2.0);
do_test4(-1.0/2.0);
return 0;
}
More information about the rrd-developers
mailing list