Metric Prefixes in Python
This is an updated version of an article I wrote in 2019 and now includes quetta, ronna, quecto and ronto, new prefixes introduced in 2022.
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 quetta and right down to quecto.
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 symbols, 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.
The code for this project consists of a single file called metricprefixes.py which you can clone or download from Github. This is the code in its entirety.
from typing import List
def main():
print("-------------------")
print("| codedrome.com |")
print("| Metric Prefixes |")
print("-------------------\n")
base10_list = create_base10_list()
print_base10(base10_list)
print()
base2_list = create_base2_list()
print_base2(base2_list)
def create_base10_list() -> List:
"""
Create a list of base 10 prefixes
with corresponding symbols and powers.
"""
base10 = [{"prefix": "quetta", "power": 30, "symbol": "Q"},
{"prefix": "ronna", "power": 27, "symbol": "R"},
{"prefix": "yotta", "power": 24, "symbol": "Y"},
{"prefix": "zetta", "power": 21, "symbol": "Z"},
{"prefix": "exa", "power": 18, "symbol": "E"},
{"prefix": "peta", "power": 15, "symbol": "P"},
{"prefix": "tera", "power": 12, "symbol": "T"},
{"prefix": "giga", "power": 9, "symbol": "G"},
{"prefix": "mega", "power": 6, "symbol": "M"},
{"prefix": "kilo", "power": 3, "symbol": "k"},
{"prefix": "hecto", "power": 2, "symbol": "h"},
{"prefix": "deca", "power": 1, "symbol": "da"},
{"prefix": "~", "power": 0, "symbol": "~"},
{"prefix": "deci", "power": -1, "symbol": "d"},
{"prefix": "centi", "power": -2, "symbol": "c"},
{"prefix": "milli", "power": -3, "symbol": "m"},
{"prefix": "micro", "power": -6, "symbol": "undefined"},
{"prefix": "nano", "power": -9, "symbol": "n"},
{"prefix": "pico", "power": -12, "symbol": "p"},
{"prefix": "femto", "power": -15, "symbol": "f"},
{"prefix": "atto", "power": -18, "symbol": "a"},
{"prefix": "zepto", "power": -21, "symbol": "z"},
{"prefix": "yocto", "power": -24, "symbol": "y"},
{"prefix": "ronto", "power": -27, "symbol": "r"},
{"prefix": "quecto", "power": -30, "symbol": "q"}]
return base10
def print_base10(base10_list: List):
"""
Use list from create_base10_list function
to print prefixes, powers and values.
"""
for b in base10_list:
print(f" {b['prefix']:8s}", end="")
print(f"{b['symbol']:4s}", end="")
print(f"10^{b['power']:<3} = ", end="")
if b["power"] >= 0:
print(f"{10**b['power']:>32}")
else:
# this ensures negative power values
# are printed in full rather than
# 1e-06 etc.
prec=abs(b["power"])
print(f"{10**b['power']:>32.{prec}f}")
def create_base2_list() -> 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: 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"]))
if __name__ == "__main__":
main()
The main function simply calls the four functions which come next.
The create_base10_list function initializes and returns a list of dictionaries, holding all the prefix 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:
python3 metricprefixes.py
The output is:
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 buy a 1 yobibyte drive?