写点什么

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

作者:桑榆
  • 2022 年 9 月 10 日
    广东
  • 本文字数:1300 字

    阅读完需:约 4 分钟

续接上文:https://xie.infoq.cn/article/85781c0fbe1ca49725e5d81e7

cmath 头文件中宏函数 isnan、isnormal、signbit 实现

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

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)       : 0isnan(1.0/0.0)   : 0isnan(-1.0/0.0)  : 0isnan(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 内建函数的知识https://blog.csdn.net/weixin_46804051/article/details/125134414

我们来看看 GCC 代码中的定义模块:https://mirrors.tuna.tsinghua.edu.cn/help/gcc.git/


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


发布于: 刚刚阅读数: 3
用户头像

桑榆

关注

北海虽赊,扶摇可接;东隅已逝,桑榆非晚! 2020.02.29 加入

Android手机厂商-相机软件系统工程师 爬山/徒步/Coding

评论

发布
暂无评论
C++ 学习 ------cmath 头文件的源码学习 03_c++_桑榆_InfoQ写作社区