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

242 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第25天,点击查看活动详情

续接上文cmath头文件的源码学习02

宏函数定义---分类函数

isnan--判断数据是否是一个number

还是之前的例子,判断是否是一个合法的实数:

  printf ("isnan(0.0)       : %d\n",isnan(0.0));
  printf ("isnan(1.0/0.0)   : %d\n",isnan(1.0/0.0));
  printf ("isnan(-1.0/0.0)  : %d\n",isnan(-1.0/0.0));
  printf ("isnan(sqrt(-1.0)): %d\n",isnan(sqrt(-1.0)));
  //测试结果
isnan(0.0)       : 0
isnan(1.0/0.0)   : 0
isnan(-1.0/0.0)  : 0
isnan(sqrt(-1.0)): 1

我们来看看函数实现:

 28 int __isnanf(float x)                                                               
 29 {                      
 30     int32_t ix;                                         
 31     GET_FLOAT_WORD(ix,x);                                
 32     ix &= 0x7fffffff;                                   
 33     ix = 0x7f800000 - ix;                                 
 34     return (int)(((uint32_t)(ix))>>31);                
 35 }           

有了前面的经验,我们可以很直接得看出,先截取指数域与小数域,ix = 0x7f800000 - ix,得到指数域差值和负的小数域,转换成uint32_t是为了右移运算时左边补0,此时右移31位,实际上是为了检测符号位,也即是前面相减的过程是否溢出得到了负数,即在指数域为11111111时,小数域还有数据,就会导致减出负数,最后判断时符号位为1,判断为NAN,这个也是IEEE754的规定:指数域11111111,小数域有数据表示非法;小数域无数据表示无穷,根据符号位确定是正无穷还是负无穷。

isnormal---判断数据是否是一个非0正常数(非0正常浮点数)

直接来看代码,实际上调用了fpclassify接口,判断返回值是否是FP_NORMAL,实现逻辑也比较简单:

 999 /* Return nonzero value if X is neither zero, subnormal, Inf, nor NaN.  */    
1000 # if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \    
1001      || __glibc_clang_prereq (2,8)   
1002 #  define isnormal(x) __builtin_isnormal (x)
1003 # else                                      
1004 #  define isnormal(x) (fpclassify (x) == FP_NORMAL)
1005 # endif

signbit---返回输入数x的符号是否是负号

看一下之前的例子,一个非0数的符号为负时返回true,其余情况返回false:

  printf ("signbit(0.0)       : %d\n",signbit(0.0));
  printf ("signbit(1.0/0.0)   : %d\n",signbit(1.0/0.0));
  printf ("signbit(-1.0/0.0)  : %d\n",signbit(-1.0/0.0));
  printf ("signbit(sqrt(-1.0)): %d\n",signbit(sqrt(-1.0)));
  //测试结果
  signbit(0.0) : 0 
  signbit(1.0/0.0) : 0 
  signbit(-1.0/0.0) : 1 
  signbit(sqrt(-1.0): 1

看下代码实现: 这里需要我们了解一下GCC内建函数的知识 # GCC种builtin函数的介绍以及实现过程 我们来看看GCC代码中的定义模块:mirrors.tuna.tsinghua.edu.cn/help/gcc.gi…

image.png 再往下就涉及到具体的机器架构对应的内建实现了,我们就不深入说明了。