## Python internal metric unit conversion function

python unit conversion
python units
assigning units in python
python pint
python imperial to metric conversion
python-measurement conversion
how to make a converter in python
unit converter module in python

I'm trying to build a function to do internal metric conversion on a wavelength to frequency conversion program and have been having a hard time getting it to behave properly. It is super slow and will not assign the correct labels to the output. If anyone can help with either a different method of computing this or a reason on why this is happening and any fixes that I cond do that would be amazing!

def convert_SI_l(n):
if n in range( int(1e-12),int(9e-11)):
return n/0.000000000001, 'pm'
else:
if n in range(int(1e-10),int(9e-8)):
return n/0.000000001 , 'nm'
else:
if n in range(int(1e-7),int(9e-5)):
return n/0.000001, 'um'
else:
if n in range(int(1e-4),int(9e-3)):
return n/0.001, 'mm'
else:
if n in range(int(0.01), int(0.99)):
return n/0.01, 'cm'
else:
if n in range(1,999):
return n/1000, 'm'
else:
if n in range(1000,299792459):
return n/1000, 'km'
else:
return n , 'm'

def convert_SI_f(n):
if n in range( 1,999):
return n, 'Hz'
else:
if n in range(1000,999999):
return n/1000 , 'kHz'
else:
if n in range(int(1e6),999999999):
return n/1e6, 'MHz'
else:
if n in range(int(1e9),int(1e13)):
return n/1e9, 'GHz'
else:
return n, 'Hz'

c=299792458

i=input("Are we starting with a frequency or a wavelength? ( F / L ):  ")

#Error statements
if i.lower() == ("f"):
True
else:
if not i.lower() == ("l"):
print ("Error invalid input")

#Cases
if i.lower() == ("f"):
f = float(input("Please input frequency (in Hz):  "))
size_l = c/f
print(convert_SI_l(size_l))

if i.lower() == ("l"):
l = float(input("Please input wavelength (in meters):  "))
size_f = ( l/c)
print(convert_SI_f(size_f))

You are using range() in a way that is close to how it is used in natural language, to express a contiguous segment of the real number line, as in in the range 4.5 to 5.25. But range() doesn't mean that in Python. It means a bunch of integers. So your floating-point values, even if they are in the range you specify, will not occur in the bunch of integers that the range() function generates.

if n in range( int(1e-12),int(9e-11)):

and I am guessing you wrote it like this because what you actually wanted was range(1e-12, 9e-11) but you got TypeError: 'float' object cannot be interpreted as an integer.

But if you do this at the interpreter prompt

>>> range(int(1e-12),int(9e-11))
range(0, 0)
>>> list(range(int(1e-12),int(9e-11)))
[]

you will see it means something quite different to what you obviously expect.

To test if a floating-point number falls in a given range do

if lower-bound <= mynumber <= upper-bound:

[PDF] python-measurement Documentation, python-measurement Documentation, Release 1.0 Warning: Measurements are stored internally by converting them to a floating-point Note: Python has restrictions on what can be used as a method attribute; if you are not� I ended up writing my own python package for unit conversion and dimensional analysis, but it is not properly packaged for release yet. We are using my unit system in the python bindings for our OpenMM system for GPU accelerated molecular mechanics. You can browse the svn repository of my python units code at: SimTK python units

You don't need ranges and your logic will be more robust if you base it on fixed threshold points that delimit the unit magnitude. This would typically be a unit of one in the given scale.

Here's a generalized approach to all unit scale determination:

SI_Length = [ (1/1000000000000,"pm"),
(1/1000000000,   "nm"),
(1/1000000,      "um"),
(1/1000,         "mm"),
(1/100,          "cm"),
(1,              "m"),
(1000,           "km") ]

SI_Frequency = [ (1, "Hz"), (1000,"kHz"), (1000000,"MHz"), (1000000000,"GHz")]

def convert(n,units):
useFactor,useName = units[0]
for factor,name in units:
if n >= factor : useFactor,useName = factor,name
return (n/useFactor,useName)

print(convert(0.0035,SI_Length)) # 3.5 mm
print(convert(12332.55,SI_Frequency)) # 12.33255 kHz

Each unit array must be in order of smallest to largest multiplier.

units � PyPI, Python support for quantities with units. because a NASA subcontractor ( Lockheed Martin) used Imperial units (pound-seconds) instead of the metric system. Function module MATERIAL_UNIT_CONVERSION will convert material units of measure. It will covert either from an alternate uom to base uom or from base uom to alternate uom. If you need to go from alternate uom to base uom, you will need to call it multiple times. There are other function modules, but this one does not have any restrictions for the

EDIT: Actually, range is a function which is generally used in itaration to generate numbers. So, when you write if n in range(min_value, max_value), this function generates all integers until it finds a match or reach the max_value.

The range type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in for loops.

if n in range(int(1e-10),int(9e-8)):
return n/0.000000001 , 'nm'

you should write:

if 1e-10 <= n < 9e-8:
return n/0.000000001 , 'nm'

Also keep in mind that range only works on integers, not float.

More EDIT:

For your specific use case, you can define dictionary of *(value, symbol) pairs, like below:

import collections

symbols = collections.OrderedDict(
[(1e-12, u'p'),
(1e-9, u'n'),
(1e-6, u'μ'),
(1e-3, u'm'),
(1e-2, u'c'),
(1e-1, u'd'),
(1e0, u''),
(1e1, u'da'),
(1e2, u'h'),
(1e3, u'k'),
(1e6, u'M'),
(1e9, u'G'),
(1e12, u'T')])

The use the bisect.bisect function to find the "insertion" point of your value in that ordered collection. This insertion point can be used to get the simplified value and the SI symbol to use.

For instance:

import bisect

def convert_to_si(value):
if value < 0:
value, symbol = convert_to_si(-value)
return -value, symbol
elif value > 0:
orders = list(symbols.keys())
order_index = bisect.bisect(orders, value / 10.0)
order = orders[min(order_index, len(orders) - 1)]
return value / order, symbols[order]
else:
return value, u""

Demonstration:

for value in [1e-12, 3.14e-11, 0, 2, 20, 3e+9]:
print(*convert_to_si(value), sep="")

You get:

1.0p
0.0314n
0
2.0
2.0da
3.0G