Built-ins for numbers

Related FAQs: Do you have things like 1,000,000 or 1 000 000 instead of 1000000, or something like 3.14 instead of 3,14 or vice versa? See this and this FAQ entry, also note the c built-in above.

abs

Note:

This built-in exists since FreeMarker 2.3.20.

Gives the absolute value of a number. For example x?abs , if x is -5, will evaluate to 5.

c (when used with numerical value)

Note:

This built-in exists since FreeMarker 2.3.3.

This built-in converts a number to string for a "computer language" as opposed to for human audience. That is, it formats with the rules that programming languages used to use, which is independent of all the locale and number format settings of FreeMarker. It always uses dot as decimal separator, and it never uses grouping separators (like 3,000,000), nor exponential form (like 5E20), nor superfluous leading or trailing 0-s (like 03 or 1.0), nor + sign (like +1). It will print at most 16 digits after the decimal dot, and thus numbers whose absolute value is less than 1E-16 will be shown as 0. This built-in is crucial because be default (like with ${x}) numbers are converted to strings with the locale (language, country) specific number formatting, which is for human readers (like 3000000 is possibly printed as 3,000,000). When the number is printed not for human audience (e.g., for a database record ID used as the part of an URL, or as invisible field value in a HTML form, or for printing CSS/JavaScript numerical literals) this built-in must be used to print the number (i.e., use ${x?c} instead of ${x}), or else the output will be possibly broken depending on the current number formatting settings and locale (like the decimal point is not dot, but comma in many countries) and the value of the number (like big numbers are possibly "damaged" by grouping separators).

If the incompatible_improvements FreeMarker configuration setting is set to 2.3.24 or higher (also if it's set to 2.3.20 or higher and you are outside a string literal), this built-in will return "INF", "-INF" and "NaN" for positive/negative infinity and IEEE floating point Not-a-Number, respectively. These are the XML Schema compatible representations of these special values. (Earlier it has returned what java.text.DecimalFormat did with US locale, none of which is understood by any (common) computer language.)

Note that this built-in also works on booleans.

is_infinite

Note:

This built-in exists since FreeMarker 2.3.20.

Tells if a number is floating point infinite (according to IEEE 754). For example, someNumber?is_infinite evaluates to true or false depending on if the value of someNumber is infinite or not. Of course, if the underlying number is not of floating point type, this will always return false.

is_nan

Note:

This built-in exists since FreeMarker 2.3.20.

Tells if a number is floating point NaN (according to IEEE 754). For example, someNumber?is_nan evaluates to true or false depending on if the value of someNumber is NaN or not. Of course, if the underlying number is not of floating point type, this will always return false.

lower_abc

Note:

This built-in exists since FreeMarker 2.3.22.

Converts 1, 2, 3, etc., to the string "a", "b", "c", etc. When reaching "z", it continues like "aa", "ab", etc. This is the same logic that you can see in column labels in spreadsheet applications (like Excel or Calc). The lowest allowed number is 1. There's no upper limit. If the number is 0 or less or it isn't an integer number then the template processing will be aborted with error.

Example:

<#list 1..30 as n>${n?lower_abc} </#list>

Prints:

a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad 

See also: upper_abc

round, floor, ceiling

Note:

The rounding built-ins exist since FreeMarker 2.3.13.

Converts a number to a whole number using the specified rounding rule:

  • round: Rounds to the nearest whole number. If the number ends with .5, then it rounds upwards (i.e., towards positive infinity)

  • floor: Rounds the number downwards (i.e., towards neagative infinity)

  • ceiling: Rounds the number upwards (i.e., towards positive infinity)

Example:

<#assign testlist=[
  0, 1, -1, 0.5, 1.5, -0.5,
  -1.5, 0.25, -0.25, 1.75, -1.75]>
<#list testlist as result>
    ${result} ?floor=${result?floor} ?ceiling=${result?ceiling} ?round=${result?round}
</#list>

