changeset 212:2b0b9bb94660 trunk

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 5125934e5f27
children 9a6981c95395
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