comparison babel/numbers.py @ 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 cc699743ec06
comparison
equal deleted inserted replaced
211:5125934e5f27 212:2b0b9bb94660
242 NUMBER_PATTERN = r"(?P<number>%s+)" % NUMBER_TOKEN 242 NUMBER_PATTERN = r"(?P<number>%s+)" % NUMBER_TOKEN
243 SUFFIX_PATTERN = r"(?P<suffix>.*)" 243 SUFFIX_PATTERN = r"(?P<suffix>.*)"
244 244
245 number_re = re.compile(r"%s%s%s" % (PREFIX_PATTERN, NUMBER_PATTERN, 245 number_re = re.compile(r"%s%s%s" % (PREFIX_PATTERN, NUMBER_PATTERN,
246 SUFFIX_PATTERN)) 246 SUFFIX_PATTERN))
247
248 def bankersround(value, ndigits=0):
249 """Round a number to a given precision.
250
251 Works like round() except that the round-half-even (banker's rounding)
252 algorithm is used instead of round-half-up.
253
254 >>> bankersround(5.5, 0)
255 6.0
256 >>> bankersround(6.5, 0)
257 6.0
258 >>> bankersround(-6.5, 0)
259 -6.0
260 >>> bankersround(1234, -2)
261 1200.0
262 """
263 sign = int(value < 0) and -1 or 1
264 value = abs(value)
265 a, b = str(float(value)).split('.', 1)
266 digits = str(float(value)).replace('.', '')
267 add = 0
268 i = len(a) + ndigits
269 if i < 0 or i >= len(digits):
270 pass
271 elif digits[i] > '5':
272 add = 1
273 elif digits[i] == '5' and digits[i-1] in '13579':
274 add = 1
275 scale = 10.**ndigits
276 return int(value * scale + add) / scale * sign
247 277
248 # TODO: 278 # TODO:
249 # Filling 279 # Filling
250 # Rounding increment in pattern 280 # Rounding increment in pattern
251 # Scientific notation 281 # Scientific notation
328 self.prefix = prefix 358 self.prefix = prefix
329 self.suffix = suffix 359 self.suffix = suffix
330 self.grouping = grouping 360 self.grouping = grouping
331 self.int_precision = int_precision 361 self.int_precision = int_precision
332 self.frac_precision = frac_precision 362 self.frac_precision = frac_precision
333 self.format = '%%#.%df' % self.frac_precision[1]
334 if '%' in ''.join(self.prefix + self.suffix): 363 if '%' in ''.join(self.prefix + self.suffix):
335 self.scale = 100.0 364 self.scale = 100.0
336 elif u'‰' in ''.join(self.prefix + self.suffix): 365 elif u'‰' in ''.join(self.prefix + self.suffix):
337 self.scale = 1000.0 366 self.scale = 1000.0
338 else: 367 else:
354 if b: 383 if b:
355 b = get_decimal_symbol(locale) + b 384 b = get_decimal_symbol(locale) + b
356 else: 385 else:
357 a, b = self._format_int(text, 0, 1000, locale), '' 386 a, b = self._format_int(text, 0, 1000, locale), ''
358 else: # A normal number pattern 387 else: # A normal number pattern
359 a, b = (self.format % abs(value)).split('.', 1) 388 a, b = str(bankersround(abs(value),
389 self.frac_precision[1])).split('.', 1)
360 a = self._format_int(a, self.int_precision[0], 390 a = self._format_int(a, self.int_precision[0],
361 self.int_precision[1], locale) 391 self.int_precision[1], locale)
362 b = self._format_frac(b, locale) 392 b = self._format_frac(b, locale)
363 retval = u'%s%s%s%s' % (self.prefix[negative], a, b, 393 retval = u'%s%s%s%s' % (self.prefix[negative], a, b,
364 self.suffix[negative]) 394 self.suffix[negative])
378 if a == '0': 408 if a == '0':
379 ndecimals = 0 409 ndecimals = 0
380 while b.startswith('0'): 410 while b.startswith('0'):
381 b = b[1:] 411 b = b[1:]
382 ndecimals -= 1 412 ndecimals -= 1
383 text = str(round(value, max - ndecimals)) 413 text = str(bankersround(value, max - ndecimals))
384 if text == '0.0': 414 if text == '0.0':
385 text = a = '0' 415 text = a = '0'
386 b = '' 416 b = ''
387 digits = 1 417 digits = 1
388 else: 418 else:
Copyright (C) 2012-2017 Edgewall Software