changeset 214:5f90da6265a9

Switched to using our own round() implementation. This way we can be sure the correct rounding algorithm (banker's rounding) is used on all platforms.
author jonas
date Tue, 10 Jul 2007 21:20:07 +0000
parents b13f3bf4c208
children bf3799fa4e42
files babel/numbers.py
diffstat 1 files changed, 33 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/babel/numbers.py
+++ b/babel/numbers.py
@@ -245,6 +245,36 @@
 number_re = re.compile(r"%s%s%s" % (PREFIX_PATTERN, NUMBER_PATTERN,
                                     SUFFIX_PATTERN))
 
+def bankersround(value, ndigits=0):
+    """Round a number to a given precision.
+
+    Works like round() except that the round-half-even (banker's rounding)
+    algorithm is used instead of round-half-up.
+
+    >>> bankersround(5.5, 0)
+    6.0
+    >>> bankersround(6.5, 0)
+    6.0
+    >>> bankersround(-6.5, 0)
+    -6.0
+    >>> bankersround(1234, -2)
+    1200.0
+    """
+    sign = int(value < 0) and -1 or 1
+    value = abs(value)
+    a, b = str(float(value)).split('.', 1)
+    digits = str(float(value)).replace('.', '')
+    add = 0
+    i = len(a) + ndigits
+    if i < 0 or i >= len(digits):
+        pass
+    elif digits[i] > '5':
+        add = 1
+    elif digits[i] == '5' and digits[i-1] in '13579':
+        add = 1
+    scale = 10.**ndigits
+    return int(value * scale + add) / scale * sign
+
 # TODO:
 #  Filling
 #  Rounding increment in pattern
@@ -330,7 +360,6 @@
         self.grouping = grouping
         self.int_precision = int_precision
         self.frac_precision = frac_precision
-        self.format = '%%#.%df' % self.frac_precision[1]
         if '%' in ''.join(self.prefix + self.suffix):
             self.scale = 100.0
         elif u'‰' in ''.join(self.prefix + self.suffix):
@@ -356,7 +385,8 @@
             else:
                 a, b = self._format_int(text, 0, 1000, locale), ''
         else: # A normal number pattern
-            a, b = (self.format % abs(value)).split('.', 1)
+            a, b = str(bankersround(abs(value), 
+                                    self.frac_precision[1])).split('.', 1)
             a = self._format_int(a, self.int_precision[0],
                                  self.int_precision[1], locale)
             b = self._format_frac(b, locale)
@@ -380,7 +410,7 @@
             while b.startswith('0'):
                 b = b[1:]
                 ndecimals -= 1
-        text = str(round(value, max - ndecimals))
+        text = str(bankersround(value, max - ndecimals))
         if text == '0.0':
             text = a = '0'
             b = ''
Copyright (C) 2012-2017 Edgewall Software