At computing a resulting price (of percentage-based services) I was using a combination of Mul() and NormalRound(). The computation takes a place i a datastructure rulset
AS:NormalRound(AS:Mul(@percentage, @basePrice), 0)
@percentage
and @basePrice
are decimals in the db, as well as the result field
For some reason it used to work for a long time, however, suddenly it started to fail, but only in PROD environment:
Function 'AS:NormalRound()' has failed. ---> System.FormatException: Input string was not in a correct format.
at System.Number.ParseDouble(String value, NumberStyles options, NumberFormatInfo numfmt)
at System.String.System.IConvertible.ToDouble(IFormatProvider provider)
at CZ.Advantages.Asap.Rule.NormalRoundFunction.Invoke(XsltContext xsltContext, Object[] args, XPathNavigator docContext)
Here obviously AS:Mul()
didn’t fail. Mul()
produces decimal output, but the way it’s not convertible to double (When I removed AS:NormalRound it started to work). It was quite hell to find out the reason since it appeared only at production and I thought it’s because of the data.
Anyway I looked at NormalRound() and found out it uses floating point (double) arithmetic, and so maybe it’s anyway wrong.
Or to use some home brew round solution (as Kit4it suggested at Number formatting (currency))
round(AS:Mul(@AmountInvoiceCurrency,@Rate) * 100) div 100
(corresponds to http://stackoverflow.com/questions/3805248/xsl-rounding-format-number-problem)
So maybe when we use AS:Div() instead of div it’s almost perfect (provided that xsl round() works well with really high/low numbers.
I think the most proper way for the time being is to use AS:AsapRound, in my case
AS:AsapRound(AS:Mul(@percentage, @basePrice), '0b58b6b8-5d68-42bd-bf23-c698a9c78cbf')
And somewhere to define the precision… It seems to me quite cumbersome.
Or am I missing something?
I would personally extend funciton AS:NormalRound
so it accepts the second optional parameter ‘arithmetic’ (either ‘double’, or ‘decimal’). Or to add a new function DecimalRound.