SI Prefixes

Most people are familiar with a few of the more common prefixes used before many units to denote a fraction or a multiple of the unit - kilograms, megabytes, centimetres etc.. As well as these there a number of less well known ones, going right up to yotta and right down to yocto.

As a simple but hopefully enlightening programming exercise I have put together this short Python program to list all the prefixes along with their corresponding powers and multipliers.

If you are the sort of person who reads programming blogs like this one you will know that using kilo, mega, giga etc. to prefix the word "byte" is technically inaccurate. Way back in 1998 an organisation called The International Electrotechnical Commission came up with a set of alternatives to apply to computer memory which is measured in powers of 2 rather than powers of 10. Instead of kilobyte/megabyte/gigabyte etc. their sequence goes kibibyte/mebibyte/gibibyte etc.. This has never caught on of course, and these proposed alternatives have languished in obscurity for the last two decades. This is presumably because the strictly innaccurate kilo/mega/giga usage already had an unstoppable inertia; it might also be because kibi, mebi and gibi just sound plain silly. Despite that I will include them in this project.

To get started create a new folder somewhere and within it create an empty file called siprefixes.py. You can download the source code from the Downloads page or clone/download from Github if you prefer. Open the file and type or paste this code.

siprefixes.py

def main():

    """
    Call functions to create lists of prefixes and powers
    in base 10 and base 2, then print them.
    """

    print("-------------------------------------\n| code-in-python.com - SI Prefixes  |\n-------------------------------------\n")

    base10_list = create_base10_list()

    print_base10(base10_list)

    print("")

    base2_list = create_base2_list()

    print_base2(base2_list)

#-----------------------------------------------------

def create_base10_list():

    """
    Create a list of base 10 prefixes with corresponding powers.
    """

    base10 = [{"prefix": "yotta", "power": 24},
              {"prefix": "zetta", "power": 21},
              {"prefix": "exa", "power": 18},
              {"prefix": "peta", "power": 15},
              {"prefix": "tera", "power": 12},
              {"prefix": "giga", "power": 9},
              {"prefix": "mega", "power": 6},
              {"prefix": "kilo", "power": 3},
              {"prefix": "hecto", "power": 2},
              {"prefix": "deca", "power": 1},

              {"prefix": "(none)", "power": 0},

              {"prefix": "deci", "power": -1},
              {"prefix": "centi", "power": -2},
              {"prefix": "milli", "power": -3},
              {"prefix": "micro", "power": -6},
              {"prefix": "nano", "power": -9},
              {"prefix": "pico", "power": -12},
              {"prefix": "femto", "power": -15},
              {"prefix": "atto", "power": -18},
              {"prefix": "zepto", "power": -21},
              {"prefix": "yocto", "power": -24}]

    return base10

#-----------------------------------------------------

def print_base10(base10_list):

    """
    Use list from create_base10_list function
    to print prefixes, powers and values.
    """

    for b in base10_list:

        if b["power"] >= 0:
            print("{:6s} 10^{:<3} = {:>26}".format(b["prefix"], b["power"], 10**b["power"]))
        else:
            print("{:6s} 10^{:<3} = {:>26.{prec}f}".format(b["prefix"], b["power"], 10**b["power"], prec=abs(b["power"])))

#-----------------------------------------------------

def create_base2_list():

    """
    Create a list of base 2 prefixes with corresponding powers.
    """

    base2 = [{"prefix": "kibibyte", "power": 10},
             {"prefix": "mebibyte", "power": 20},
             {"prefix": "gibibyte", "power": 30},
             {"prefix": "tebibyte", "power": 40},
             {"prefix": "pebibyte", "power": 50},
             {"prefix": "exbibyte", "power": 60},
             {"prefix": "zebibyte", "power": 70},
             {"prefix": "yobibyte", "power": 80}]

    return base2

#-----------------------------------------------------

def print_base2(base2_list):

    """
    Use list from create_base2_list function
    to print prefixes, powers and values.
    """

    for b in base2_list:

        print("1 {}: 2^{} = {:>33,} bytes".format(b["prefix"], b["power"], 2**b["power"]))

#-----------------------------------------------------

main()

The main function simply calls the four functions which come next.

The create_base10_list initializes and returns a list of dictionaries, holding all the prefixe and power pairs. The next function is print_base10 which takes the list from create_base10_list and prints out the prefix, the power equation, and the multiplier.

The next two functions are create_base2_list and print_base2 which replicate the functionality of the previous functions but for the base 2 memory prefixes.

That's all there is to the code so run it with this command:

Run

python3.6 siprefixes.py

The output is

Program Output

------------------------------------
| code-in-python.com - SI Prefixes |
------------------------------------

yotta  10^24  =  1000000000000000000000000
zetta  10^21  =     1000000000000000000000
exa    10^18  =        1000000000000000000
peta   10^15  =           1000000000000000
tera   10^12  =              1000000000000
giga   10^9   =                 1000000000
mega   10^6   =                    1000000
kilo   10^3   =                       1000
hecto  10^2   =                        100
deca   10^1   =                         10
(none) 10^0   =                          1
deci   10^-1  =                        0.1
centi  10^-2  =                       0.01
milli  10^-3  =                      0.001
micro  10^-6  =                   0.000001
nano   10^-9  =                0.000000001
pico   10^-12 =             0.000000000001
femto  10^-15 =          0.000000000000001
atto   10^-18 =       0.000000000000000001
zepto  10^-21 =    0.000000000000000000001
yocto  10^-24 = 0.000000000000000000000001

1 kibibyte: 2^10 =                             1,024 bytes
1 mebibyte: 2^20 =                         1,048,576 bytes
1 gibibyte: 2^30 =                     1,073,741,824 bytes
1 tebibyte: 2^40 =                 1,099,511,627,776 bytes
1 pebibyte: 2^50 =             1,125,899,906,842,624 bytes
1 exbibyte: 2^60 =         1,152,921,504,606,846,976 bytes
1 zebibyte: 2^70 =     1,180,591,620,717,411,303,424 bytes
1 yobibyte: 2^80 = 1,208,925,819,614,629,174,706,176 bytes

The powers of 10 exhibit a very satisfying symmetry, as well as some staggering largeness and smallness at the extreme ends. The measures of memory don't take us to such extremes but are large enough for the time being. I wonder how long it will be before we can go out and buy a 1 yobibyte drive?