I have noticed some strange precision behaviour that I cannot understand, I have some XML:
<CLD>
<UCRV>
<UCR1>.07</UCR1>
</UCRV>
</CLD>
And in an XSLT file, I am selecting the value as pence (or 100 pence as it seems, I don't know why but it's what the customer wants!) as:
<xsl:value-of select="./s0:CLD/s0:UCRV/s0:UCR1/text() * 100 * 100"/>
But this is output as 700.00000000000011 The data type is xsd:Decimal. Is there some default precisioning going on here? I can simply round the number but I just wanted to understand it a bit better.
Thanks
Floating point numbers can't represent everything precisely. Since the numbers are stored in binary form, numbers that seem to be easy to write in decimal can be actually only approached in binary sometimes. This is the case with 0.07, it's stored internally as 0.070000000000000011 as it seems in your case. As a rule of thumb, you should never trust floating point values so as to compare them directly without rounding.
As people already explained, the only numeric type used in XPath is xs:double.
The number()
function converts a value to a double. Therefore, operations on numbers in XPath 1.0 can and sometimes do lead to loss of precision.
There exist different solutions:
Use the round()
function. One can also use the floor()
or the ceiling()
functions.
Use the XSLT format-number()
function() or the <xsl:number>
instruction.
Do note that XPath 2.0 supports all XSD numeric types, including xs:decimal
. An XPath 2.0 expression that doesn't cause loss of precision is:
xs:decimal(0.07)*100*100
This is standard floating point maths. In this there is a maximun number of bits to fit the number and the number is held in scientific form in binary. Here 0.07 cannot be represented exactly and is held as 0.070000000000000011.
For more see many questions on SO (albeit in other languages) using tag floating-point, wikipedia and What Every Computer Scientist Should Know About Floating-Point Arithmetic
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With