Prints:

    0 ?floor=0 ?ceiling=0 ?round=0
    1 ?floor=1 ?ceiling=1 ?round=1
    -1 ?floor=-1 ?ceiling=-1 ?round=-1
    0.5 ?floor=0 ?ceiling=1 ?round=1
    1.5 ?floor=1 ?ceiling=2 ?round=2
    -0.5 ?floor=-1 ?ceiling=0 ?round=0
    -1.5 ?floor=-2 ?ceiling=-1 ?round=-1
    0.25 ?floor=0 ?ceiling=1 ?round=0
    -0.25 ?floor=-1 ?ceiling=0 ?round=0
    1.75 ?floor=1 ?ceiling=2 ?round=2
    -1.75 ?floor=-2 ?ceiling=-1 ?round=-2

These built-ins may be useful in pagination operations and like. If you just want to display numbers in rounded form, then you should rather use the string built-in or the number_format setting.

string (when used with a numerical value)

Converts a number to a string. In its simplest form (expression?string) it uses the default format that the programmer has specified via the number_format and the locale configuration settings. You can also specify a number format explicitly with this built-in, as it will be shown later.

There are four predefined number formats: computer, currency, number, and percent. The exact meaning of these is locale (nationality) specific, and is controlled by the Java platform installation, not by FreeMarker, except for computer, which uses the same formatting as the c built-in. There can also be programmer-defined formats, whose name starts with @ (programmers see more here...). You can use these predefined formats like this:

<#assign x=42>
${x}
${x?string}  <#-- the same as ${x} -->
${x?string.number}
${x?string.currency}
${x?string.percent}
${x?string.computer}

If your locale is US English, this will print:

42
42
42
$42.00
4,200%
42

The output of first three expressions is identical because the first two expressions use the default format, which is "number" here. You can change this default using a setting:

<#setting number_format="currency">
<#assign x=42>
${x}
${x?string}  <#-- the same as ${x} -->
${x?string.number}
${x?string.currency}
${x?string.percent}

Will now output:

$42.00
$42.00
42
$42.00
4,200%

since the default number format was set to "currency".

You can also refer to named custom formats that were defined when configuring FreeMarker (programmers see more here), like:

${x?string.@price}
${x?string.@weight}

where the custom format names were "price" and "weight". This way the templates can just refer to the application-domain meaning, and the exact format can be specified outside the templates, on a single central place. (Programmers can read about defining such named formats here...)

Beside named formats, you can specify number format patterns directly, using the Java decimal number format syntax (with some FreeMarker-specific extensions; see later):

<#assign x = 1.234>
${x?string["0"]}
${x?string["0.#"]}
${x?string["0.##"]}
${x?string["0.###"]}
${x?string["0.####"]}

${1?string["000.00"]}
${12.1?string["000.00"]}
${123.456?string["000.00"]}

${1.2?string["0"]}
${1.8?string["0"]}
${1.5?string["0"]} <-- 1.5, rounded towards even neighbor
${2.5?string["0"]} <-- 2.5, rounded towards even neighbor

${12345?string["0.##E0"]}
1
1.2
1.23
1.234
1.234

001.00
012.10
123.46

1
2
2 <-- 1.5, rounded towards even neighbor
2 <-- 2.5, rounded towards even neighbor

1.23E4

Note that as in FreeMarker foo.bar is equivalent with foo["bar"], you could also write x?string.currency as x?string["currency"], but of course that wouldn't be practical. But in the above examples we have to use the square bracket syntax, because the characters involved (numbers, dot, #) aren't allowed syntactically after the dot operator.

For historical reasons, you could also write things like x?string("0.#"), which does exactly the same as x?string["0.#"].

Following the financial and statistics practice, by default the rounding goes according the so called half-even rule, which means rounding towards the nearest "neighbor", unless both neighbors are equidistant, in which case, it rounds towards the even neighbor. This was visible in the above example if you look at the rounding of 1.5 and of 2.5, as both were rounded to 2, since 2 is even, but 1 and 3 are odds. The other popular rounding rule, where we always round up when the neighbors are equidistant (and so 2.5 is rounded to 3) is called the half-up rule, and it can be activated as described later.

As it was shown for the predefined formats earlier, the default formatting of the numbers can be set in the template:

<#setting number_format="0.##">
${1.234}
1.23

The default number format also can be specified outside the templates with the FreeMarker API (like with Configuration.setNumberFormat(String)).

