java - Incorrect multiplication result by XSLT with javax.xml.transform (0.2*0.8*0.8) -


i have xslt below:

<?xml version="1.0" encoding="utf-8"?>  <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="xml" encoding="utf-8" indent="yes"/>  <xsl:template match="test">          <result>             <xsl:value-of select="number(depth)*number(width)*number(height)"/>         </result>   </xsl:template> 

when test xslt against below sample file in altova xml or in w3cschool here, result 0.128

sample file:

<?xml version="1.0" encoding="utf-8"?> <test> <depth>.8</depth> <width>.8</width> <height>.2</height> </test> 

however, things change when use java invoke xslt. result

<result>0.12800000000000003</result> 

below simple code i'm using:

 import javax.xml.transform.*;     import javax.xml.transform.stream.streamresult;     import javax.xml.transform.stream.streamsource;     import java.io.file;     import java.io.ioexception;     import java.net.urisyntaxexception;  public class testmain {     public static void main(string[] args) throws ioexception, urisyntaxexception, transformerexception {         transformerfactory factory = transformerfactory.newinstance();         source xslt = new streamsource(new file("transform.xslt"));         transformer transformer = factory.newtransformer(xslt);          source text = new streamsource(new file("input.xml"));         transformer.transform(text, new streamresult(new file("output.xml")));     } } 

question: why java code giving output 0.12800000000000003? 0.12800000000000000 understandable, 0.12800000000000003 incorrect calculation.

firstly, floating point arithmetic in general produce such rounding errors, because numbers 0.8 cannot represented accurately in value space of xs:double.

secondly, stylesheet explicitly using number() function, converts values in source document (like 0.8) floating point, both in xslt 1.0 , xslt 2.0. xslt 2.0 offers solution in replace call number() call on xs:decimal(), give decimal arithmetic rather binary floating-point, , avoid rounding errors. code executing doing floating-point arithmetic in both cases.

the correct answer expression according rules of w3c specification in both 1.0 , 2.0 in fact 0.12800000000000003. specification not give leniency on this. implementors take short-cuts, , use libraries floating-point arithmetic (and more particularly, number-to-string conversion) not written follow w3c rules. suspect implementation outputs 0.128 query using number-to-string conversion routine trying smarter w3c spec allows.

if want avoid kind of rounding error, correct approach is:

(a) xslt 1.0, use format-number() format output number of decimal places accurate (or needed)

(b) xslt 2.0, use xs:decimal arithmetic - when reading numbers source document means explicitly making them xs:decimal, either validating source document against schema declares type xs:decimal, or using xs:decimal() function in stylesheet.


Comments

Popular posts from this blog

java - Jasper subreport showing only one entry from the JSON data source when embedded in the Title band -

serialization - Convert Any type in scala to Array[Byte] and back -

SonarQube Plugin for Jenkins does not find SonarQube Scanner executable -