我怎样才能在verilog中做更准确的计算ln(1+x)

How can I do more accurate calculation ln(1+x) in verliog

我想在 verilog A 中计算 ln(1+x)。 我知道密码是

y = ln(1+x);

但是如果x值变得非常小(ex x=3.52e-18),y值变为零。 在 MATLAB 中,我可以这样计算

y=log1p(x);

我想像那个代码那样计算。 怎样计算更准确?

添加不属于 IEEE 标准的数学函数的唯一方法是使用 C 接口。

在 SystemVerilog 中,您可以添加此行而不必编写任何 C 代码

import "DPI-C" function real log1p(real arg);

但是在 Verilog 中,您必须从必须用 C 语言编写的代码中调用调用 log1p 的 VPI 包装函数。

当然,您始终可以编写 log1p 的多项式或有理数或 table-driven 近似值,或者找到其他人已经实现它的库。

但是如果您已经有一个计算 log() 的函数,那么在紧要关头有一个计算 log(1 + ) 的小技巧!

  1. 如果 1 + x = 1——也就是说,如果 fl(1 + ) = 1——那么只是 return .
  2. 否则,计算 x*log(1 + x)/((1 + x) − 1)(分母中的括号完全相同)。

为什么这样做?

  • 对于||的简单情况> 1/2,这是有效的,因为 fl(1 + ) 在最坏的情况下只会损失一位精度,因此商 /(fl(1 + ) − 1) 基本上抵消(或完全抵消,如果 ≤ −1/2或 ≥ 1) 基本上只留下 log(fl(1 + )) ≈ log(1 + ).

  • 对于 ulp(1)/2 < || 的有趣案例≤ 1/2,这是可行的,因为我们对 ⋅() 的近似因子,其中 () := log(1 + )/ 在零附近条件非常好,因此即使我们实际评估 ( fl(1 + ) - 1)。 因此,虽然 log(1 + x) 单独放大了 1 + x 中的舍入误差, x*log(1 + x)/((1 + x) - 1) 在几个 ulps 范围内给出了 log(1 + ) 的一个很好的近似值(前提是你的 log 函数有小误差)。

    详情:

    1. fl(1 + ) − 1的绝对误差至多为ulp(1)/2。
    2. () ≥ 1/2 所有 || ≤ 1/2.
    3. |′()|所有 || ≤ 2 ≤ 1/2.

    因此根据中值定理,在 和 fl(1 + ) − 1 之间存在一些使得

    |() − (fl(1 + ) − 1)| = |′()⋅( − [fl(1 + ) − 1])| ≤ 2⋅|1 + − fl(1 + )| ≤ 2⋅ulp(1)/2 = ulp(1),

    因此(fl(1 + ) − 1)与()的相对误差为|() − (fl(1 + ) − 1)|/|()| ≤ 2⋅ulp(1)。 而 (fl(1 + ) − 1) 是 log(1 + x)/((1 + x) - 1) 的近似值。

    (对于正输入,|′()| ≤ 1/2 因此界限提高到 ulp(1)/2。)

  • 1 + x = 1 的边缘情况当且仅当 || 发生≤ ulp(1)/2。 当这个成立时,由于 log(1 + ) = + O(²) 级数截断的误差(具体来说,最多 ||/2 ≤ ulp(1)/4,如果您查看级数的确切项)是不比舍入误差差。 这种情况必须特殊处理,以避免被 (1 + x) - 1.

    给出的零除

(此技术作为定理 4 出现在戈德堡关于 What Every Computer Scientist Should Know about Floating-Point Arithmetic 的臭名昭著的笔记中。)