Note that as number formatting is locale sensitive, the locale setting also plays role in the formatting:

<#setting number_format=",##0.00">
<#setting locale="en_US">
US people write:     ${12345678}
<#setting locale="de_DE">
German people write: ${12345678}
US people write:     12,345,678.00
German people write: 12.345.678,00

Extended Java decimal format

Note:

You need at least FreeMarker 2.3.24 for these to work. Before that, extended Java decimal format parts are just silently ignored by java.text.DecimalFormat.

FreeMarker extends the Java decimal format patterns with extra options. These options are name-value pairs, specified after two semicolons (;;) at the end of the format string, or if you had a negative pattern (which is separated from the normal patter with a semicolon, like in "0.0;minus 0.0"), the after only one semicolon. For example:

Standard decimal format: ${10002.5?string[",000"]}
Extended decimal format: ${10002.5?string[",000;; roundingMode=halfUp groupingSeparator=_"]}
Standard decimal format: 10,002
Extended decimal format: 10_003
Warning!

A very easy mistake to make is just using a single semicolon instead of two. It won't even result in an error, as java.text.DecimalFormat thinks you have just specified some weird format for negative numbers. So remember to use two semicolons.

Above, in the extended decimal format, we have specified half-up rounding mode and group separator "_". The table of all options follows (note that these are defined by java.text.DecimalFormat and java.text.DecimalFormatSymbols, not by FreeMarker):

Name Meaning / value
roundingMode The value is one of up, down, ceiling, floor, halfUp, halfDown, halfEven, and unnecessary. The behavior that most people learns in school is halfUp, but the Java default is halfEven (also called bankers' rounding). (See the java.math.RoundingMode API for explanations.)
multiplier since 2.3.29; multipier since 2.3.24 The number will be shown after multiplied with this integer number.
decimalSeparator The character separating the integer part from the fraction part (like "." in 3.14).
monetaryDecimalSeparator This is used instead of decimalSeparator when the pattern contains parts that make it a monetary format. (See the Java decimal number format documentation for more.)
groupingSeparator The single character used for grouping the integer part (like "," in 1,000,000) Note that grouping is turned on by using "," in the pattern, as shown in the earlier example. If it's not turned on, this option won't have visible effect.
exponentSeparator This string (of arbitrary length) is used to separate the exponent from the part before it. (like "E" in 1.23E6). Only has visible effect if the pattern specifies exponential (also known as scientific) format, like "0.##E0".
minusSign The single character used as minus sign (like "-" in -1).
infinity The string (of arbitrary length) used to show infinity.
nan The string (of arbitrary length) used to show not-a-number (NaN).
percent The single character used as the percent symbol (like "%" in 50%). Only has visible effect if the pattern contains %.
perMill The single character used as the per-mill symbol (like "‰" in 50021‰). Only has visible effect if the pattern contains .
zeroDigit The first character in the 10 character range (of character codes) that contains the digits to be used. For example, if this is A, then 1 will B, 2 will be C, and so on.
currencyCode Currency ISO 4217 code. Only has effect when the pattern contains parts that make it a monetary format. It's an error to specify a code that's not a known ISO 4217 code in the Java installation.
currencySymbol Currency symbol; shown where the localized currency name is present in the pattern. Overrides the symbol determined based on the currencyCode.

Regarding the syntax of the options:

  • The option name and value are separated by equals character (=).

  • Options are separated by whitespace and/or optional comma (,)

  • The option value can be quoted with apostrophe (') or normal quotation mark (") , like exponentSeparator='*10^' or exponentSeparator="*10^". If the value itself has to contain the character used for quotation, then it has to be entered twice (like infinity='It''s infinite', but you could also write infinity="It's infinite"). Backslash has no special meaning.

  • Non-string values must not be quoted. Strings only has to be quoted if they contain punctuation or whitespace, or any other non-letter non-digit non-"_" non-"$" characters. Thus, for example, both roundingMode=down and roundingMode="down" are legal.

upper_abc

Note:

This built-in exists since FreeMarker 2.3.22.

Same as lower_abc, but converts to upper case letters, like "A", "B", "C", …, "AA", "AB", etc.