我有一个函数,它使用一个array-like
自变量和一个value
自变量作为输入。在对此功能进行单元测试(我使用hypothesis
)期间,如果抛出非常大的value
(np.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
。
如果我不能抛出正确的答案,至少我希望能够抛出一个异常。问题在于,现在我不知道如何识别不良输入。一个更适合其他情况的更可取的答案是可取的,因为我认为这是一个反复出现的问题。
答案 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
设置一个最大值,如果您的值大于该值,则可以:
将值减小到该数字,前提是数组中的所有内容都将小于该数字。
引发错误。
像这样:
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))
这可以确保在减去value
和my_array
中的唯一数字X时,得到唯一的结果。这是一个关于减法的普遍事实,如果失败,那是因为浮点算术不够精确,无法将value - X
当作不同于value
或X
的数字来处理。 / p>