Mercurial > babel > mirror
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: |