C++ 学习 ------cmath 头文件的源码学习 02
续接上文:https://xie.infoq.cn/article/a8610035745c237f4b2cf4863
宏函数 isfinite 和 isinf 的分析
宏函数定义---分类函数
isfinite---返回输入数 x 是否有限值
我们来看几个例子,其它三个数都是无限或无法解释的实数:
我们来看看它的具体实现
实现方式与 ieee754 对浮点数的解释一致,首先转换获取该浮点数的位解释(第 31 位符号位,30 到 23 位为指数域,22 到 0 位为小数域);
(ix&0x7f800000)是截取其指数域,然后减去 0x7f800000 得到两者的差,然后左移 31 位,相当于此时只保留第 32 位的值。因为指数域值为 0-255,其中 0-254 做减法减去 255 之后都是不够的,会导致最高位变为 1,这时所表示的浮点数也正式有限的,而指数域全为 1 就会导致 255-255,最高位为 0,最后 return 也是 0,此时表示的数也是无穷大的。
isinf---返回输入数 x 是否是无限值
还是上面的例子:
这一次两个除 0 的情况都是无限值,函数逻辑如下:
判断逻辑与 isfinite 类似,t = ix & 0x7fffffff 是获取指数域+小数域;
t ^= 0x7f800000 按位异或,对指数域,只有为 0 的位置异或之后为 1,为 1 的位置异或之后为 0,小数域为 0 的位置异或之后为 0,为 1 的位置异或之后为 1,相当于不改变小数域,指数域按位取反;
t |= -t 按位或上-t,注意到这里使用的是 int32_t,所以转换为负数之后使用补码表示,即负数的补码等于原来正数的反码+1,这样看来-t,就是对原来的 t,符号域为 1(因为 t 的符号域截断为 0),指数域再按位取反,即变为最开始的指数域,小数域按位取反,然后再加 1;
这里我们扩展思考一下:二进制下的数字都可以写成(A)1(B)的形式,其中 A 表示一串 01 字符串,1 表示从右向左的出现的第一个数字 1,B 表示空(奇数)或者是连续的 0(偶数),即:
偶数:(A)1(00…0)
奇数:(A)1 那么,-t 的运算是,所有位置取反+1,即变形如下(Ā表示所有位置取反):
偶数:(Ā)0(11…1) + 1 = (Ā)1(00…0)
奇数:(Ā)0 + 1 = (Ā)1 那么,t|(-t),就是
偶数:(Ā)1(00…0) | (A)1(00…0) = (11…1)1(00…0)
奇数:(Ā)1 | (A)1 = (1…1)1 所以最后 t 要么全为 1,要么一堆 1 跟着一堆 0;这里我们考虑无限函数判断的三种情况:负无限,正无限,0,分别如下:
这样来看,中间位运算的作用就是将无限数的特征(指数域全为 1,小数域全为 0)提取出来,然后利用原数据的符号位和指数域最高位将数据转换为正负 1 标识正无限和负无限,同时也可以将 0 表示为 0,这也是符合该函数的返回值定义的,如果返回来其它值,那说明并不满足上面的特征,那就不是无限数。
版权声明: 本文为 InfoQ 作者【桑榆】的原创文章。
原文链接:【http://xie.infoq.cn/article/85781c0fbe1ca49725e5d81e7】。文章转载请联系作者。
评论