libdev 0.92__tar.gz → 0.93__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {libdev-0.92 → libdev-0.93}/PKG-INFO +1 -1
- {libdev-0.92 → libdev-0.93}/libdev/__init__.py +1 -1
- {libdev-0.92 → libdev-0.93}/libdev/num.py +87 -1
- {libdev-0.92 → libdev-0.93}/libdev.egg-info/PKG-INFO +1 -1
- {libdev-0.92 → libdev-0.93}/tests/test_num.py +16 -0
- {libdev-0.92 → libdev-0.93}/LICENSE +0 -0
- {libdev-0.92 → libdev-0.93}/README.md +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/cfg.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/check.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/codes.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/crypt.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/dev.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/doc.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/fin.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/gen.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/img.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/lang.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/log.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/req.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/s3.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev/time.py +0 -0
- {libdev-0.92 → libdev-0.93}/libdev.egg-info/SOURCES.txt +0 -0
- {libdev-0.92 → libdev-0.93}/libdev.egg-info/dependency_links.txt +0 -0
- {libdev-0.92 → libdev-0.93}/libdev.egg-info/requires.txt +0 -0
- {libdev-0.92 → libdev-0.93}/libdev.egg-info/top_level.txt +0 -0
- {libdev-0.92 → libdev-0.93}/setup.cfg +0 -0
- {libdev-0.92 → libdev-0.93}/setup.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_cfg.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_check.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_codes.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_crypt.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_dev.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_doc.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_gen.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_img.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_lang.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_log.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_req.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_s3.py +0 -0
- {libdev-0.92 → libdev-0.93}/tests/test_time.py +0 -0
|
@@ -4,7 +4,21 @@ Numbers functionality
|
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
6
|
import math
|
|
7
|
-
from decimal import Decimal
|
|
7
|
+
from decimal import Decimal, ROUND_HALF_UP
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
_SUBSCRIPTS = {
|
|
11
|
+
"0": "₀",
|
|
12
|
+
"1": "₁",
|
|
13
|
+
"2": "₂",
|
|
14
|
+
"3": "₃",
|
|
15
|
+
"4": "₄",
|
|
16
|
+
"5": "₅",
|
|
17
|
+
"6": "₆",
|
|
18
|
+
"7": "₇",
|
|
19
|
+
"8": "₈",
|
|
20
|
+
"9": "₉",
|
|
21
|
+
}
|
|
8
22
|
|
|
9
23
|
|
|
10
24
|
def is_float(value: str) -> bool:
|
|
@@ -242,3 +256,75 @@ def to_step(value, step=1, side=False):
|
|
|
242
256
|
value = int(value)
|
|
243
257
|
|
|
244
258
|
return value
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _to_subscript(n: int) -> str:
|
|
262
|
+
"""Convert an integer n to a string of subscript digits."""
|
|
263
|
+
return "".join(_SUBSCRIPTS[d] for d in str(n))
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def compress_zeros(x: int | float, round: int | None = None) -> str | None:
|
|
267
|
+
"""
|
|
268
|
+
Given a float or decimal‐string x, return a string where
|
|
269
|
+
runs of leading zeros in the fraction are shown as:
|
|
270
|
+
one '0' plus a subscript count of the zeros.
|
|
271
|
+
If `round` is provided, the remaining digits after the zeros
|
|
272
|
+
are rounded to that many places.
|
|
273
|
+
|
|
274
|
+
Examples:
|
|
275
|
+
compress_zeros(0.00012) -> '0.0₃12'
|
|
276
|
+
compress_zeros(0.00012, round=2) -> '0.0₃12'
|
|
277
|
+
compress_zeros(0.0123) -> '0.0123' (only one leading zero, so unchanged)
|
|
278
|
+
compress_zeros(0.0123456, round=3)-> '0.0123'
|
|
279
|
+
compress_zeros(1.000045) -> '1.0₄45'
|
|
280
|
+
compress_zeros(-0.0010959999999999997522, round=3)
|
|
281
|
+
-> '-0.0₂11'
|
|
282
|
+
"""
|
|
283
|
+
|
|
284
|
+
if x is None:
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
dec_x = Decimal(str(x))
|
|
288
|
+
s = format(dec_x, "f")
|
|
289
|
+
|
|
290
|
+
# no fractional part
|
|
291
|
+
if "." not in s:
|
|
292
|
+
return s
|
|
293
|
+
|
|
294
|
+
int_part, frac = s.split(".", 1)
|
|
295
|
+
|
|
296
|
+
# count leading zeros in the fractional part
|
|
297
|
+
zero_run = len(frac) - len(frac.lstrip("0"))
|
|
298
|
+
|
|
299
|
+
# If rounding is requested, do it first
|
|
300
|
+
if round is not None:
|
|
301
|
+
# ensure at least one zero is counted for quantization
|
|
302
|
+
places = max(zero_run, 1) + round
|
|
303
|
+
quant = Decimal(f"1e-{places}")
|
|
304
|
+
dec_q = dec_x.quantize(quant, rounding=ROUND_HALF_UP)
|
|
305
|
+
s_q = format(dec_q, "f")
|
|
306
|
+
|
|
307
|
+
# if rounding eliminated fractional part
|
|
308
|
+
if "." not in s_q:
|
|
309
|
+
return s_q
|
|
310
|
+
|
|
311
|
+
int_part_q, frac_q = s_q.split(".", 1)
|
|
312
|
+
# for zero_run == 0 or 1, we just return the rounded string
|
|
313
|
+
if zero_run <= 1:
|
|
314
|
+
return s_q
|
|
315
|
+
|
|
316
|
+
# strip any trailing zeros, then compress
|
|
317
|
+
frac_q = frac_q.rstrip("0")
|
|
318
|
+
if not frac_q:
|
|
319
|
+
return int_part_q
|
|
320
|
+
tail = frac_q[zero_run:]
|
|
321
|
+
return f"{int_part_q}.0{_to_subscript(zero_run)}{tail}"
|
|
322
|
+
|
|
323
|
+
# No rounding: only compress if more than one leading zero
|
|
324
|
+
if zero_run <= 1:
|
|
325
|
+
return s
|
|
326
|
+
|
|
327
|
+
tail = frac[zero_run:]
|
|
328
|
+
|
|
329
|
+
# build compressed form
|
|
330
|
+
return f"{int_part}.0{_to_subscript(zero_run)}{tail}"
|
|
@@ -11,6 +11,7 @@ from libdev.num import (
|
|
|
11
11
|
to_step,
|
|
12
12
|
add,
|
|
13
13
|
pretty,
|
|
14
|
+
compress_zeros,
|
|
14
15
|
)
|
|
15
16
|
|
|
16
17
|
|
|
@@ -155,3 +156,18 @@ def test_pretty():
|
|
|
155
156
|
assert pretty(123.456, 1) == "123"
|
|
156
157
|
assert pretty(123.456, 1, True) == "+123"
|
|
157
158
|
assert pretty(12345.6, 3, True) == "+12’346"
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_compress_zeros():
|
|
162
|
+
assert compress_zeros(None) == None
|
|
163
|
+
assert compress_zeros(0) == "0"
|
|
164
|
+
assert compress_zeros(0.0) == "0.0"
|
|
165
|
+
assert compress_zeros(1) == "1"
|
|
166
|
+
assert compress_zeros(1.0) == "1.0"
|
|
167
|
+
assert compress_zeros(1.0, round=0) == "1.0"
|
|
168
|
+
assert compress_zeros(0.00012) == "0.0₃12"
|
|
169
|
+
assert compress_zeros(0.00012, round=2) == "0.0₃12"
|
|
170
|
+
assert compress_zeros(0.0123) == "0.0123"
|
|
171
|
+
assert compress_zeros(0.0123456, round=3) == "0.0123"
|
|
172
|
+
assert compress_zeros(1.000045) == "1.0₄45"
|
|
173
|
+
assert compress_zeros(-0.0010959999999999997522, round=3) == "-0.0₂11"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|