简体   繁体   English

Python内部度量单位转换功能

[英]Python internal metric unit conversion function

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))

EDIT: Actually, range is a function which is generally used in itaration to generate numbers. 编辑:实际上, range是通常在义化中用于生成数字的函数。 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 . 所以,当你写 if n in range(min_value, max_value)该函数生成的所有整数,直到找到一个匹配或达到 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. range类型表示数字的不可变序列,并通常用于在循环的特定次数for环路。

Instead of writing: 而不是写:

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. 还请记住, range仅适用于整数,不适用于浮点数。

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. 使用bisect.bisect函数可在该有序集合中找到值的“插入”点。 This insertion point can be used to get the simplified value and the SI symbol to use. 该插入点可用于获取简化值和要使用的SI符号。

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

You can adapt this function to your needs… 您可以根据需要调整此功能…

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 . 您正在以接近自然语言的方式使用range() ,以表示实数线的连续段,如4.5到5.25所示 But range() doesn't mean that in Python. 但是range()在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. 因此,即使在指定范围内 ,浮点值也不会出现在range()函数生成的一堆整数中。

Your first test is 你的第一个测试是

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 . 我猜你是这样写的,因为你真正想要的是range(1e-12, 9e-11)但是你得到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:

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. 每个单位数组必须按最小到最大的倍数顺序排列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM