XSL - rounding/format-number problem

冷暖自知 提交于 2019-11-27 12:23:29

Not sure why format would be so inconsistent but from memory the spec for it is...complex.

Meantime, you can use the round function (ref). Which is less than perfect, but is functional. If you need to have a particular number of sig figs you can use THE POWER OF MATHS! and do something like:

<xsl:value-of select="round(yournum*100) div 100"/>

I've had endless trouble with decimals in XSLT/XPath 1.0, often a combination of it representing decimals as floating-point numbers and it using half-even rounding (banker's rounding). Unfortunately, the round(yournum*100) div 100 approach didn't work for me, due to floating-point imprecision. For example, multiplying 1.255 by 100 gives 125.49999999999999 (this isn't meant to be implementation dependent, as it's supposed to be IEEE 754, but I don't know if all implementations do adhere to that). When rounded, this then gives 125, rather than the desired 126.

I've taken the following approach, which I think works (although this is always a tricky area so I won't declare too much confidence!). However, it depends on your XSLT engine supporting EXSLT extensions. It presumes you want to round to two decimal places.

<func:function name="local:RoundHalfUp">
    <xsl:param name="number"/>

    <xsl:choose>
        <xsl:when test="contains($number, '.')">
            <xsl:variable name="decimal" select="estr:split($number, '.')[2]"/>
            <xsl:choose>
                <xsl:when test="string-length($decimal) &gt; 2">
                    <func:result select="format-number(concat($number, '1'), '0.00')"/>
                </xsl:when>
                <xsl:otherwise>
                    <func:result select="format-number($number, '0.00')"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
            <func:result select="format-number($number, '0.00')"/>
        </xsl:otherwise>
    </xsl:choose>

</func:function>

which can be called like:

<xsl:value-of select="local:RoundHalfUp(1.255)"/>

The namespaces are:

xmlns:func="http://exslt.org/functions"
xmlns:estr="http://exslt.org/strings"
xmlns:local="http://www.acme.org/local_function"

It's important to note that the function appends a '1', not adds 0.001 or similar.

Definately better to use XSLT 2.0 if it's an option (because it has a proper decimal type), but I know that's often not an option (from painful experience!).

Compared to all above answers i found

<xsl:value-of select="format-number(xs:decimal($quantity), '####0.00')" />

is useful, it is not truncating any decimal point values. truncating exactly specified numbers. if number is in Exponential format we can use as follows:

<xsl:value-of select="format-number(xs:decimal(number($quantity)), '####0.00')" />

Thanks

I've also encountered the issue whereby if you did round($number * 100) div 100 you get a floating point representation of .4999999 and the rounding doesn't work properly.

To get around this, This seems to work: round($number * 1000 div 10) div 100

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!