【Tanh的标量实现】

cmath


计算机是如何实现tanh计算的


一、tanh的一些基本内容

对于tanh函数有公式为 t a n h ( x ) = ( e x − e − x ) / ( e x + e − x ) tanh(x) = (e^{x} -e^{-x}) / (e^{x}+e^{-x}) tanh(x)=(exex)/(ex+ex)。其定义域为R,原因是分母利用不等式可得>=2,所以无限制条件。

其次需要知道tanh的泰勒展开式,为 t a n h ( x ) = ∑ n = 1 ∞ 2 2 n ( 2 n − 1 ) B 2 n x 2 n − 1 ( 2 n ! ) tanh(x) = \sum_{n=1}^{\infty} \frac {2^{2n} (2n-1)B_{2n}x^{2n-1}}{(2n!)} tanh(x)=n=1(2n!)22n(2n1)B2nx2n1
其中 B 2 n B_{2n} B2n是伯努利数。
其函数图像如下:
在这里插入图片描述一目了然,奇函数有$-tanh(x) = tanh(-x) $。因此我们只需要在正区间内讨论其值即可。

另外需要清楚这个导数公式,也可以证出其单调性,以及曲线趋于平直的点 [ t a n h ( x ) ] ′ = 1 − t a n h 2 ( x ) [{tanh(x)}]' = 1-tanh^{2}(x) [tanh(x)]=1tanh2(x)

二、代码

1.我的实现例子

代码如下(示例):

#include <bits/stdc++.h>

using namespace std;

float myexp(float x){
        return 1+x+x*x/2+x*x*x/6+x*x*x*x/24+x*x*x*x*x*x/120;
}


float mytanh(float x){
        int ix = (*(int*)&x) & 0x7fffffff;  //去掉符号位 
        float t; //中间变量
        float z;  //最终结果
        if(ix >= 0x7f800000){
          if(x >= 0) return 1; //+Inf 
          else return 1/x - 1;    //-Inf or NaN
        }

        if(ix < 0x41B00000){ //|x| < 22
          if(ix < 0x24000000){   //|x| < -55
            return x*(1+x);
          }
          if(ix >= 0x40000000){ //|x| >= 1
            t = myexp(2*ix)-1;
            z = 1 - 2/(t+2);
          }else{
            t = myexp(-2*ix)-1;
            z = -t/(t+2);
          }
        }else{
                return z = 1;   // |x| > 22  return +-1
        }
        return (x >= 0)? z : -z;
}

int main(){
        float i = 5.123456;
        float m = mytanh(i);
        float n = tanh(i);
        float q = m - n;
        cout << "mytanh = " << m << "cmath's tanh " << n << endl;
        cout << q;
        return 0;

}

2.代码中分段函数的实现原理

1、在 0 < = x < = 2 − 55 0 <= x <= 2^{-55} 0<=x<=255时,有 t a n h ( x ) = x ∗ ( 1 + x ) tanh(x) = x*(1+x) tanh(x)=x(1+x)
2、在 2 − 55 < x < = 1 2^{-55} < x <=1 255<x<=1时, 有 t a n h ( x ) = − t t + 2 tanh(x) = \frac{-t}{t+2} tanh(x)=t+2t 其中 t = e − 2 x − 1 t = e^{-2x}-1 t=e2x1
3、在 1 < = x < 22 1 <= x < 22 1<=x<22时,有 t a n h ( x ) = 1 − 2 t + 2 tanh(x) = 1 - \frac{2}{t+2} tanh(x)=1t+22 其中 t = e 2 x − 1 t = e^{2x}-1 t=e2x1
4、在 22 < x < i n f 22 < x < inf 22<x<inf时,有 t a n h ( x ) = 1 tanh(x) = 1 tanh(x)=1

下面对这四段函数进行具体解释:
对于第一段,是因为在x趋于一个很小的数值时近似有Tanh(x) = x,此时(1+x)约等于1,对于公式中逼近0的一段区间分子使用泰勒即为 2 x + 2 x 2 2x+2x^{2} 2x+2x2,分母就是2,所以可以直接得到x(1+x)这个式子。但是为什么是 2 − 55 2^{-55} 255这个值,还有待研究,但是确定的是这里使用一个较小的值即可

对于第二和第三段,对tanh(x)的公式进行通分化简即可得出结果,无误差。

对于第四段,便可以使用我们前边提到过的导数,令导数为0,也即求 t a n h ( x ) = 1 tanh(x) = 1 tanh(x)=1的x的值,在计算器中我们可以得到tanh(17) 约等于 0.9999999999999964。tanh(18)约等于1,因此找到了一个点,但是在glibc中其使用了22作为这个点,大于这个点的x代入tanh(x)中均会得到结果1。


补充

代码中使用了位运算的技巧,需要清楚ieee754浮点数标准后进行阅读。这篇只是对tanh标量的初步认知,后面重点是进行向量化计算。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值