GNOME Bugzilla – Bug 465747
Wrong number comparison in XPath expression including sum()
Last modified: 2007-08-13 01:05:07 UTC
<?xml version="1.0" encoding="UTF-8"?> <!-- This file shows a bug in the xmlstarlet comand line utility, that itself uses libxml2 and libxslt. Used with libxslt v1.1.21 and libxml2 v2.6.29 The expression '//T[V!=(AV+sum(As/A/M))]' will find select records for which the expression is not true! Here the used command line: xml sel -t -m '//T[V!=(AV+sum(As/A/M))]' -v V -o ' | ' -v AV -o ' | ' -v 'AV+sum(As/A/M)' -n bug.xml It will select records that match the expression //T[V!=(AV+sum(As/A))] and then show the value of 'V' of 'AV' and of 'AV+sum(As/A/M)' --> <D> <!-- Elements that are wrongly selected and demonstrate the issue. --> <!-- Shows: 268.09 | 266.99 | 268.09 How comes that the record is matched if the calculation of AV + sum(As/A/M) equals to V? --> <T> <V>268.09</V> <AV>266.99</AV> <As> <A> <M>1.1</M> </A> </As> </T> <!-- Shows: 21.12 | 16.63 | 21.12 How comes that the record is matched if the calculation of AV + sum(As/A/M) equals to V? --> <T> <V>21.12</V> <AV>16.63</AV> <As> <A> <M>4.49</M> </A> </As> </T> <!-- Shows: 81.88 | 71.76 | 81.88 The calculation of AV + sum(As/A/M) equals to V therefore this record should not be selected --> <T> <V>81.88</V> <AV>71.76</AV> <As> <A> <M>10.12</M> </A> </As> </T> <!-- Shows: 7.95 | 6.05 | 7.949999999999999 This record is apparenbtly matched because the calculation of AV + sum(As/A/M) equals to 7.949999999999999 instead to 7.95 --> <T> <V>7.95</V> <AV>6.05</AV> <As> <A> <M>1.9</M> </A> </As> </T> <!-- This is a strange case, it shows correctly for the explained expression: 10.36 | 8.96 | 10.36 But for an expression that uses a substraction it will show: 10.36 | 8.96 | 8.959999999999999 Here the expression for the substraction: xml sel -t -m '//T[AV!=(V - sum(As/A/M))]' -v V -o ' | ' -v AV -o ' | ' -v 'V - sum(As/A/M)' -n bug.xml --> <T> <V>10.36</V> <AV>8.96</AV> <As> <A> <M>1.4</M> </A> </As> </T> <!-- Positive examples, i.e. they are detected correctly --> <!-- Shows: 62.39 | 60.52 | 64.26 --> <T> <V>62.39</V> <AV>60.52</AV> <As> <A> <M>1.87</M> </A> <A> <M>1.87</M> </A> </As> </T> <!-- Shows: 237.95 | 226.05 | 249.85 --> <T> <V>237.95</V> <AV>226.05</AV> <As> <A> <M>11.9</M> <M>11.9</M> </A> </As> </T> </D>
Created attachment 93503 [details] XML file allowing to show this bug The same file as in the bug text
I have tasted it also with different Linux and Windows versions of xmlstarlet that use an older version of libxslt, so it seems to be platform independent.
You have an incorrect expectation. Whenever floating point arithmetic is performed in a program (and that includes the conversion from Ascii text into binary double within XPath), there is a high probability that "rounding errors" will occur. Your "select" statement is testing for inequality, i.e. two floating point numbers are not *exactly* (bit-for-bit) equal, and this will usually be true even though the numbers being compared differ by only the rounding error.
Hello William, it might be that it is a rounding error (at least the examples 4 and 5 show this clearly), nevertheless the same examples work correctly with another XML tool (Stylus Studio). I find the xmlstarlet utility very handy for scripted tests, but we stumbled about this. The strange thing is that the rounding error appears only in two examples (records 4 and 5) for all the others the cast back to a string has the same value. In any case it is in the your hands to consider this as a bug or not. I'd appreciate if you could give a hint how to obtain correct results for the expected verification. With best regards, Robert
I cannot comment on the internals of Stylus Studio, but for libxml2 XPath works internally with "doubles", and that is what is behind the behaviour which you describe as a "bug". There are many (good) reasons why libxml2 has chosen to implement it's XPath in this way, and it will not be changed. If you have some doubt about whether "rounding error" explains your other test cases, try the following program: #include <stdio.h> #include <stdlib.h> int main(int nargs, char **argv) { char *cV = "268.09", *cAV = "266.99", *cM = "1.1"; double V, AV, M; AV = atof(cAV); V = atof(cV); M = atof(cM); if (V != (AV + M)) { printf("Differs: V = %f, AV = %f, M = %f\n" "Error is %e\n", V, AV, M, V - (AV + M)); } else { printf("Values are equal\n"); } return 0; } On my testing system (i686) this yields: [bill@bbsuper bug465747]$ ./test Differs: V = 268.090000, AV = 266.990000, M = 1.100000 Error is -3.419487e-14 As far as implementing your verification, from a general computational point of view you should check that the absolute difference between the value found and the value expected is less than some constant (e.g. abs(V - (AV+sum(As/A/M))) < .00000001 From an XPath perspective, however, this is not an easy thing to do. In any event, this is not a bug.