如何检查函数的输入是否在数据类型限制内?

时间:2018-11-26 14:37:53

标签: python limit

我有一个函数,它使用一个array-like自变量和一个value自变量作为输入。在对此功能进行单元测试(我使用hypothesis)期间,如果抛出非常大的valuenp.float128无法处理的那个),则该功能将失败。

检测这些值并正确处理它们的好方法是什么?

下面是我的函数的代码:

def find_nearest(my_array, value):
    """ Find the nearest value in an unsorted array.
    """
    # Convert to numpy array and drop NaN values.
    my_array = np.array(my_array, copy=False, dtype=np.float128)
    my_array = my_array[~np.isnan(my_array)]

    return my_array[(np.abs(my_array - value)).argmin()]

抛出错误的示例:

find_nearest([0.0, 1.0], 1.8446744073709556e+19)

抛出:0.0,但正确的答案是1.0

如果我不能抛出正确的答案,至少我希望能够抛出一个异常。问题在于,现在我不知道如何识别不良输入。一个更适合其他情况的更可取的答案是可取的,因为我认为这是一个反复出现的问题。

2 个答案:

答案 0 :(得分:1)

请注意,float128实际上不是128位精度!实际上,它是longdouble的实现:https://en.wikipedia.org/wiki/Extended_precision。此类存储的精度为63位-这就是为什么它在1e + 19左右失败的原因,因为这对您来说是63位二进制位。当然,如果数组中的差异大于1,它将能够在该数字上进行区分,这仅意味着您试图区分的任何差异都必须大于您的1/2**63输入value

What is the internal precision of numpy.float128?这是一个古老的答案,阐述了同样的事情。我已经完成测试,并确认np.float128完全是longdouble,具有63位精度。

我建议您为value设置一个最大值,如果您的值大于该值,则可以:

  1. 将值减小到该数字,前提是数组中的所有内容都将小于该数字。

  2. 引发错误。

像这样:

VALUE_MAX = 1e18
def find_nearest(my_array, value):
    if value > VALUE_MAX:
        value = VALUE_MAX
    ...

或者,您可以选择更科学的方法,例如将value与数组的最大值进行实际比较:

def find_nearest(my_array, value):
    my_array = np.array(my_array, dtype=np.float128)
    if value > np.amax(my_array):
        value = np.amax(my_array)
    elif value < np.amin(my_array):
        value = np.amin(my_array)
    ...

这样,您将确定自己永远不会遇到此问题-因为您的值将始终与数组的最大值一样大,或与数组的最小值一样小。

答案 1 :(得分:1)

这里的问题似乎不是float128无法处理1.844...e+19,而是您可能无法添加两个具有如此根本不同的比例的浮点数,并且期望获得准确的结果:

In [1]: 1.8446744073709556e+19 - 1.0 == 1.8446744073709556e+19
Out[1]: True

如果您真的需要这种准确性,那么最好的选择是使用Decimal对象并将它们作为dtype'object'放入numpy数组:

In [1]: from decimal import Decimal

In [2]: big_num = Decimal(1.8446744073709556e+19)

In [3]: big_num  # Note the slight innaccuracies due to floating point conversion
Out[3]: Decimal('18446744073709555712')

In [4]: a = np.array([Decimal(0.0), Decimal(1.0)], dtype='object')

In [5]: a[np.abs(a - big_num).argmin()]
Out[5]: Decimal('1')

请注意,这将比典型的Numpy操作慢很多,因为它必须为每次计算恢复为Python,而不是能够利用自己的优化库(因为numpy没有Decimal类型)。

编辑:

如果您不需要此解决方案,只是想知道您当前的代码是否会失败,我建议采用“尝试一下”的非常科学的方法:

fails = len(set(my_array)) == len(set(my_array - value))

这可以确保在减去valuemy_array中的唯一数字X时,得到唯一的结果。这是一个关于减法的普遍事实,如果失败,那是因为浮点算术不够精确,无法将value - X当作不同于valueX的数字来处理。 / p>