diff --git a/mo/util_format.py b/mo/util_format.py
index 6ed6a48591fafb6b5f4f950e663dc06f78452286..7b20df1ca28b965a0c012909aa50377e20125c95 100644
--- a/mo/util_format.py
+++ b/mo/util_format.py
@@ -1,6 +1,7 @@
 # Utils that do not depend on any other in mo (to avoid circular dependency)
 
 from datetime import datetime
+import decimal
 from typing import Optional
 
 import mo
@@ -120,3 +121,12 @@ def data_size(bytes: int) -> str:
         return f'{bytes/(1<<20):.1f} MiB'
     else:
         return f'{bytes/(1<<10):.1f} KiB'
+
+
+def format_decimal(points: Optional[decimal.Decimal]) -> Optional[str]:
+    if points is None:
+        return None
+    elif points % 1 == 0:
+        return str(int(points))
+    else:
+        return str(points)
diff --git a/mo/web/jinja.py b/mo/web/jinja.py
index f16c2e5c4efec31f9bfc7c637e1655456936775e..e6721b2001c61223173888e3a7cf8224106a865d 100644
--- a/mo/web/jinja.py
+++ b/mo/web/jinja.py
@@ -27,6 +27,7 @@ app.jinja_env.filters.update(inflected=util_format.inflect_number)
 app.jinja_env.filters.update(timedelta=util_format.timedelta)
 app.jinja_env.filters.update(time_and_timedelta=util_format.time_and_timedelta)
 app.jinja_env.filters.update(data_size=util_format.data_size)
+app.jinja_env.filters.update(decimal=util_format.format_decimal)
 
 # Exporty proměnných
 
diff --git a/mo/web/org_score.py b/mo/web/org_score.py
index cbebbcda83cdf883faccb1a583864d98a2ac1204..b8526435163dd5515cb457b3a29d5c112d3b0f9c 100644
--- a/mo/web/org_score.py
+++ b/mo/web/org_score.py
@@ -10,6 +10,7 @@ from mo.rights import Right
 from mo.score import Score
 from mo.web import app
 from mo.web.table import Cell, CellLink, Column, Row, Table, cell_pion_link
+from mo.util_format import format_decimal
 
 
 class OrderCell(Cell):
@@ -52,7 +53,7 @@ class SolPointsCell(Cell):
             return '–'
         elif self.sol.points is None:
             return '?'
-        return str(self.sol.points)
+        return format_decimal(self.sol.points)
 
     def to_html(self) -> str:
         if not self.sol:
@@ -60,7 +61,7 @@ class SolPointsCell(Cell):
         elif self.sol.points is None:
             points = '<span class="unknown">?</span></a>'
         else:
-            points = str(self.sol.points)
+            points = format_decimal(self.sol.points)
 
         if self.sol.final_feedback_obj:
             url = mo.web.util.org_paper_link(self.contest_id, None, self.user, self.sol.final_feedback_obj)
@@ -180,7 +181,7 @@ def org_score(round_id: Optional[int] = None, contest_id: Optional[int] = None):
             'pion_place':   pion.place.name,
             'school':       CellLink(school.name or "?", url_for('org_place', id=school.place_id)),
             'grade':        pant.grade,
-            'total_points': result.get_total_points(),
+            'total_points': format_decimal(result.get_total_points()),
             'birth_year':   pant.birth_year,
             'order_key':    result._order_key,
         })
diff --git a/mo/web/templates/org_contest.html b/mo/web/templates/org_contest.html
index 2675f9e02c0179769676ae65f4bc6cf2e204f5ee..176143881a71563cd0f8debf22a482678746c8ed 100644
--- a/mo/web/templates/org_contest.html
+++ b/mo/web/templates/org_contest.html
@@ -113,7 +113,7 @@
 		<td>{{ task.code }}
 		<td>{{ task.name }}
 		<td>{{ task.sol_count }}
-		<td>{{ task.max_points|none_value('–') }}
+		<td>{{ task.max_points|decimal|none_value('–') }}
 		<td><div class="btn-group">
 			<a class="btn btn-xs btn-primary" href="{{ url_for('org_contest_task', contest_id=contest.contest_id, task_id=task.task_id, site_id=site_id) }}">Odevzdaná řešení</a>
 			{% if not site and can_edit_points %}
diff --git a/mo/web/templates/org_contest_solutions.html b/mo/web/templates/org_contest_solutions.html
index 0f24a7fb0abacdb2c23f26f7eab3893324030233..99f04c1e347b98721d57dcc77746a0fdbf6997cf 100644
--- a/mo/web/templates/org_contest_solutions.html
+++ b/mo/web/templates/org_contest_solutions.html
@@ -93,7 +93,7 @@ konkrétní úlohu. Symbol <span class="icon">🗐</span> značí, že existuje
 				{% endif %}
 				<td class="sol">
 					{% if sol.points is not none %}
