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

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…​

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

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