函数族定义---双曲函数

  • cosh---计算双曲余弦函数
  • sinh---计算双曲正弦函数
  • tanh---计算双曲正切函数
  • acosh---计算双曲余弦面积
  • asinh---计算双曲正弦面积
  • atanh---计算双曲正切面积 同样的,我们来分析看下sinh的计算过程 glibc/sysdeps/ieee754/dbl-64/e_sinh.c
44 double45 __ieee754_sinh (double x)
46 {
47 double t, w, h;
48 int32_t ix, jx;
49 uint32_t lx;
50
51 /* High word of |x|. */52 GET_HIGH_WORD (jx, x);
53 ix = jx & 0x7fffffff;
54
55 /* x is INF or NaN */56 if (__glibc_unlikely (ix >= 0x7ff00000))
57 return x + x;
58
59 h = 0.5;
60 if (jx < 0)
61 h = -h;
62 /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */63 if (ix < 0x40360000) /* |x|<22 */64 {
65 if (__glibc_unlikely (ix < 0x3e300000)) { /* |x|<2**-28 */66 math_check_force_underflow (x);
67 if (shuge + x > one)
68 return x;
69 /* sinh(tiny) = tiny with inexact */70 }
71 t = __expm1 (fabs (x));
72 if (ix < 0x3ff00000)
73 return h * (2.0 * t - t * t / (t + one));
74 return h * (t + t / (t + one));
75 }
76
77 /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */78 if (ix < 0x40862e42)
79 return h * __ieee754_exp (fabs (x));
80
81 /* |x| in [log(maxdouble), overflowthresold] */82 GET_LOW_WORD (lx, x);
83 if (ix < 0x408633ce || ((ix == 0x408633ce) && (lx <= (uint32_t) 0x8fb9f87d)))
84 {
85 w = __ieee754_exp (0.5 * fabs (x));
86 t = h * w;
87 return t * w;
88 }
89
90 /* |x| > overflowthresold, sinh(x) overflow */91 return math_narrow_eval(x * shuge);
92 }

通过对源码的阅读,我们也能比较清晰的了解它的计算原理:

  1. 获取输入double的高位字jx,并且截断符号位得到ix;
  2. 判断无穷大(INF)和Nan的情况,直接返回x+x;
  3. 对ix进行划分:
  • ix < 0x40360000:|x| in [0,22],使用sign(x)0.5(E+E/(E+1)))进行计算,同时注意一些边界条件;
  • ix < 0x40862e42:|x| in [22, log(maxdouble)],使用0.5*exp(|x|)进行计算;
  • ix < 0x408633ce || ((ix == 0x408633ce) && (lx <= (uint32_t) 0x8fb9f87d)):|x| in [log(maxdouble), overflowthresold],使用hwwexp(0.5|x|)进行计算;
  • 其它情况,出现越界了,|x| > overflowthresold, sinh(x) overflow。

函数族定义---指数和对数函数

exp---返回自然对数e的x次方

double exp (double x);

frexp---获取有效数字和指数

double frexp (double x     , int* exp);

其中x为输入数,exp为存储指数的地址,计算如下的公式

$$$$x = significand*2^{exponent} $$$$其中,significand在[0.5,1) 之间

如:

param = 8.0;
result = frexp (param , &n);
printf ("%f = %f * 2^%d\n", param, result, n);
//输出结果:
//8.000000 = 0.500000 * 2^4
复制代码

ldexp---生成数字和指数有效数字

double ldexp (double x     , int exp);

返回 $$$$x * 2^{exp} $$$$如:

param = 0.95;
n = 4;
result = ldexp (param , n);
printf ("%f * 2^%d = %f\n", param, n, result);
输出结果:
0.950000 * 2^4 = 15.200000

log---返回自然对数

double log (double x);

log10---返回以10为底的对数

double log10 (double x);

如:

param = 1000.0;
result = log10 (param);
printf ("log10(%f) = %f\n", param, result );
//返回结果
log10(1000.000000) = 3.000000

modf---将数字拆分为整数和分数两个部分

double modf (double x     , double* intpart);

x为输入数字,intpart保存整数部分,小数部分返回,同时,整数部分和小数部分的符号相同

exp2---计算$$$$2^x $$$$

double exp2 (double x);

expm1---计算$$$$e^x-1 $$$$

double expm1 (double x);

ilogb---返回以2为底对数的整数部分

int ilogb (double x);

先对x做以2为底的对数,然后取出其中的整数部分返回 如:

param = 10.0;result = ilogb (param);
printf ("ilogb(%f) = %d\n", param, result);
//输出结果
ilogb(10.000000) = 3

因为8<10<16,所以log2(8)<log2(10)<log2(16)log_2(8)<log_2(10)<log_2(16)log2(8)<log2(10)<log2(16)即,3<log2(10)<43<log_2(10)<43<log2(10)<4,取其中的整数部分就是3。

log1p---返回ln(1+x)

double log1p (double x);

log2---返回$$$$log_2{x} $$$$

double log2 (double x);

如:

param = 1024.0;
result = log2 (param);
printf ("log2 (%f) = %f.\n", param, result );
//输出结果
log2 (1024.000000) = 10.000000

logb---返回以FLT_RADIX为底的对数,在大多数平台上,这个值为2

double logb (double x);

基本同log2

scalbn---计算$$$$x * {FLT\_RADIX}^n $$$$

double scalbn (double x     , int n);
复制代码

如:

param = 1.50;
n = 4;
result = scalbn (param , n);
printf ("%f * %d^%d = %f\n", param, FLT_RADIX, n, result);
//输出结果:
1.500000 * 2^4 = 24.000000

scalbln---同scalbn,第二个入参可以是long

double scalbln (double x     , long int n);

后续函数分析见下一节