-						{{ sol.points }}
+						{{ sol.points|decimal }}
 						{% if sum_points.append(sol.points) %}{% endif %}
 					{% else %}
 						<span class="unknown">?</span>
@@ -111,7 +111,7 @@ konkrétní úlohu. Symbol <span class="icon">🗐</span> značí, že existuje
 			{% endif %}
 					<a class="btn btn-xs btn-link icon" title="Detail řešení" href="{{ url_for('org_submit_list', contest_id=contest.contest_id, user_id=u.user_id, task_id=task.task_id, site_id=site_id) }}">🔍</a>
 		{% endfor %}
-		<th>{{ sum_points|sum }}</th>
+		<th>{{ sum_points|sum|decimal }}</th>
 	</tr>
 	{% endfor %}
 	<tfoot>
diff --git a/mo/web/templates/org_round.html b/mo/web/templates/org_round.html
index ac93210581020b547d1cd0edba25805f79b6876f..5a568a65b754852f5daa7fc6f37166ad4bb6d0d8 100644
--- a/mo/web/templates/org_round.html
+++ b/mo/web/templates/org_round.html
@@ -140,7 +140,7 @@
 			<td>{{ task.code }}
 			<td>{{ task.name }}
 			<td>{{ task.sol_count }}
-			<td>{{ task.max_points|none_value('–') }}
+			<td>{{ task.max_points|decimal|none_value('–') }}
 			{% if can_manage_round %}
 			<td><div class="btn-group">
 				<a class="btn btn-xs btn-primary" href="{{ url_for('org_round_task_edit', id=round.round_id, task_id=task.task_id) }}">Editovat</a>
diff --git a/mo/web/templates/org_submit_list.html b/mo/web/templates/org_submit_list.html
index 49f9b8f4cd800c7084b8120ff6e9d430ba323164..1b281d6daa04dab9b55e1bf9bd68c435ed374d64 100644
--- a/mo/web/templates/org_submit_list.html
+++ b/mo/web/templates/org_submit_list.html
@@ -13,8 +13,8 @@
 	<tr><th>Úloha<td><a href='{{ url_for('org_contest_task', contest_id=sc.contest.contest_id, site_id=site_id, task_id=sc.task.task_id) }}'>{{ sc.task.code }} {{ sc.task.name }}</a>
 	{% if solution %}
 	<tr><th>Body<td>
-		{% if solution.points is not none %}{{solution.points}}{% else %}<span class="unknown">?</span>{% endif %}
-		{% if sc.task.max_points is not none %}<span class="hint"> / {{ sc.task.max_points }}</span>{% endif %}
+		{{ solution.points|decimal|none_value(Markup('<span class="unknown">?</span>')) }}
+		{% if sc.task.max_points is not none %}<span class="hint"> / {{ sc.task.max_points|decimal }}</span>{% endif %}
 	<tr title="Viditelná účastníkovi po uzavření kola">
 		<th>Poznámka k řešení:<td style="white-space: pre;">{{ solution.note|or_dash }}</td>
 	<tr title="Viditelná jen organizátorům">
@@ -153,7 +153,7 @@ Existuje více než jedna verze oprav, finální je podbarvená.
 	{% for p in points_history %}
 	<tr {% if loop.index == 1 %} class='sol-active'{% endif %}>
 		<td>{{ p.points_at|timeformat }}
-		<td>{% if p.points is not none %}{{ p.points }}{% else %}–{% endif %}
+		<td>{{ p.points|decimal|none_value('–') }}
 		<td>{{ p.user|user_link }}
 	</tr>
 	{% endfor %}
diff --git a/mo/web/templates/parts/org_solution_table.html b/mo/web/templates/parts/org_solution_table.html
index aa7f0df1b108f9a11db11947d9d9735d7309fdc3..23ff5fcc6c7e951e7929a243816317ae5fb8c858 100644
--- a/mo/web/templates/parts/org_solution_table.html
+++ b/mo/web/templates/parts/org_solution_table.html
@@ -89,7 +89,7 @@ finální (ve výchozím stavu poslední nahrané).{% elif sc.allow_upload_solut
 				<input type="number" min=0 {% if task.max_points is not none %}max={{ task.max_points }}{% endif %} class="form-control" name="points_{{u.user_id}}" value="{{ request_form.get("points_{}".format(u.user_id)) or sol.points }}" size="4" tabindex={{ tabindex.value }} autofocus>
 				{% set tabindex.value = tabindex.value + 1%}
 			{% else %}
-				{% if sol.points is not none %}{{ sol.points}}{% else %}<span class="unknown">?</span>{% endif %}
+				{{ sol.points|decimal|none_value(Markup('<span class="unknown">?</span>')) }}
 			{% endif %}
 		{% else %}
 		<td colspan="4" class="text-center">