Browse Source

Fixed #30761 -- Prevented floatformat filter from returning a negative zero.

Sky 5 years ago
parent
commit
3cf907c20c

+ 3 - 2
django/template/defaultfilters.py

@@ -152,12 +152,13 @@ def floatformat(text, arg=-1):
 
     # Avoid conversion to scientific notation by accessing `sign`, `digits`,
     # and `exponent` from Decimal.as_tuple() directly.
-    sign, digits, exponent = d.quantize(exp, ROUND_HALF_UP, Context(prec=prec)).as_tuple()
+    rounded_d = d.quantize(exp, ROUND_HALF_UP, Context(prec=prec))
+    sign, digits, exponent = rounded_d.as_tuple()
     digits = [str(digit) for digit in reversed(digits)]
     while len(digits) <= abs(exponent):
         digits.append('0')
     digits.insert(-exponent, '.')
-    if sign:
+    if sign and rounded_d:
         digits.append('-')
     number = ''.join(reversed(digits))
     return mark_safe(formats.number_format(number, abs(p)))

+ 5 - 0
docs/ref/templates/builtins.txt

@@ -1722,6 +1722,11 @@ displayed. For example:
 Using ``floatformat`` with no argument is equivalent to using ``floatformat``
 with an argument of ``-1``.
 
+.. versionchanged:: 3.1
+
+    In older versions, a negative zero ``-0`` was returned for negative numbers
+    which round to zero.
+
 .. templatefilter:: force_escape
 
 ``force_escape``

+ 3 - 0
docs/releases/3.1.txt

@@ -279,6 +279,9 @@ Miscellaneous
 * ``django.utils.decorators.classproperty()`` decorator is moved to
   ``django.utils.functional.classproperty()``.
 
+* :tfilter:`floatformat` template filter now outputs (positive) ``0`` for
+  negative numbers which round to zero.
+
 .. _deprecated-features-3.1:
 
 Features deprecated in 3.1

+ 10 - 0
tests/template_tests/filter_tests/test_floatformat.py

@@ -64,6 +64,16 @@ class FunctionTests(SimpleTestCase):
         self.assertEqual(floatformat(0, 10), '0.0000000000')
         self.assertEqual(floatformat(0.000000000000000000015, 20), '0.00000000000000000002')
 
+    def test_negative_zero_values(self):
+        tests = [
+            (-0.01, -1, '0.0'),
+            (-0.001, 2, '0.00'),
+            (-0.499, 0, '0'),
+        ]
+        for num, decimal_places, expected in tests:
+            with self.subTest(num=num, decimal_places=decimal_places):
+                self.assertEqual(floatformat(num, decimal_places), expected)
+
     def test_infinity(self):
         pos_inf = float(1e30000)
         neg_inf = float(-1e30000)