cmath
一、FLOOR简介
floor函数,其功能是“向下取整”,或者说“向下舍入”、“向零取舍”,即取不大于x的最大整数,与“四舍五入”不同,下取整是直接取按照数轴上最接近要求值的左边值,即不大于要求值的最大的那个整数值。
二、算法
1.标量源码
#include "math.h"
#include "math_private.h"
static const float huge = 1.0e30;
float
floorf(float x)
{
int32_t i0,j0;
u_int32_t i;
GET_FLOAT_WORD(i0,x);
j0 = ((i0>>23)&0xff)-0x7f;
if(j0<23) {
if(j0<0) { /* raise inexact if x != 0 */
if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
if(i0>=0) {i0=0;}
else if((i0&0x7fffffff)!=0)
{ i0=0xbf800000;}
}
} else {
i = (0x007fffff)>>j0;
if((i0&i)==0) return x; /* x is integral */
if(huge+x>(float)0.0) { /* raise inexact flag */
if(i0<0) i0 += (0x00800000)>>j0;
i0 &= (~i);
}
}
} else {
if(j0==0x80) return x+x; /* inf or NaN */
else return x; /* x is integral */
}
SET_FLOAT_WORD(x,i0);
return x;
}
代码解读(大致实现原理):
首先我们需要对传入的浮点数x做一个取阶码exp运算,这里需要了解IEEE754浮点数标准,即第一位符号位,接8位指数位,接23位尾数位,那么取阶码就是右移23位后,和0xff做一个&运算,再减掉偏置值就可以得到真值j0了。
然后对真值进行范围判断,先看最简单的两种情况,x在(0,1)区间内都返回0;在(-1,0)区间内返回-1。此时j0 是小于0的。
然后在j0在(0,23)内时,做一个对0x007fffff右移j0位的运算,这里之前我不太明白,发现这个数字是符号位和指数位全为0,尾数位全为1。如果x是整数(integer),那么0x007fffff右移j0位后,再与x的浮点数形式做&运算,结果必然是0(这里要知道前面符号位和指数位肯定是0,因为你和0做的&),那也就是说尾数位全0,为什么?因为整数啊,如果移完后尾数不为0那么结果肯定就不为0,那说明小数点后有非零数存在那就不是整数了。
在x<0时,x先加一下对0x00800000右移j0位后的结果,再与~i(就是尾数全0,符号位和指数位全1)做&运算。这个自己可以举个例子就搞明白了,比如-1.5,即为1011 1111 1100 0000 0000……
加完后得到1100 0000 0100 0000 0000…… 再和~i做个&运算,得到1100 0000 0100 0000……就是-2,没问题。
NAN和INF比较容易看出,真值为128那说明指数位全1了,返回x本身就行。