Skip to content

Commit 950d654

Browse files
committed
Support thousands separators for formatting of fractional part
Closes #918
1 parent 8f68766 commit 950d654

2 files changed

Lines changed: 21 additions & 3 deletions

File tree

mpmath/libmp/libmpf.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,7 @@ def from_str(x, prec=0, rnd=round_fast, base=0):
14001400
(?P<zeropad>0(?=0*[1-9]))?
14011401
(?P<width>[0-9]+)?
14021402
(?P<thousands_separators>[,_])?
1403-
(?:\.(?P<precision>[0-9]+))?
1403+
(?:\.(?P<precision>[0-9]+)(?P<frac_separators>[,_])?)?
14041404
(?P<rounding>[UDYZN])?
14051405
(?P<type>[aAbeEfFgG%])?
14061406
""", re.DOTALL | re.VERBOSE).fullmatch
@@ -1447,6 +1447,7 @@ def read_format_spec(format_spec):
14471447
'no_neg_0': False,
14481448
'alternate': False,
14491449
'thousands_separators': '',
1450+
'frac_separators': '',
14501451
'width': -1,
14511452
'precision': -1,
14521453
'rounding': round_nearest,
@@ -1464,6 +1465,8 @@ def read_format_spec(format_spec):
14641465
or format_dict['thousands_separators']
14651466
format_dict['width'] = int(match['width'] or format_dict['width'])
14661467
format_dict['precision'] = int(match['precision'] or format_dict['precision'])
1468+
format_dict['frac_separators'] = match['frac_separators'] \
1469+
or format_dict['frac_separators']
14671470
rounding_char = match['rounding']
14681471
format_dict['type'] = match['type'] or format_dict['type']
14691472

@@ -1681,13 +1684,21 @@ def format_digits(num, format_dict, prec):
16811684
or (precision and not strip_last_zero)):
16821685
frac_part = '.' + frac_part
16831686

1687+
sep_range = 3
1688+
frac_sep = format_dict['frac_separators']
1689+
if frac_sep and frac_part:
1690+
frac_part = frac_part[:sep_range + 1] + "".join(frac_sep + frac_part[pos:pos + sep_range]
1691+
for pos in range(sep_range + 1,
1692+
len(frac_part),
1693+
sep_range))
16841694
digits = frac_part + exponent
16851695

16861696
sign = '-' if num[0] else ''
16871697
if sign != '-' and format_dict['sign'] != '-':
16881698
sign = format_dict['sign']
16891699
if fmt_type == 'f' and format_dict['no_neg_0']:
1690-
if int_part == "0" and all(_ in ['0', '.'] for _ in digits):
1700+
if int_part == "0" and all(_ in ['0', '.', '_', ',']
1701+
for _ in digits):
16911702
if format_dict['sign'] == '-':
16921703
sign = ''
16931704
else:
@@ -1697,7 +1708,6 @@ def format_digits(num, format_dict, prec):
16971708
digits += '%'
16981709

16991710
sep = format_dict['thousands_separators']
1700-
sep_range = 3
17011711
width = format_dict['width']
17021712
if (int_part and fmt_type in ['%', 'f', 'e', 'g', '']
17031713
and format_dict['fill_char'] == '0' and format_dict['align'] == '='

mpmath/tests/test_format.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ def fmt_str(draw, types='fFeE', for_complex=False):
6868
+ ['0' + str(_) for _ in range(40)]))
6969
if prec:
7070
res += '.' + prec
71+
# if sys.version_info >= (3, 14):
72+
# gchar = draw(st.sampled_from([''] + list(',_')))
73+
# res += gchar
7174

7275
# Type
7376
res += draw(st.sampled_from(types))
@@ -178,6 +181,9 @@ def test_mpf_fmt_cpython():
178181
assert f'{mp.mpf(0.0000005001):f}' == '0.000001'
179182
assert f'{mp.mpf(0.0000004999):f}' == '0.000000'
180183

184+
# grouping in fractional part
185+
assert f'{mp.mpf(0.0000004999):.9_f}' == '0.000_000_500'
186+
181187
# 'e' code formatting with explicit precision (>= 0). Output should
182188
# always have exactly the number of places after the point that were
183189
# requested.
@@ -485,6 +491,8 @@ def test_mpf_floats_bulk(fmt, x):
485491
if not x and math.copysign(1, x) == -1:
486492
return # skip negative zero
487493
spec = read_format_spec(fmt)
494+
if spec['frac_separators'] and spec['fill_char'] == '0':
495+
return # XXX: python/cpython#130860
488496
if not spec['type'] and spec['precision'] < 0 and math.isfinite(x):
489497
# The mpmath could choose a different decimal
490498
# representative (wrt CPython) for same binary

0 commit comments

Comments
 (0)