-
Notifications
You must be signed in to change notification settings - Fork 1
/
formatnum.py
472 lines (419 loc) · 20.7 KB
/
formatnum.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
# This program is public domain
# Author: Paul Kienzle
"""
Number formatting
=================
Format values and uncertainties nicely for printing.
:func:`format_value` produces the value format v with no uncertainty.
:func:`format_uncertainty_pm` produces the expanded format v +/- err.
:func:`format_uncertainty_compact` produces the compact format v(##),
where the number in parenthesis is the uncertainty in the last two digits of v.
:func:`format_uncertainty` uses the compact format by default, but this
can be changed to use the expanded +/- format by setting
format_uncertainty.compact to False.
The formatted string uses only the number of digits warranted by
the uncertainty in the measurement, and is limited to max_digits of precision.
If the uncertainty is 0 or not otherwise provided, the simple
%g floating point format option is used.
Infinite and indefinite numbers are represented as inf and NaN.
Example::
>>> v,dv = 757.2356,0.01032
>>> print format_uncertainty_pm(v,dv)
757.236 +/- 0.010
>>> print format_uncertainty_compact(v,dv)
757.236(10)
>>> print format_uncertainty(v,dv)
757.236(10)
>>> format_uncertainty.compact = False
>>> print format_uncertainty(v,dv)
757.236 +/- 0.010
UncertaintyFormatter() returns a private formatter with its own
formatter.compact flag.
"""
from __future__ import division
import math
import numpy
__all__ = ['format_uncertainty', 'format_uncertainty_pm',
'format_uncertainty_compact']
# Coordinating scales across a set of numbers is not supported. For easy
# comparison a set of numbers should be shown in the same scale. One could
# force this from the outside by adding scale parameter (either 10**n, n, or
# a string representing the desired SI prefix) and having a separate routine
# which computes the scale given a set of values.
# Coordinating scales with units offers its own problems. Again, the user
# may want to force particular units. This can be done by outside of the
# formatting routines by scaling the numbers to the appropriate units then
# forcing them to print with scale 10**0. If this is a common operation,
# however, it may want to happen inside.
# The value e<n> is currently formatted into the number. Alternatively this
# scale factor could be returned so that the user can choose the appropriate
# SI prefix when printing the units. This gets tricky when talking about
# composite units such as 2.3e-3 m**2 -> 2300 mm**2, and with volumes
# such as 1 g/cm**3 -> 1 kg/L.
def format_value(value, uncertainty, max_digits=15):
"""
Given *value* v and *uncertainty* dv, return a string v which is
the value formatted with the appropriate number of digits.
If *max_digits* is specified, limit uncertainty to that many digits.
"""
return _format_uncertainty(value, uncertainty, compact=None,
max_digits=max_digits)
def format_uncertainty_pm(value, uncertainty, max_digits=15):
"""
Given *value* v and *uncertainty* dv, return a string v +/- dv.
If *max_digits* is specified, limit uncertainty to that many digits.
"""
return _format_uncertainty(value, uncertainty, compact=False,
max_digits=max_digits)
def format_uncertainty_compact(value, uncertainty, max_digits=15):
"""
Given *value* v and *uncertainty* dv, return the compact
representation v(##), where ## are the first two digits of the uncertainty.
If *max_digits* is specified, limit uncertainty to that many digits.
"""
return _format_uncertainty(value, uncertainty, compact=True,
max_digits=max_digits)
class UncertaintyFormatter:
"""
Value and uncertainty formatter.
The *formatter* instance will use either the expanded v +/- dv form
or the compact v(##) form depending on whether *formatter.compact* is
True or False. The default is True.
"""
compact = True
def __call__(self, value, uncertainty, max_digits=15):
"""
Given *value* and *uncertainty*, return a string representation.
If *max_digits* is specified, limit uncertainty to that many digits.
"""
return _format_uncertainty(value, uncertainty, self.compact,
max_digits=15)
format_uncertainty = UncertaintyFormatter()
def _format_uncertainty(value, uncertainty, compact, max_digits):
"""
Implementation of both the compact and the +/- formats.
"""
# Handle indefinite value
if numpy.isinf(value):
return "inf" if value > 0 else "-inf"
if numpy.isnan(value):
return "NaN"
# Handle indefinite uncertainty
if uncertainty is None or uncertainty<=0 or numpy.isnan(uncertainty):
return "%g"%value
if numpy.isinf(uncertainty):
if compact is None:
return "%.2g"%value
elif compact:
return "%.2g(inf)"%value
else:
return "%.2g +/- inf"%value
# Handle zero and negative values
sign = "-" if value < 0 else ""
value = abs(value)
# Determine scale of value and error
err_place = int(math.floor(math.log10(uncertainty)))
if value == 0:
val_place = err_place - 1
else:
val_place = int(math.floor(math.log10(value)))
# Cap the number of digits at max_digits
if val_place - err_place > max_digits-2:
err_place = val_place - (max_digits-(1 if compact is None else 2))
if err_place > val_place:
# Degenerate case: error bigger than value
# The mantissa is 0.#(##)e#, 0.0#(##)e# or 0.00#(##)e#
val_place = err_place+2
elif err_place == val_place:
# Degenerate case: error and value the same order of magnitude
# The value is ##(##)e#, #.#(##)e# or 0.##(##)e#
val_place = err_place+1
elif err_place <= 1 and val_place >= -3:
# Normal case: nice numbers and errors
# The value is ###.###(##)
val_place = 0
else:
# Extreme cases: zeros before value or after error
# The value is ###.###(##)e#, ##.####(##)e# or #.#####(##)e#
pass
# Force engineering notation, with exponent a multiple of 3
val_place = int(math.floor(val_place/3.))*3
# Format the result
digits_after_decimal = abs(val_place - err_place + 1)
# Only use one digit of uncertainty if no precision included in result
if compact is None: digits_after_decimal -= 1
val_str = "%.*f"%(digits_after_decimal,value/10.**val_place)
exp_str = "e%d"%val_place if val_place != 0 else ""
if compact is None:
result = "".join((sign,val_str,exp_str))
elif compact:
err_str = "(%d)"%int(uncertainty/10.**(err_place-1)+0.5)
result = "".join((sign,val_str,err_str,exp_str))
else:
err_str = "%.*f"%(digits_after_decimal,uncertainty/10.**val_place)
result = "".join((sign,val_str,exp_str+" +/- ",err_str,exp_str))
#print sign,value, uncertainty, "=>", result
return result
def test_compact():
# Oops... renamed function after writing tests
value_str = format_uncertainty_compact
# val_place > err_place
assert value_str(1235670,766000) == "1.24(77)e6"
assert value_str(123567.,76600) == "124(77)e3"
assert value_str(12356.7,7660) == "12.4(77)e3"
assert value_str(1235.67,766) == "1.24(77)e3"
assert value_str(123.567,76.6) == "124(77)"
assert value_str(12.3567,7.66) == "12.4(77)"
assert value_str(1.23567,.766) == "1.24(77)"
assert value_str(.123567,.0766) == "0.124(77)"
assert value_str(.0123567,.00766) == "0.0124(77)"
assert value_str(.00123567,.000766) == "0.00124(77)"
assert value_str(.000123567,.0000766) == "124(77)e-6"
assert value_str(.0000123567,.00000766) == "12.4(77)e-6"
assert value_str(.00000123567,.000000766) == "1.24(77)e-6"
assert value_str(.000000123567,.0000000766) == "124(77)e-9"
assert value_str(.00000123567,.0000000766) == "1.236(77)e-6"
assert value_str(.0000123567,.0000000766) == "12.357(77)e-6"
assert value_str(.000123567,.0000000766) == "123.567(77)e-6"
assert value_str(.00123567,.000000766) == "0.00123567(77)"
assert value_str(.0123567,.00000766) == "0.0123567(77)"
assert value_str(.123567,.0000766) == "0.123567(77)"
assert value_str(1.23567,.000766) == "1.23567(77)"
assert value_str(12.3567,.00766) == "12.3567(77)"
assert value_str(123.567,.0764) == "123.567(76)"
assert value_str(1235.67,.764) == "1235.67(76)"
assert value_str(12356.7,7.64) == "12356.7(76)"
assert value_str(123567,76.4) == "123567(76)"
assert value_str(1235670,764) == "1.23567(76)e6"
assert value_str(12356700,764) == "12.35670(76)e6"
assert value_str(123567000,764) == "123.56700(76)e6"
assert value_str(123567000,7640) == "123.5670(76)e6"
assert value_str(1235670000,76400) == "1.235670(76)e9"
# val_place == err_place
assert value_str(123567,764000) == "0.12(76)e6"
assert value_str(12356.7,76400) == "12(76)e3"
assert value_str(1235.67,7640) == "1.2(76)e3"
assert value_str(123.567,764) == "0.12(76)e3"
assert value_str(12.3567,76.4) == "12(76)"
assert value_str(1.23567,7.64) == "1.2(76)"
assert value_str(.123567,.764) == "0.12(76)"
assert value_str(.0123567,.0764) == "12(76)e-3"
assert value_str(.00123567,.00764) == "1.2(76)e-3"
assert value_str(.000123567,.000764) == "0.12(76)e-3"
# val_place == err_place-1
assert value_str(123567,7640000) == "0.1(76)e6"
assert value_str(12356.7,764000) == "0.01(76)e6"
assert value_str(1235.67,76400) == "0.001(76)e6"
assert value_str(123.567,7640) == "0.1(76)e3"
assert value_str(12.3567,764) == "0.01(76)e3"
assert value_str(1.23567,76.4) == "0.001(76)e3"
assert value_str(.123567,7.64) == "0.1(76)"
assert value_str(.0123567,.764) == "0.01(76)"
assert value_str(.00123567,.0764) == "0.001(76)"
assert value_str(.000123567,.00764) == "0.1(76)e-3"
# val_place == err_place-2
assert value_str(12356700,7640000000) == "0.0(76)e9"
assert value_str(1235670,764000000) == "0.00(76)e9"
assert value_str(123567,76400000) == "0.000(76)e9"
assert value_str(12356,7640000) == "0.0(76)e6"
assert value_str(1235,764000) == "0.00(76)e6"
assert value_str(123,76400) == "0.000(76)e6"
assert value_str(12,7640) == "0.0(76)e3"
assert value_str(1,764) == "0.00(76)e3"
assert value_str(0.1,76.4) == "0.000(76)e3"
assert value_str(0.01,7.64) == "0.0(76)"
assert value_str(0.001,0.764) == "0.00(76)"
assert value_str(0.0001,0.0764) == "0.000(76)"
assert value_str(0.00001,0.00764) == "0.0(76)e-3"
# val_place == err_place-3
assert value_str(12356700,76400000000) == "0.000(76)e12"
assert value_str(1235670,7640000000) == "0.0(76)e9"
assert value_str(123567,764000000) == "0.00(76)e9"
assert value_str(12356,76400000) == "0.000(76)e9"
assert value_str(1235,7640000) == "0.0(76)e6"
assert value_str(123,764000) == "0.00(76)e6"
assert value_str(12,76400) == "0.000(76)e6"
assert value_str(1,7640) == "0.0(76)e3"
assert value_str(0.1,764) == "0.00(76)e3"
assert value_str(0.01,76.4) == "0.000(76)e3"
assert value_str(0.001,7.64) == "0.0(76)"
assert value_str(0.0001,0.764) == "0.00(76)"
assert value_str(0.00001,0.0764) == "0.000(76)"
assert value_str(0.000001,0.00764) == "0.0(76)e-3"
# Zero values
assert value_str(0,7640000) == "0.0(76)e6"
assert value_str(0, 764000) == "0.00(76)e6"
assert value_str(0, 76400) == "0.000(76)e6"
assert value_str(0, 7640) == "0.0(76)e3"
assert value_str(0, 764) == "0.00(76)e3"
assert value_str(0, 76.4) == "0.000(76)e3"
assert value_str(0, 7.64) == "0.0(76)"
assert value_str(0, 0.764) == "0.00(76)"
assert value_str(0, 0.0764) == "0.000(76)"
assert value_str(0, 0.00764) == "0.0(76)e-3"
assert value_str(0, 0.000764) == "0.00(76)e-3"
assert value_str(0, 0.0000764) == "0.000(76)e-3"
# negative values
assert value_str(-1235670,765000) == "-1.24(77)e6"
assert value_str(-1.23567,.766) == "-1.24(77)"
assert value_str(-.00000123567,.0000000766) == "-1.236(77)e-6"
assert value_str(-12356.7,7.64) == "-12356.7(76)"
assert value_str(-123.567,764) == "-0.12(76)e3"
assert value_str(-1235.67,76400) == "-0.001(76)e6"
assert value_str(-.000123567,.00764) == "-0.1(76)e-3"
assert value_str(-12356,7640000) == "-0.0(76)e6"
assert value_str(-12,76400) == "-0.000(76)e6"
assert value_str(-0.0001,0.764) == "-0.00(76)"
# non-finite values
assert value_str(-numpy.inf,None) == "-inf"
assert value_str(numpy.inf,None) == "inf"
assert value_str(numpy.NaN,None) == "NaN"
# bad or missing uncertainty
assert value_str(-1.23567,numpy.NaN) == "-1.23567"
assert value_str(-1.23567,-numpy.inf) == "-1.23567"
assert value_str(-1.23567,-0.1) == "-1.23567"
assert value_str(-1.23567,0) == "-1.23567"
assert value_str(-1.23567,None) == "-1.23567"
assert value_str(-1.23567,numpy.inf) == "-1.2(inf)"
def test_pm():
# Oops... renamed function after writing tests
value_str = format_uncertainty_pm
# val_place > err_place
assert value_str(1235670,766000) == "1.24e6 +/- 0.77e6"
assert value_str(123567., 76600) == "124e3 +/- 77e3"
assert value_str(12356.7, 7660) == "12.4e3 +/- 7.7e3"
assert value_str(1235.67, 766) == "1.24e3 +/- 0.77e3"
assert value_str(123.567, 76.6) == "124 +/- 77"
assert value_str(12.3567, 7.66) == "12.4 +/- 7.7"
assert value_str(1.23567, .766) == "1.24 +/- 0.77"
assert value_str(.123567, .0766) == "0.124 +/- 0.077"
assert value_str(.0123567, .00766) == "0.0124 +/- 0.0077"
assert value_str(.00123567, .000766) == "0.00124 +/- 0.00077"
assert value_str(.000123567, .0000766) == "124e-6 +/- 77e-6"
assert value_str(.0000123567, .00000766) == "12.4e-6 +/- 7.7e-6"
assert value_str(.00000123567, .000000766) == "1.24e-6 +/- 0.77e-6"
assert value_str(.000000123567,.0000000766) == "124e-9 +/- 77e-9"
assert value_str(.00000123567, .0000000766) == "1.236e-6 +/- 0.077e-6"
assert value_str(.0000123567, .0000000766) == "12.357e-6 +/- 0.077e-6"
assert value_str(.000123567, .0000000766) == "123.567e-6 +/- 0.077e-6"
assert value_str(.00123567, .000000766) == "0.00123567 +/- 0.00000077"
assert value_str(.0123567, .00000766) == "0.0123567 +/- 0.0000077"
assert value_str(.123567, .0000766) == "0.123567 +/- 0.000077"
assert value_str(1.23567, .000766) == "1.23567 +/- 0.00077"
assert value_str(12.3567, .00766) == "12.3567 +/- 0.0077"
assert value_str(123.567, .0764) == "123.567 +/- 0.076"
assert value_str(1235.67, .764) == "1235.67 +/- 0.76"
assert value_str(12356.7, 7.64) == "12356.7 +/- 7.6"
assert value_str(123567, 76.4) == "123567 +/- 76"
assert value_str(1235670, 764) == "1.23567e6 +/- 0.00076e6"
assert value_str(12356700, 764) == "12.35670e6 +/- 0.00076e6"
assert value_str(123567000, 764) == "123.56700e6 +/- 0.00076e6"
assert value_str(123567000,7640) == "123.5670e6 +/- 0.0076e6"
assert value_str(1235670000,76400) == "1.235670e9 +/- 0.000076e9"
# val_place == err_place
assert value_str(123567,764000) == "0.12e6 +/- 0.76e6"
assert value_str(12356.7,76400) == "12e3 +/- 76e3"
assert value_str(1235.67,7640) == "1.2e3 +/- 7.6e3"
assert value_str(123.567,764) == "0.12e3 +/- 0.76e3"
assert value_str(12.3567,76.4) == "12 +/- 76"
assert value_str(1.23567,7.64) == "1.2 +/- 7.6"
assert value_str(.123567,.764) == "0.12 +/- 0.76"
assert value_str(.0123567,.0764) == "12e-3 +/- 76e-3"
assert value_str(.00123567,.00764) == "1.2e-3 +/- 7.6e-3"
assert value_str(.000123567,.000764) == "0.12e-3 +/- 0.76e-3"
# val_place == err_place-1
assert value_str(123567,7640000) == "0.1e6 +/- 7.6e6"
assert value_str(12356.7,764000) == "0.01e6 +/- 0.76e6"
assert value_str(1235.67,76400) == "0.001e6 +/- 0.076e6"
assert value_str(123.567,7640) == "0.1e3 +/- 7.6e3"
assert value_str(12.3567,764) == "0.01e3 +/- 0.76e3"
assert value_str(1.23567,76.4) == "0.001e3 +/- 0.076e3"
assert value_str(.123567,7.64) == "0.1 +/- 7.6"
assert value_str(.0123567,.764) == "0.01 +/- 0.76"
assert value_str(.00123567,.0764) == "0.001 +/- 0.076"
assert value_str(.000123567,.00764) == "0.1e-3 +/- 7.6e-3"
# val_place == err_place-2
assert value_str(12356700,7640000000) == "0.0e9 +/- 7.6e9"
assert value_str(1235670,764000000) == "0.00e9 +/- 0.76e9"
assert value_str(123567,76400000) == "0.000e9 +/- 0.076e9"
assert value_str(12356,7640000) == "0.0e6 +/- 7.6e6"
assert value_str(1235,764000) == "0.00e6 +/- 0.76e6"
assert value_str(123,76400) == "0.000e6 +/- 0.076e6"
assert value_str(12,7640) == "0.0e3 +/- 7.6e3"
assert value_str(1,764) == "0.00e3 +/- 0.76e3"
assert value_str(0.1,76.4) == "0.000e3 +/- 0.076e3"
assert value_str(0.01,7.64) == "0.0 +/- 7.6"
assert value_str(0.001,0.764) == "0.00 +/- 0.76"
assert value_str(0.0001,0.0764) == "0.000 +/- 0.076"
assert value_str(0.00001,0.00764) == "0.0e-3 +/- 7.6e-3"
# val_place == err_place-3
assert value_str(12356700,76400000000) == "0.000e12 +/- 0.076e12"
assert value_str(1235670,7640000000) == "0.0e9 +/- 7.6e9"
assert value_str(123567,764000000) == "0.00e9 +/- 0.76e9"
assert value_str(12356,76400000) == "0.000e9 +/- 0.076e9"
assert value_str(1235,7640000) == "0.0e6 +/- 7.6e6"
assert value_str(123,764000) == "0.00e6 +/- 0.76e6"
assert value_str(12,76400) == "0.000e6 +/- 0.076e6"
assert value_str(1,7640) == "0.0e3 +/- 7.6e3"
assert value_str(0.1,764) == "0.00e3 +/- 0.76e3"
assert value_str(0.01,76.4) == "0.000e3 +/- 0.076e3"
assert value_str(0.001,7.64) == "0.0 +/- 7.6"
assert value_str(0.0001,0.764) == "0.00 +/- 0.76"
assert value_str(0.00001,0.0764) == "0.000 +/- 0.076"
assert value_str(0.000001,0.00764) == "0.0e-3 +/- 7.6e-3"
# Zero values
assert value_str(0,7640000) == "0.0e6 +/- 7.6e6"
assert value_str(0, 764000) == "0.00e6 +/- 0.76e6"
assert value_str(0, 76400) == "0.000e6 +/- 0.076e6"
assert value_str(0, 7640) == "0.0e3 +/- 7.6e3"
assert value_str(0, 764) == "0.00e3 +/- 0.76e3"
assert value_str(0, 76.4) == "0.000e3 +/- 0.076e3"
assert value_str(0, 7.64) == "0.0 +/- 7.6"
assert value_str(0, 0.764) == "0.00 +/- 0.76"
assert value_str(0, 0.0764) == "0.000 +/- 0.076"
assert value_str(0, 0.00764) == "0.0e-3 +/- 7.6e-3"
assert value_str(0, 0.000764) == "0.00e-3 +/- 0.76e-3"
assert value_str(0, 0.0000764) == "0.000e-3 +/- 0.076e-3"
# negative values
assert value_str(-1235670,766000) == "-1.24e6 +/- 0.77e6"
assert value_str(-1.23567,.766) == "-1.24 +/- 0.77"
assert value_str(-.00000123567,.0000000766) == "-1.236e-6 +/- 0.077e-6"
assert value_str(-12356.7,7.64) == "-12356.7 +/- 7.6"
assert value_str(-123.567,764) == "-0.12e3 +/- 0.76e3"
assert value_str(-1235.67,76400) == "-0.001e6 +/- 0.076e6"
assert value_str(-.000123567,.00764) == "-0.1e-3 +/- 7.6e-3"
assert value_str(-12356,7640000) == "-0.0e6 +/- 7.6e6"
assert value_str(-12,76400) == "-0.000e6 +/- 0.076e6"
assert value_str(-0.0001,0.764) == "-0.00 +/- 0.76"
# non-finite values
assert value_str(-numpy.inf,None) == "-inf"
assert value_str(numpy.inf,None) == "inf"
assert value_str(numpy.NaN,None) == "NaN"
# bad or missing uncertainty
assert value_str(-1.23567,numpy.NaN) == "-1.23567"
assert value_str(-1.23567,-numpy.inf) == "-1.23567"
assert value_str(-1.23567,-0.1) == "-1.23567"
assert value_str(-1.23567,0) == "-1.23567"
assert value_str(-1.23567,None) == "-1.23567"
assert value_str(-1.23567,numpy.inf) == "-1.2 +/- inf"
def test_max_digits():
# extreme uncertainty
assert format_uncertainty_compact(1.234567890123456789e20,0.00764) == "123.456789012346(0)e18"
assert format_uncertainty_pm(1.234567890123456789e20,0.00764) == "123.456789012346e18 +/- 0.000000000000e18"
assert format_value(1.234567890123456789e20,0.00764) == "123.456789012346e18"
assert format_uncertainty_compact(1.234567890123456789e20,0.00764,max_digits=5) == "123.46(0)e18"
assert format_uncertainty_pm(1.234567890123456789e20,0.00764,max_digits=5) == "123.46e18 +/- 0.00e18"
assert format_value(1.234567890123456789e20,0.00764,max_digits=5) == "123.46e18"
assert format_uncertainty_compact(1.234567890123456789e1,0.00764,max_digits=5) == "12.346(8)"
assert format_uncertainty_pm(1.234567890123456789e1,0.00764,max_digits=5) == "12.346 +/- 0.008"
assert format_value(1.234567890123456789e1,0.00764,max_digits=5) == "12.346"
def test():
# Check compact and plus/minus formats
test_compact()
test_pm()
test_max_digits()
# Check that the default is the compact format
assert format_uncertainty(-1.23567,0.766) == "-1.24(77)"
import doctest
doctest.testmod()
if __name__ == "__main__": test()