首页 > 编程语言 >C++学习------cmath头文件的源码学习06

C++学习------cmath头文件的源码学习06

时间:2022-11-28 23:02:34浏览次数:51  
标签:ix 头文件 double param --- 源码 C++ exp result


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

  • 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);

后续函数分析见下一节

标签:ix,头文件,double,param,---,源码,C++,exp,result
From: https://blog.51cto.com/u_15830688/5893764

相关文章

  • C++引用和指针
    1、有时候要想搞清楚一条赋值语句到底是改变了指针的值还是改变了指针所指对象的值不太容易,最好的办法就是记住赋值永远改变的等号左边的对象,例如:*p=0,改变的是p所指对象的......
  • C++ 类this及返回自身对象的引用方式
    这篇文章主要介绍了C++ 类this及返回自身对象的引用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教 +目录this及返回自身对象......
  • C++ 之 宏定义
      宏在C语言中非常重要,但在C++中却无甚大用,普遍的共识:尽量避免使用宏  C++之父Bjarne在《C++ProgrammingLanguage》中写到Avoidmacros   《Eff......
  • go源码学习(一):数据结构-数组
    数组是相同类型元素的集合,在内存中对应一块连续的内存空间。数组类型是通过存储的元素类型以及能够存储的大小两个维度来决定的,一旦声明之后大小就不可更改。初始化go语......
  • SpringBoot 自动装配源码解析
    SpringBoot自动装配源码解析step1:SpringApplication.run(ZylSpringBootApplication.class,args);step2:this.refreshContext(context);-->org.springframework.bo......
  • jsp源码实例2(获取表单参数)
    jsp源码实例2(获取表单参数)packagecoreservlets;importjava.io.*;importjavax.servlet.*;importjavax.servlet.http.*;importjava.util.*;/**Showsallthep......
  • C++11:lambda匿名函数
    lambda源自希腊字母表中第11位的λ,在计算机科学领域,它则被用来表示一种匿名函数。所谓匿名函数,简单地理解就是没有名称的函数,又常被称为lambda函数或者lambda表达......
  • pinia源码解读二(定义模块)
    定义模块store.ts文件的defineStore方法判断是option写法还是setup写法isSetupStore=typeofsetup==='function'内部创建useStore函数,并给函数绑定$id属性为用......
  • Vue 2.x源码学习:render方法、模板解析和依赖收集
    众所周知,Vue的脚手架项目是通过编写.vue文件来对应vue里组件,然后.vue文件是通过vue-loader来解析的,下面是我学习组件渲染过程和模板解析中的一些笔记。之前的笔记:应用初......
  • vue2源码学习2vuex&vue-router
    1.vue插件编写插件可以实现对象vue的拓展,比如新增全局属性/方法,添加实例方法,使用mixin混入其他配置项等等。编写插件必须要实现install方法,当调用Vue.use()使用插件时,......