Really short snipped of a decimal and binary prefix calculator in Python.
Without covering the entire International System of Units (SI) range, it does fit my daily needs.
The code could be way smarter, but i wanted to keep the recipe as basic as i could.
Tested on Python 2.4.1
and 2.6.4;
could work on lower as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def binary_prefix(value, binary=True):
'''Return a tuple with a scaled down version of value and it's binary prefix
Parameters:
- `value`: numeric type to trim down
- `binary`: use binary (ICE) or decimal (SI) prefix
'''
SI = 'kMGTPEZY'
unit = binary and 1024. or 1000.
for i in range(-1, len(SI)):
if abs(value) < unit:
break
value/= unit
return (value, i<0 and '' or (binary and SI[i].upper() + 'i' or SI[i]))
|
Usage:
>>> ['%.2f %sB' % binary_prefix(nbr) for nbr in (12, 1023, 1028, 4096, 1<<16, 1<<32, 1<<128)]
['12.00 B', '1023.00 B', '1.00 KiB', '4.00 KiB', '64.00 KiB', '4.00 GiB', '274877906944.00 YiB']
>>> [k % binary_prefix(v, False) for k,v in {'modem %u %s':56000, 'SATA %u %sb/s':3*10**9, 'Ethernet %u%sb/s': 10**7, 'income %.1f %s EUR':-7**8}.iteritems()]
['income -5.8 M EUR', 'modem 56 k', 'SATA 3 Gb/s', 'Ethernet 10Mb/s']
>>> print '%.3f %s' % binary_prefix(12e255)
9.69e+228 Yi
Notes:
- i choose to not use
result_if_True if condition else result_if_False
because the ternary operator appeared only in Python 2.5 - really slight optimization could be done by storing the sign of
value
(i.e.:sign = value/abs(value)
) and restoring it at the end (i.e.:return (value*sign, ...
) instead of usingabs()
in the loop; i choose simplicity
Bugs:
It is not fool-proof; it does comes with the Python limitations. On my computer:
>>> binary_prefix((1e200 * 1e200) / (1e200 * 1e200))
(nan, 'Yi')
>>> binary_prefix(1e200 * 1e200)
(inf, 'Yi')
>>> binary_prefix(2**1e200)
Traceback (most recent call last):
...
OverflowError: (34, 'Numerical result out of range')
>>> binary_prefix(2**9999)
Traceback (most recent call last):
...
OverflowError: long int too large to convert to float