如何防止浮动不精确影响numpy.arange?

时间:2018-02-12 21:21:34

标签: python python-2.7 numpy floating-point

由于numpy.arange()使用ceil((stop - start)/step)来确定项目数,因此小浮点数不精确(stop = .400000001)会向列表中添加非预期值。

实施例

第一种情况不包括停止点(预期)

>>> print(np.arange(.1,.3,.1))
[0.1 0.2]

第二种情况包括停止点(非预期)

>>> print(np.arange(.1,.4,.1))
[0.1 0.2 0.3 0.4]

numpy.linspace()解决了这个问题np.linspace(.1,.4-.1,3)。但需要知道步骤的数量。 np.linspace(start,stop-step,np.ceil((stop-step)/step))导致同样的不满。

问题

如何在不知道范围内的元素数量的情况下生成可靠的float范围?

极端情况

考虑我想要生成未知精度的浮点索引的情况

np.arange(2.00(...)001,2.00(...)021,.00(...)001)

4 个答案:

答案 0 :(得分:2)

如果使用精确数学计算了这些值,您的目标是计算ceil((stop - start)/step)

如果{strong}仅浮点值为startstopstep,那么这是不可能的,这些值是某些舍入操作的结果可能发生了错误。舍入会删除信息,而根本无法通过缺少信息来创建信息。

因此,如果您有关于startstopstep的其他信息,则此问题仅可解决。

假设step是准确的,但startstop有一些由e0e1限制的累积错误。也就是说,您知道start最多e0远离其理想数学值(在任一方向上),stop最多e1远离其理想值(在任何一个方向)。那么(stop-start)/step的理想值可以从(stop-start-e0-e1)/step(stop-start+e0+e1)/step远离其理想值。

假设(stop-start-e0-e1)/step(stop-start+e0+e1)/step之间有一个整数。那么就不可能知道理想的ceil结果应该是较小的整数,还是从startstopstep的浮点值得到的更大的结果。边界e0e1

但是,根据您提供的示例,理想(stop-start)/step可能正好是整数,如(.4-.1)/.1中所示。如果是这样,任何非零错误界限都可能导致错误区间跨越一个整数,使得问题无法从我们迄今为止的信息中解决。

因此,为了解决问题,您必须拥有的信息不仅仅是错误的简单边界。例如,您必须知道(stop-start)/step正好是整数或以其他方式量化。例如,如果您知道步数的理想计算将产生.1的倍数,例如3.8,3.9,4.0,4.1或4.2,但从不4.05,并且误差足够小以至于浮动 - 点数计算(stop-start)/step的最终误差小于.05,然后可以将(stop-start)/step舍入到最近的符合条件的倍数,然后将ceil应用于该值。

如果您有此类信息,可以使用startstopstep例如)中的错误更新问题。也许它们中的每一个都是从十进制到浮点的单个转换的结果)和理想(stop-start)/step的可能值。如果您没有此类信息,则无法解决。

答案 1 :(得分:0)

如果您保证(stop-start)step的倍数,那么您可以使用decimal模块来计算步数,即

from decimal import Decimal

def arange(start, stop, step):
    steps = (Decimal(stop) - Decimal(start))/Decimal(step)

    if steps % 1 != 0:
        raise ValueError("step is not a multiple of stop-start")

    return np.linspace(float(start),float(stop),int(steps),endpoint=False)

print(arange('0.1','0.4','0.1'))

答案 2 :(得分:0)

如果您准确表示了您的结束和步骤,如果它们是理性的,您可以使用fractions模块:

>>> from fractions import Fraction
>>>
>>> a = Fraction('1.0000000100000000042')
>>> b = Fraction('1.0000002100000000002')
>>> c = Fraction('0.0000000099999999998') * 5 / 3
>>> 
>>> float(a) + float(c) * np.arange(int((b-a)/c))
array([1.00000001, 1.00000003, 1.00000004, 1.00000006, 1.00000008,
       1.00000009, 1.00000011, 1.00000013, 1.00000014, 1.00000016,
       1.00000018, 1.00000019])
>>>
>>> eps = Fraction(1, 10**100)
>>> b2 = b - eps
>>> float(a) + float(c) * np.arange(int((b2-a)/c))
array([1.00000001, 1.00000003, 1.00000004, 1.00000006, 1.00000008,
       1.00000009, 1.00000011, 1.00000013, 1.00000014, 1.00000016,
       1.00000018])
如果不是,你将不得不接受某种形式的截止:

>>> a = 1.0
>>> b = 1.003999999
>>> c = 0.001
>>> 
# cut off at 4 decimals
>>> round(float((b-a)/c), 4)
4.0
# cut off at 6 decimals
>>> round(float((b-a)/c), 6)
3.999999

答案 3 :(得分:-1)

您可以使用format函数在Python中将数字舍入到任意精度。

例如,如果您希望小数点后的e的前三位数字,则可以运行

float(format(np.e, '.3f'))

使用它来消除浮动不精确,你应该去。