宏函数定义---分类函数
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,分别如下:
数据 | 负无限 | 正无限 | 0 |
ix | (1)(11111111)(000...0) | (0)(11111111)(000...0) | (0)(00000000)(000...0) |
t = ix & 0x7fffffff,截断指数域和小数域 | (0)(11111111)(000...0) | (0)(11111111)(000...0) | (0)(00000000)(000...0) |
t ^= 0x7f800000,指数域取反,小数域不变 | (0)(00000000)(000...0) | (0)(00000000)(000...0) | (0)(11111111)(000...0) |
t|=-t,即t|(t的反码+1) | (0)(00000000)(000...0)|(全1+1) | (0)(00000000)(000...0)|(全1+1) | (0)(11111111)(000...0)|((1)(0..0)(1)+1) |
结果 | 溢出之后全为0 | 溢出之后全为0 | 全为1,小数域全为0 |
~(t >> 31),t是有符号数,最高位用符号位填充 | 1...11 | 1...11 | 0...00 |
(ix >> 30) | 1...11 | 0...01 | 0...00 |
~(t >> 31) & (ix >> 30) | 1...11 | 0...01 | 0...00 |
这样来看,中间位运算的作用就是将无限数的特征(指数域全为1,小数域全为0)提取出来,然后利用原数据的符号位和指数域最高位将数据转换为正负1标识正无限和负无限,同时也可以将0表示为0,这也是符合该函数的返回值定义的,如果返回来其它值,那说明并不满足上面的特征,那就不是无限数。