来自MATLAB的Python新手。
我正在使用幅度尺度函数的双曲正切截断。
将0.5 * math.tanh(r/rE-r0) + 0.5
函数应用于范围值数组r = np.arange(0.1,100.01,0.01)
时,我遇到了问题。我在接近零的一侧获得了函数的几个0.0
值,这在我执行对数时会导致域问题:
P1 = [ (0.5*m.tanh(x / rE + r0 ) + 0.5) for x in r] # truncation function
我使用这种解决方法:
P1 = [ -m.log10(x) if x!=0.0 else np.inf for x in P1 ]
这对我正在做的事情已足够,但它有点像创可贴解决方案。
根据数学显性的要求:
在天文学中,幅度尺度大致相同:
mu = -2.5log(flux) + mzp # apparent magnitude
其中mzp是每秒看到1个光子的幅度。因此,更大的通量等于更小(或更负)的视在幅度。我正在为使用多个组件功能的源制作模型。防爆。两个具有不同sersic索引的sersic函数,在内部组件上有一个P1
外部截断,在外部组件上有一个1-P1
内部截断。这样,当将截断函数添加到每个分量时,由半径定义的幅度将变得非常大,因为当P1
渐近逼近零时,mu1-2.5 * log(P1
)有多小。
TLDR:我想知道的是,是否存在一种保留浮点的方法,其精度不足以与零区分(特别是在渐近逼近零的函数的结果中)。这很重要,因为在获取这些数字的对数时,就会产生域错误。
非对数P1输出前的最后一个数字开始读取零是5.551115123125783e-17
,这是一个常见的浮点运算舍入误差结果,其中所需的结果应为零。
非常感谢任何输入。
@user:丹 没有把我的整个脚本放在一边:
xc1,yc1 = 103.5150,102.5461;
Ee1 = 23.6781;
re1 = 10.0728*0.187;
n1 = 4.0234;
# radial brightness profile (magnitudes -- really surface brightness but fine in ex.)
mu1 = [ Ee1 + 2.5/m.log(10)*bn(n1)*((x/re1)**(1.0/n1) - 1) for x in r];
# outer truncation
rb1 = 8.0121
drs1 = 11.4792
P1 = [ (0.5*m.tanh( (2.0 - B(rb1,drs1) ) * x / rb1 + B(rb1,drs1) ) + 0.5) for x in r]
P1 = [ -2.5*m.log10(x) if x!=0.0 else np.inf for x in P1 ] # band-aid for problem
mu1t = [x+y for x,y in zip(P1,mu1)] # m1 truncated by P1
其中bn(n1)= 7.72且B(rb1,drs1)= 2.65 - 4.98 *(r_b1 /( - dr1));
mu1是要截断的组件的幅度分布。 P1是截断函数。 P1的许多最终条目都为零,这是由于浮点精度导致浮点与零无法区分。
查看问题的简便方法:
>>> r = np.arange(0,101,1)
>>> P1 = [0.5*m.tanh(-x)+0.5 for x in r]
>>> P1
[0.5, 0.11920292202211757, 0.01798620996209155, 0.002472623156634768, 0.000335350130466483, 4.539786870244589e-05, 6.144174602207286e-06, 8.315280276560699e-07, 1.1253516207787584e-07, 1.5229979499764568e-08, 2.0611536366565986e-09, 2.789468100949932e-10, 3.775135759553905e-11, 5.109079825871277e-12, 6.914468997365475e-13, 9.35918009759007e-14, 1.2656542480726785e-14, 1.7208456881689926e-15, 2.220446049250313e-16, 5.551115123125783e-17, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
还要注意零之前的浮点数。
答案 0 :(得分:5)
回想一下,双曲正切可以表示为(1-e ^ { - 2x})/(1 + e ^ { - 2x})。通过一些代数,我们可以得到0.5 * tanh(x)-0.5(函数的负数)等于e ^ { - 2x} /(1 + e ^ { - 2x})。这个的对数是-2*x-log(1+exp(-2*x))
,它可以在任何地方工作并保持稳定。
也就是说,我建议您替换:
P1 = [ (0.5*m.tanh( (2.0 - B(rb1,drs1) ) * x / rb1 + B(rb1,drs1) ) + 0.5) for x in r]
P1 = [ -2.5*m.log10(x) if x!=0.0 else np.inf for x in P1 ] # band-aid for problem
采用这种更简单,更稳定的方式:
r = np.arange(0.1,100.01,0.01)
#r and xvals are numpy arrays, so numpy functions can be applied in one step
xvals=(2.0 - B(rb1,drs1) ) * r / rb1 + B(rb1,drs1)
P1=2*xvals+np.log1p(np.exp(-2*xvals))
答案 1 :(得分:1)
你可以尝试两件事。
(1)蛮力方法:找到一个变精度浮点算术包并使用它代替内置的固定精度。我在Maxima [1]中玩你的问题,我发现为了避免下溢,我必须相当多地增加浮点精度,但这是可能的。如果你愿意,我可以发布Maxima代码。我想可以为Python提供一些合适的可变精度浮点库。(2)用泰勒级数或其他类型的近似近似log((1/2)(1 + tanh(-x))以完全避免log(tanh(...))。 / p>