1 """General floating point formatting functions.
7 Each takes a number or a string and a number of digits as arguments.
10 x: number to be formatted; or a string resembling a number
11 digits_behind: number of digits behind the decimal point
13 from warnings
import warnpy3k
14 warnpy3k("the fpformat module has been removed in Python 3.0", stacklevel
=2)
19 __all__
= ["fix","sci","NotANumber"]
21 # Compiled regular expression to "decode" a number
22 decoder
= re
.compile(r
'^([-+]?)0*(\d*)((?:\.\d*)?)(([eE][-+]?\d+)?)$')
24 # \1 leading sign or empty
25 # \2 digits left of decimal point
26 # \3 fraction (empty or begins with point)
27 # \4 exponent part (empty or begins with 'e' or 'E')
30 class NotANumber(ValueError):
33 NotANumber
= 'fpformat.NotANumber'
36 """Return (sign, intpart, fraction, expo) or raise an exception:
38 intpart is 0 or more digits beginning with a nonzero
39 fraction is 0 or more digits
41 res
= decoder
.match(s
)
42 if res
is None: raise NotANumber
, s
43 sign
, intpart
, fraction
, exppart
= res
.group(1,2,3,4)
44 if sign
== '+': sign
= ''
45 if fraction
: fraction
= fraction
[1:]
46 if exppart
: expo
= int(exppart
[1:])
48 return sign
, intpart
, fraction
, expo
50 def unexpo(intpart
, fraction
, expo
):
51 """Remove the exponent by changing intpart and fraction."""
52 if expo
> 0: # Move the point left
54 intpart
, fraction
= intpart
+ fraction
[:expo
], fraction
[expo
:]
56 intpart
= intpart
+ '0'*(expo
-f
)
57 elif expo
< 0: # Move the point right
59 intpart
, fraction
= intpart
[:expo
], intpart
[expo
:] + fraction
61 fraction
= '0'*(-expo
-i
) + fraction
62 return intpart
, fraction
64 def roundfrac(intpart
, fraction
, digs
):
65 """Round or extend the fraction to size digs."""
68 return intpart
, fraction
+ '0'*(digs
-f
)
72 total
= intpart
+ fraction
73 nextdigit
= total
[i
+digs
]
74 if nextdigit
>= '5': # Hard case: increment last digit, may have carry!
77 if total
[n
] != '9': break
83 total
= total
[:n
] + chr(ord(total
[n
]) + 1) + '0'*(len(total
)-n
-1)
84 intpart
, fraction
= total
[:i
], total
[i
:]
86 return intpart
, fraction
[:digs
]
88 return intpart
[:digs
] + '0'*-digs
, ''
91 """Format x as [-]ddd.ddd with 'digs' digits after the point
92 and at least one digit before.
93 If digs <= 0, the point is suppressed."""
94 if type(x
) != type(''): x
= repr(x
)
96 sign
, intpart
, fraction
, expo
= extract(x
)
99 intpart
, fraction
= unexpo(intpart
, fraction
, expo
)
100 intpart
, fraction
= roundfrac(intpart
, fraction
, digs
)
101 while intpart
and intpart
[0] == '0': intpart
= intpart
[1:]
102 if intpart
== '': intpart
= '0'
103 if digs
> 0: return sign
+ intpart
+ '.' + fraction
104 else: return sign
+ intpart
107 """Format x as [-]d.dddE[+-]ddd with 'digs' digits after the point
108 and exactly one digit before.
109 If digs is <= 0, one digit is kept and the point is suppressed."""
110 if type(x
) != type(''): x
= repr(x
)
111 sign
, intpart
, fraction
, expo
= extract(x
)
113 while fraction
and fraction
[0] == '0':
114 fraction
= fraction
[1:]
117 intpart
, fraction
= fraction
[0], fraction
[1:]
122 expo
= expo
+ len(intpart
) - 1
123 intpart
, fraction
= intpart
[0], intpart
[1:] + fraction
125 intpart
, fraction
= roundfrac(intpart
, fraction
, digs
)
127 intpart
, fraction
, expo
= \
128 intpart
[0], intpart
[1:] + fraction
[:-1], \
129 expo
+ len(intpart
) - 1
131 if digs
> 0: s
= s
+ '.' + fraction
133 e
= '0'*(3-len(e
)) + e
134 if expo
< 0: e
= '-' + e
139 """Interactive test run."""
142 x
, digs
= input('Enter (x, digs): ')
143 print x
, fix(x
, digs
), sci(x
, digs
)
144 except (EOFError, KeyboardInterrupt):