1 # General floating point formatting functions.
4 # fix(x, digits_behind)
5 # sci(x, digits_behind)
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
16 # Compiled regular expression to "decode" a number
17 decoder
= re
.compile(r
'^([-+]?)0*(\d*)((?:\.\d*)?)(([eE][-+]?\d+)?)$')
19 # \1 leading sign or empty
20 # \2 digits left of decimal point
21 # \3 fraction (empty or begins with point)
22 # \4 exponent part (empty or begins with 'e' or 'E')
24 NotANumber
= 'fpformat.NotANumber'
26 # Return (sign, intpart, fraction, expo) or raise an exception:
28 # intpart is 0 or more digits beginning with a nonzero
29 # fraction is 0 or more digits
32 res
= decoder
.match(s
)
33 if res
is None: raise NotANumber
34 sign
, intpart
, fraction
, exppart
= res
.group(1,2,3,4)
35 if sign
== '+': sign
= ''
36 if fraction
: fraction
= fraction
[1:]
37 if exppart
: expo
= eval(exppart
[1:])
39 return sign
, intpart
, fraction
, expo
41 # Remove the exponent by changing intpart and fraction
42 def unexpo(intpart
, fraction
, expo
):
43 if expo
> 0: # Move the point left
45 intpart
, fraction
= intpart
+ fraction
[:expo
], fraction
[expo
:]
47 intpart
= intpart
+ '0'*(expo
-f
)
48 elif expo
< 0: # Move the point right
50 intpart
, fraction
= intpart
[:expo
], intpart
[expo
:] + fraction
52 fraction
= '0'*(-expo
-i
) + fraction
53 return intpart
, fraction
55 # Round or extend the fraction to size digs
56 def roundfrac(intpart
, fraction
, digs
):
59 return intpart
, fraction
+ '0'*(digs
-f
)
63 total
= intpart
+ fraction
64 nextdigit
= total
[i
+digs
]
65 if nextdigit
>= '5': # Hard case: increment last digit, may have carry!
68 if total
[n
] != '9': break
74 total
= total
[:n
] + chr(ord(total
[n
]) + 1) + '0'*(len(total
)-n
-1)
75 intpart
, fraction
= total
[:i
], total
[i
:]
77 return intpart
, fraction
[:digs
]
79 return intpart
[:digs
] + '0'*-digs
, ''
81 # Format x as [-]ddd.ddd with 'digs' digits after the point
82 # and at least one digit before.
83 # If digs <= 0, the point is suppressed.
85 if type(x
) != type(''): x
= `x`
87 sign
, intpart
, fraction
, expo
= extract(x
)
90 intpart
, fraction
= unexpo(intpart
, fraction
, expo
)
91 intpart
, fraction
= roundfrac(intpart
, fraction
, digs
)
92 while intpart
and intpart
[0] == '0': intpart
= intpart
[1:]
93 if intpart
== '': intpart
= '0'
94 if digs
> 0: return sign
+ intpart
+ '.' + fraction
95 else: return sign
+ intpart
97 # Format x as [-]d.dddE[+-]ddd with 'digs' digits after the point
98 # and exactly one digit before.
99 # If digs is <= 0, one digit is kept and the point is suppressed.
101 if type(x
) != type(''): x
= `x`
102 sign
, intpart
, fraction
, expo
= extract(x
)
104 while fraction
and fraction
[0] == '0':
105 fraction
= fraction
[1:]
108 intpart
, fraction
= fraction
[0], fraction
[1:]
113 expo
= expo
+ len(intpart
) - 1
114 intpart
, fraction
= intpart
[0], intpart
[1:] + fraction
116 intpart
, fraction
= roundfrac(intpart
, fraction
, digs
)
118 intpart
, fraction
, expo
= \
119 intpart
[0], intpart
[1:] + fraction
[:-1], \
120 expo
+ len(intpart
) - 1
122 if digs
> 0: s
= s
+ '.' + fraction
124 e
= '0'*(3-len(e
)) + e
125 if expo
< 0: e
= '-' + e
129 # Interactive test run
133 x
, digs
= input('Enter (x, digs): ')
134 print x
, fix(x
, digs
), sci(x
, digs
)
135 except (EOFError, KeyboardInterrupt):