在计算log (a/b)
时一个明显的问题是,a
和b
是给定精度(此处称为本机精度)的两个非零正有限浮点操作数。 a/b
商不能以这种精度表示为浮点数。此外,当源操作数的比率接近于1时,精度将丢失。
可以通过暂时切换到更高精度的计算来解决此问题。但是,例如在本机精度为double
并且long double
仅映射到double
时,可能无法轻易获得这种更高的精度。使用高精度计算还可能对性能产生非常显着的负面影响,例如,在GPU上,float
计算的吞吐量可能是double
计算吞吐量的32倍。 / p>
一个人可能决定使用对数的quotient rule来计算log (a/b)
为log(a) - log(b)
,但是当a
时,这会使计算面临subtractive cancellation的风险。和b
彼此靠近,导致非常大的错误。
如何精确计算给定精度的两个浮点数的商的对数,例如是否具有小于2 ulps的误差且鲁棒性强,即在不求助于高于本机精度计算的情况下,中间计算中没有下溢和溢出?
答案 0 :(得分:5)
到目前为止,我确定的最佳方法将三种情况区分开来,这三种情况是基于较大源操作数除以较小源操作数的商。该比率告诉我们操作数相距多远。如果它太大而超过了本机精度的最大可表示数字,则必须使用商规则,并且结果将计算为log(a) - log(b)
。如果比率接近于1,则计算应利用函数log1p()
来提高准确性,并将结果计算为log1p ((a - b) / b)
。 Sterbenz Lemma表示2.0
是一个很好的切换点,因为如果{≤{1}}的比率等于或小于2,则将精确计算{{1}。 }}。
下面,我将演示此设计的实现方法,该函数接受a-b
个参数。使用log (a/b)
可以更轻松地评估准确性,因为这样可以对可能的测试用例进行更密集的采样。显然,整体准确性将取决于数学库中float
和float
的实现质量。使用具有几乎正确舍入的函数的数学库(logf()
中的最大误差<0.524 ulp,logpf()
中的最大误差<0.506 ulp),在logf()
中观察到的最大误差为<1.5 ulps。使用不同的库,对函数进行如实的全面实现(log1pf()
中的最大错误<0.851 ulp,log_quotient()
中的最大错误<0.874 ulp),logf()
中观察到的最大错误是<1.7 ulps。
log1pf()