Jinja round() function gives results which may be unexpected

Compare results:

{{5.4|round(0)}}
{{5.5|round(0)}}
{{5.6|round(0)}}

{{10.4|round(0)}}
{{10.5|round(0)}}
{{10.6|round(0)}}

{{100.4|round(0)}}
{{100.5|round(0)}}
{{100.6|round(0)}}

Same with using “float”:

Also this:

So, for values >10 rounding may give wrong results for “10.5” and correct results for “10.55”.

Seems that rounding is similar to “banking rounding”…
Not sure that this is correct.

1 Like

I think it’s down to the method that round uses and Floating Point Issues:

…values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done toward the even choice (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2).

Note: The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.

Built-in Functions — Python 3.10.13 documentation

1 Like

I saw it.
But this is a merely short description how it is implemented.
The question is “why to use a non-precise processing”?
I would call this “weird”:

As for this:
I never dealt with a Python, but in C/C++ rounding always gives correct results…

There’s nothing incorrect in your results above.

When the decimal is 0.5 which way do you round?

It is equally close to 0 and 1.

If you just pick up or down you might introduce a bias in results.

By rounding even up and odd down this is less likely to happen.

This is agreed, but in mathematics rounding “0.5” is always “up”…
Probably it should be the 4th method - “up”, “down”, current “even/odd” and “mathematical”.

1 Like

Can you give a source for that?

It was certainly how I was taught (in the UK).

These links aren’t official, but shows that people do do it this way.
https://www.calculateme.com/number-rounding/0.5/

https://www.mathsisfun.com/numbers/rounding-methods.html

1 Like

I was also taught in USSR school:
23.4 → 23
23.5 → 24
23.6 → 24

Well, I would rename the thread - seems that probably different methods are used…

Yes, exactly that.

I assume this convention differs around the world and/or across fields.
I would prefer .5 to round up because I am comfortable with it, but it’s not critical.

To be honest, I assumed that it was rounding up until I saw this thread!

Just to add to this, in finance 0.5 rounds up except when dealing with tax, when it rounds down.

However, apparently in some finance circumstances, 0.499999999 might also round up and 0.500000001 might round down.

What a crazy world we live in :grin:

1 Like

According to the documentation, if no rounding mode is specified it will default to ‘round-to-even’ (which behaves differently from ‘ceiling’).

Round function

The documentation includes a link to the following Wikipedia article explaining how ‘round half to even’ works:

2 Likes

Thanks for the link. Also, the “ceiling” method is not same as what I expected:

23.4 → 23
23.5 → 24
23.6 → 24

, the “ceiling” method will give us:

23.4 → 24
23.5 → 24
23.6 → 24

“My method” is called in Wikipedia as “Rounding half away from zero” (or “commercial”).

1 Like

New Zealand schools too.

Is there a way to have this without own calculating via special function or parameter? Didn’t find such. Wonder there is no other already asking/implemented it.

Rounding half away from zero

One may also round half away from zero (or round half toward infinity), a tie-breaking rule that is commonly taught and used, namely: If the fractional part of x is exactly 0.5, then y = x + 0.5 if x is positive, and y = x − 0.5 if x is negative.

For example, 23.5 gets rounded to 24, and −23.5 gets rounded to −24.

This method, also known as commercial rounding treats positive and negative values symmetrically, and therefore is free of overall positive/negative bias if the original numbers are positive or negative with equal probability. It does, however, still have bias away from zero.

So more or less a simpler way or a simple parameter to get this

{% set val = "-0.4" %}
{% set val = val|float %}

{% if val > 0 %}
  {% if val % 1 >= 0.5 %}
    {% set val = val|round(0,"ceil") %} 
  {% else %}
    {% set val = val|round(0,"floor") %} 
  {% endif %}
{% else %}
  {% if val % 1 > 0.5 %}
    {% set val = val|round(0,"ceil") %}
  {% else %}
    {% set val = val|round(0,"floor") %}
  {% endif %}
{% endif %}

{{ val }}

or

{% set val = "1.4" %}
{% set val = val|float %}

{% set val = ((val>0)-(val<0))*(val|abs+0.5)|int %}

{{ val }}
1 Like