今天正在写的机器学习代码里遇到了这样一个函数:
。要怎么计算呢?
咦?直接算不行吗?不行。计算机的精度是有限的。这个函数的定义域是
。当
十分接近 0 时,
就十分接近 1,再用 1 去减它就会损失精度。当
特别大时,
就接近 0,用 1 减它就得到 1,再取对数就完全变成 0 了。
怎么办呢?原来,在许多编程语言中,提供了 log1p 和 expm1 两个函数。它们的功能是计算
和
。若分步计算这两个式子,当
接近 0 时就会损失精度,而 log1p 和 expm1 两个函数则改用泰勒展开法间接计算这两个式子,在
接近 0 时仍能保持足够的精度。
上面两个函数的泰勒展开分别为:
,
。当
很小时,取 2 ~ 3 项就够了。若只取一项也可以看出来,其实
和
在原点附近都是约等于
的。

再回头看文章开头的函数
。当
很小时,我们可以借助 expm1 函数避免精度损失:
。当
很大时,可以借助 log1p 函数避免精度损失:
。由此也可以看出,
这个函数在
时近似为
,在
时近似为
。

那么多大的
算「很大」,多小算「很小」呢?文献 [1] 提出,可以用
作为分界点,
时就使用 expm1 函数,
时就使用 log1p 函数。实验发现,这个分界点是最优的 —— 正好左侧用 expm1 函数计算误差小,右侧用 log1p 函数计算误差小。其实,
的图像是关于直线
对称的,
正是图像与对称轴交点的横坐标。
参考文献:
[1] https://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf
原文作者:;如有侵权,请联系管理员删除。