Python 数值编程语言是否区分“a”;“最大有限数”;及;无穷大;?
问题动机: 在我所了解的标准数值语言中(例如,Matlab、Python numpy等),例如,如果取一个适度大的数字的指数,则由于数值溢出,输出为无穷大。如果乘以0,则得到NaN。单独来说,这些步骤是合理的,但它们揭示了数学实现中的逻辑错误。由溢出产生的第一个数是有限的,我们显然希望0与这个大的有限数相乘的结果是0 明确地:Python 数值编程语言是否区分“a”;“最大有限数”;及;无穷大;?,python,matlab,numpy,integer-overflow,Python,Matlab,Numpy,Integer Overflow,问题动机: 在我所了解的标准数值语言中(例如,Matlab、Python numpy等),例如,如果取一个适度大的数字的指数,则由于数值溢出,输出为无穷大。如果乘以0,则得到NaN。单独来说,这些步骤是合理的,但它们揭示了数学实现中的逻辑错误。由溢出产生的第一个数是有限的,我们显然希望0与这个大的有限数相乘的结果是0 明确地: >>> import numpy as np >>> np.exp(709)*0 0.0 >>> np.exp(71
>>> import numpy as np
>>> np.exp(709)*0
0.0
>>> np.exp(710)*0
nan
我想我们可以在这里引入“最大有限值”(LFV)的概念,它将具有以下特性:
- LFV将是数值溢出的默认值,否则 四舍五入到无穷大
- LFV<无穷大
- 任何显式数字
(MATLAB详细信息:realmax - LFV*0=0
更新:在评论中,人们似乎有点反对我提出的问题的实用性。我的问题不是因为出现了许多相关问题,而是因为同一问题在许多不同的环境中经常出现。与进行数据分析的人交谈时,这往往会对运行时间产生影响训练/拟合模型时出错。问题基本上是为什么不使用数字语言处理。从评论中,我基本上得出结论,编写语言的人没有看到以这种方式处理问题的实用性。在我看来,当某些特定问题频繁发生时,对于使用某种语言的人来说,这是非常重要的以一种有原则的方式处理这些异常可能是有意义的,这样每个用户就不必这样做了。所以…我很好奇,四处搜寻了一下 正如我在评论中已经提到的,“最大有限值”IEEE 754中存在的一种类型,如果考虑了溢出标志设置的无穷大值,则对应于所建议的LFV,区别在于该标志仅可在操作之后被读出,而不是作为值本身的一部分被存储。这意味着如果发生溢出,则必须手动检查标志并采取行动。而不仅仅是内置LFV*0=0 关于异常处理及其在编程语言中的支持,有一个非常有趣的话题。引用: IEEE 754设置标志并返回无穷大或安静NaN的模型假设用户经常(或至少适当地)测试状态诊断原始问题需要用户检查所有结果是否存在异常值,而异常值反过来又假设这些结果在所有操作中都会被过滤,因此可以标记错误数据。根据这些假设,一切都应该正常,但不幸的是,它们并不十分现实 论文还抱怨对浮点异常处理的支持较差,特别是在C99和Java中(我相信大多数其他语言也不比这更好)。尽管如此,没有做出重大努力来解决这一问题或创建更好的标准,在我看来,似乎表明IEEE 754及其支持在某种意义上“足够好”(稍后将详细介绍)
让我为您的示例问题提供一个解决方案来演示一些东西。我使用numpy使其在溢出时引发异常:
import numpy as np
def exp_then_mult_naive(a, b):
err = np.seterr(all='ignore')
x = np.exp(a) * b
np.seterr(**err)
return x
def exp_then_mult_check_zero(a, b):
err = np.seterr(all='ignore', over='raise')
try:
x = np.exp(a)
return x * b
except FloatingPointError:
if b == 0:
return 0
else:
return exp_then_mult_naive(a, b)
finally:
np.seterr(**err)
def exp_then_mult_scaling(a, b):
err = np.seterr(all='ignore', over='raise')
e = np.exp(1)
while abs(b) < 1:
try:
x = np.exp(a) * b
break
except FloatingPointError:
a -= 1
b *= e
else:
x = exp_then_mult_naive(a, b)
np.seterr(**err)
return x
large = np.float_(710)
tiny = np.float_(0.01)
zero = np.float_(0.0)
print('naive: e**710 * 0 = {}'.format(exp_then_mult_naive(large, zero)))
print('check zero: e**710 * 0 = {}'
.format(exp_then_mult_check_zero(large, zero)))
print('check zero: e**710 * 0.01 = {}'
.format(exp_then_mult_check_zero(large, tiny)))
print('scaling: e**710 * 0.01 = {}'.format(exp_then_mult_scaling(large, tiny)))
# output:
# naive: e**710 * 0 = nan
# check zero: e**710 * 0 = 0
# check zero: e**710 * 0.01 = inf
# scaling: e**710 * 0.01 = 2.233994766161711e+306
将numpy导入为np
def exp_then_mult_naive(a,b):
err=np.seterr(all='ignore')
x=np.exp(a)*b
np.seterr(**错误)
返回x
def exp然后检查零(a,b):
err=np.seterr(all='ignore',over='raise')
尝试:
x=np.exp(a)
返回x*b
除了FloatingPointError:
如果b==0:
返回0
其他:
返回exp\u then\u mult\u naive(a,b)
最后:
np.seterr(**错误)
def exp_然后_mult_缩放(a,b):
err=np.seterr(all='ignore',over='raise')
e=np.exp(1)
当abs(b)<1时:
尝试:
x=np.exp(a)*b
打破
除了FloatingPointError:
a-=1
b*=e
其他:
x=exp\u then\u mult\u naive(a,b)
np.seterr(**错误)
返回x
大=np.浮点数(710)
微小=np.浮动(0.01)
零=np.浮点(0.0)
打印('naive:e**710*0={}'。格式(exp\u then\u mult\u naive(大,零)))
打印('检查零:e**710*0={}'
.format(exp\u then\u mult\u check\u zero(大,零)))
打印('检查零:e**710*0.01={}'
.format(exp\u then\u mult\u check\u zero(大,小)))
打印('scaling:e**710*0.01={}'。格式(exp\u-then\u-mult\u scaling(大、小)))
#输出:
#天真的: