Welcome, guest | Sign In | My Account | Store | Cart

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.

Python, 14 lines
 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 using abs() 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