1

I need to format some numbers without rounding them and also add two 0s if they are integers as follows.

given : 10.20 , result : 10.20 given : 10.56556, result : 10.56 given : 65000 , result : 65000.00

This is what I have so far:

<cfscript>
vars = {};
vars.rate = 10.20;     // should yield to : 10.20
//vars.base_salary = 10.56556; // should yield to : 10.56
//vars.base_salary = 65000;    // should yield to : 65000.00



vars.formatted1 = trim(numberFormat((vars.rate * 100) / 100, "__________.__"));
vars.formatted2 = trim(numberFormat(int(vars.rate * 100) / 100, "__________.__"));

vars.formatted3 = NumberFormat((ceiling(vars.rate*100)/100), '9.99');

writeDump(vars);
</cfscript>

Notice, formatted2 for 10.20 yields to 10.19, which is not correct. any help?

CFNinja
  • 3,571
  • 4
  • 38
  • 59
  • (Edit) A) Since it looks like you are representing currency, why are you using [floating point numbers](http://stackoverflow.com/questions/2002821/why-does-this-subtraction-not-equal-zero)? When precision is important, never use "approximate" types. Instead use BigDecimal, `PrecisionEvaluate()`, etcetera. B) While possible, why round down? That is a bit atypical for currency. – Leigh Jan 11 '17 at 01:06
  • @Leigh, a) they are currency indeed. The application code that I have inherited is creating decimals, which is a long story. b) The "management" decision was not to round them up, but just cut them 2nd digit after the decimal. Again, I have had no say in that. Interesting thing is that this only fails for 10.20, and works fine for say 9.20 ,11.20 or any other number i tested so far : trim(numberFormat(int(vars.rate * 100) / 100, "__________.__")) – CFNinja Jan 11 '17 at 17:14
  • *this only fails for 10.20, and works fine for say* That is because CF uses an approximate type, ie double. So it will always happen with certain numbers because *...[certain] decimal numbers that "look" round in base 10, are not exactly representable in base 2*. For example if you multiply `10.20 * 100`, you would expect to see "1020". Due to the use of approximate types, what you actually get is something like `1019.999999...` http://trycf.com/gist/90a8b072eb63e87a7b54975f3b075e37/acf2016?theme=monokai – Leigh Jan 11 '17 at 19:28

1 Answers1

2

Since it looks like you are representing currency, do not use floating point numbers. CF typically uses Double to represent numbers (and when formatting with NumberFormat) which is an approximate type. Do not use approximate types when precision is important, like with currency. Instead use BigDecimal and functions like PrecisionEvaluate().

Without more details, I would ask why truncate the numbers? Though possible, it is a bit atypical for currency. At least for U.S. currency which is usually rounded using HALF_EVEN:

.. round[s] towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor....

That said, to answer the question you can truncate the numbers by creating a BigDecimal. Then using setScale() to specify the desired number of decimal places and override the default rounding mode.

NB: Be sure to read the docs on RoundingMode so you fully understand how it handles various values

Example:

doubleValue = 10.56556;
mode = createObject("java", "java.math.RoundingMode");
decimalValue = javacast("bigdecimal", doubleValue).setScale(2, mode.DOWN);
writeOutput("decimalValue = "& decimalValue);

Results:

decimalValue = 10.20
decimalValue = 10.56
decimalValue = 6500.00
Community
  • 1
  • 1
Leigh
  • 28,765
  • 10
  • 55
  • 103