Rounding Numbers to a Specified Precision

Problem

You want to round to a specific number of decimal places; however, XSLT’s round, ceiling, and floor functions always map numbers to integer values.

Solution

Multiply, round, and divide using a power of ten that determines how many decimal digits are required. Assuming $pi = 3.1415926535897932:

<xsl:value-of select="round($pi * 10000) div 10000"/>

results in 3.1416. Similarily:

<xsl:value-of select="ceiling($pi * 10000) div 10000"/>

results in 3.1416, and:

<xsl:value-of select="floor($pi * 10000) div 10000"/>

results in 3.1415.

Rounding to a specific number of decimal places is also achieved using format-number( ):

<xsl:value-of select="format-number($pi,'#.####')"/>

This results in 3.1416. This will work even if more than one significant digit is in the whole part because format-number never uses a format specification as an indication to remove significant digits from the whole part:

<xsl:value-of select="format-number($pi * 100,'#.####')"/>

This results in 314.1593.

You can use format-number to get the effect of truncating rather than rounding by using one more formatting digit than required and then chopping off the last character:

<xsl:variable name="pi-to-5-sig" select="format-number($pi,'#.#####')"/>
<xsl:value-of select="substring($pi-to-5-sig,1,string-length($pi-to-5-sig) -1)"/>

This results in 3.1415.

Discussion

This multiply, round, and divide technique works well as long as the numbers involved remain within the representational limits of IEEE floating point. If you try to capture too many places after the decimal, then the rules of IEEE floating point will interfere with the expected result. For example, trying to pick up 16 decimal digits of pi will give you only 15:

<xsl:value-of select="round($pi * 10000000000000000) div 10000000000000000"/>

This results in 3.141592653589793, not 3.1415926535897932.

An alternative technique manipulates the number as a string and truncates:

<xsl:value-of select="concat(substring-before($pi,'.'),
                       '.', 
                       substring(substring-after($pi,'.'),1,4))"/>

and results in 3.1415.

The effect of ceiling or round can be obtained by this technique at the cost additional complexity.

<xsl:variable name="whole" select="substring-before($pi,'.')"/>
<xsl:variable name="frac" select="substring-after($pi,'.')"/>
<xsl:value-of select="concat($whole,
                       '.', 
                       substring($frac,1,3),
                    round(substring($frac,4,2) div 10))"/>

This results in 3.1416.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset