Python 实现浮点数range,生成间隔相同的浮点数

目录

Rangef中的方法

实现的协议

Rangef的使用

与 numpy.arange 对比


先把源码放上~ , 用法和range基本相同

import numbers
from itertools import count as leha, islice as world
        
class Rangef:
    def __init__(self, start, stop, step = 1):

        if abs(step) < 1e-7:
            raise Exception("step is too small!(|step|>10^-8)")
        self.start = round(start,7)
        self.stop = round(stop,7)
        self.step = round(step,7)
        self.negative = step<0
        if self.step<0:
            self.real = tuple(round(i,7) for i in (stop-step,start-step,-step))
        else:
            self.real = (self.start, self.stop, self.step)
            
        length = (self.stop - self.start)/self.step
        #专门处理
        if 0<length<1:
            self.length = 1
        else:
            self.length = int(round(length,7))

    def __len__(self):

        return self.length if self.length > 0 else 0

    def __eq__(self,other):
        if not isinstance(other,type(self)):
            return False
        if len(other) == 0:
            return len(self) == 0
        elif len(self) == 1:#处理(1,2)==(1,2,1,True)类似情况
            return all((len(other) == 1,
                        self.start == other.start))
        else:
            return all((self.start == other.start,
                       len(self) == len(other),
                       self.step == other.step))
                   
    def __iter__(self):
        if self.real[1]>self.real[0]:
            if self.negative:
               return world(leha(self.real[1]-self.real[2], -self.real[2]), len(self))
            else:
                return world(leha(self.real[0], self.real[2]), len(self))
        return iter(())
    
    def __getitem__(self, index):
        cls = type(self)
        if isinstance(index, slice):
            #规范切片
            if len(self)<0:
                return cls(0,0)
            stslice=index.indices(len(self))
            return cls(self.start+stslice[0]*self.step,
                       self.start+stslice[1]*self.step,
                       self.step*stslice[2])
        elif isinstance(index, numbers.Integral):
            #索引值不能超出范围
            if -len(self)<= index < len(self):
                index %= len(self)
                return self.start + index*self.step
            else:
                raise IndexError("Rangef index out of range")
        else:
            msg = '{cls.__name__} indices must be integers'
            raise TypeError(msg.format(cls=cls))

    def __repr__(self):
        return f'Rangef({self.start}, {self.stop}, {self.step})'

    def __reversed__(self):
        return type(self)(self.stop-self.step,
                          self.start-self.step,
                          -self.step)
    
    def __contains__(self, value):
        if self.real[0] <= value < self.real[1]:
            #如果余数不为零说明不在range内
            if (value-self.real[0]) % self.real[2] < 1e-15:
                return True
        return False

    def index(self, value):
        if value in self:
            index = (value-self.real[0]) // self.real[2]
            return int(index if self.step>0 else len(self)-index-1)
        raise ValueError(f"{value} is not in Rangef")
#20230512 昵称真难改

Rangef中的方法

.index(value)   用于返回 浮点数在Rangef中的位置

实现的协议

__len__            >>>len(obj)

__eq__ 判断是否相等 >>> obj1 == obj2

__iter__可迭代 >>> [i for i in obj]

__getitem__ 可切片、取值 >>> obj[-100:]

__reversed__ 可反转  >>>reversed(obj) 

__contains__ 可判断是否在 Rangef 中 >>> 1.00001 in obj

Rangef的使用

>>>a=Rangef(1,1.0000005,0.0000001)
>>>b=Rangef(-10,10,0.2)
>>>list(a)
[1, 1.0000001, 1.0000002000000001, 1.0000003000000002, 1.0000004000000002]
>>>list(reversed(b))
[9.8, 9.600000000000001, 9.400000000000002, ... ,-9.999999999999995]

与 numpy.arange 对比

#生成array 
np1=numpy.arange(1,2,0.0000001,'d') # 13264200 ns
rf1=array.array('d', Rangef(1,2,0.0000001)) # 793447200 ns

#生成list
np2=list(numpy.arange(1,2,0.0000001,'d')) # 346744000 ns
rf2=list(Rangef(1,2,0.0000001)) # 215716800 ns

生成 一千万个浮点数 的数组 ,使用 arange 要比 Rangef 快 50 倍,

生成一千万个浮点数 的列表 , 使用 arange 转化要比 Rangef 慢接近 2 倍

如果想要判断数值在区间内的位置,或是生成小规模的序列 还是挺方便的,毕竟Rangef 不需要生成真正的序列对象(基本不耗内存)。

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值