自定义支持 float 的 range 函数

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/eastossifrage/article/details/100670351

python range() 函数是步进函数,可快速优雅地创建一个整数列表,一般用在 for 循环中。但是 python 自带的 range() 步进函数只支持整数类型,不支持浮点数。那么,为了支持浮点数,我们只能自定义一个函数。

1、Python 内建函数 range() 的语法

range(start, stop[, step])

1.1、参数说明:

  • start: 计数从 start 开始。默认是从 0 开始。例如range(5)等价于range(0, 5);
  • stop: 计数到 stop 结束,但不包括 stop。例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5
  • step:步长,默认为1。例如:range(0, 5) 等价于 range(0, 5, 1)

1.2、运行实例

>>> list(range(2, 98, 3))
[2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95]

2、自定义支持 float 的步进函数

2.1、功能要求

  输入 Input:
      start (float)  : 计数从 start 开始。默认是从 0 开始。
      end   (float)  : 计数到 stop 结束,但不包括 stop。
      step (float)  : 步长,默认为 1,如为浮点数,参照 steps 小数位数。

  输出 Output:
      float 数据类型的列表

按照上面的功能要求,我的思路是利用原有的、只支持整数的 range 函数。那么就需要将 step 这个浮点型数据转换成整型类型,这不是简单的舍去小数取整数,而是将小数部分乘以适当的 10**n(n 为小数部分的位数),整体将浮点数转换成整型。

2.2、取 step 的小数位数

2.2.1、试错1-利用简单的算术运算

>>> import math
>>> b = math.modf(5.02)
>>> b
(0.019999999999999574, 5.0)
>>> b[0]
0.019999999999999574
>>> float(5.02)-int(5.02)
0.019999999999999574
>>> 5.02 - int(5.02)
0.019999999999999574
>>>

很明显,由于 Python 的浮点数的精度问题,我们使用简单的算术运算方法无法获得精准的小数位数。

2.2.2、试错2-decimal 模块

>>> import decimal
>>> decimal.Decimal(5.02)
Decimal('5.019999999999999573674358543939888477325439453125')
>>> decimal.Decimal(5.02) -decimal.Decimal(5)
Decimal('0.01999999999999957367435854394')

很遗憾,这个小数部分也会自动变长,无法达到自己的要求。而 decimal 模块种的 getcontext().prec
可以设置有效的小数位数,但是无法读取给定的浮点数的小数位数。故这个模块也无法解决自己的问题。

2.2.3、 将浮点数转换成字符串

>>> str(48.36).index(".")
2
>>> len(str(48.36))
5
>>> len(str(48.36))-1-str(48.36).index(".") # 此处减 1 是因为小数点也占一位
2         # 得出小数部分的位数

2.3、自定义支持 float 的步进函数

def float_range(start, stop, step):
    ''' 支持 float 的步进函数

        输入 Input:
            start (float)  : 计数从 start 开始。默认是从 0 开始。
            end   (float)  : 计数到 stop 结束,但不包括 stop。
            step (float)  : 步长,默认为 1,如为浮点数,参照 steps 小数位数。

        输出 Output:
            浮点数列表

        例子 Example:
            >>> print(float_range(3.612, 5.78, 0.22))
            [3.612, 3.832, 4.052, 4.272, 4.492, 4.712, 4.932, 5.152, 5.372]
    '''
    start_digit = len(str(start))-1-str(start).index(".") # 取开始参数小数位数
    stop_digit = len(str(stop))-1-str(stop).index(".")    # 取结束参数小数位数
    step_digit = len(str(step))-1-str(step).index(".")    # 取步进参数小数位数
    digit = max(start_digit, stop_digit, step_digit)      # 取小数位最大值
    return [(start*10**digit+i*step*10**digit)/10**digit for i in range(int((stop-start)//step))]

另一种更简单的选择

如果你跟随我的思路,理解了这些内容,那么其实最后的 float_range 函数中有一些多余的内容。
只要你的需求中能够忽视小数的精度问题,那么你可以使用如下函数:

def float_range(start, stop, step):
    ''' 支持 float 的步进函数

        输入 Input:
            start (float)  : 计数从 start 开始。默认是从 0 开始。
            end   (float)  : 计数到 stop 结束,但不包括 stop。
            step (float)  : 步长,默认为 1,如为浮点数,参照 steps 小数位数。

        输出 Output:
            浮点数列表

        例子 Example:
            >>> print(float_range(3.612, 5.78, 0.22))
            [3.612, 3.8320000000000003, 4.0520000000000005, 4.272, 4.492, 4.712, 4.932, 5.152, 5.372]
    '''

    return [start+i*step for i in range(int((stop-start)//step))]

其实这个函数的实现只需要最后的列表推导即可,但是列表中的浮点数的小数精度可能不随人愿。

猜你喜欢

转载自blog.csdn.net/eastossifrage/article/details/100670351
今日推荐