1. 浮点数
浮点数在计算机中是由二进制表示,一个浮点数如1.0f在计算机中表示为。浮点数的基本结构为:
阶符 + 阶码 + 尾符 + 尾数
在这里,e表示为阶码,阶码前的
为阶符,由0、1表示,m为尾数,m前的符号位为尾符。
以float类型为例:float类型为4字节,前一个字节中,第一位为阶符,其余7位为阶码。因此阶码范围为-127- 127;后3个字节中,第一个位为隐藏位,第二位为尾符,其余位表示尾数。隐藏位0、1也表示为正负,当隐藏位和尾符不一致时表示需要进行规格化。
浮点数运算的步骤:
- 0操作数检查: 对两操作数进行0操作数检查,一个操作数为0,可减少不必要的运算。
- 对阶:当两操作数的阶码不相等时,需要进行对阶,阶码不一致,表示两操作数的小数点位置不一致。规则:小阶对齐大阶。尾数向右移动一位,阶码+1;这时候,尾数向右移动的过程中会导致尾数的有效精度丢失。
- 尾数求和运算:对尾数进行求和运算。
- 结果规格化:规格化要求:
,m为尾数,即当一个尾数为0.0001时需要左移使得尾数为0.1。当隐藏位与符号位不一致时,也需要进行规格化。规则:尾数左移,阶码 -1。
- 舍入处理:在对阶或向右规格化时,尾数要向右移位,这样,被右移的尾数的低位部分会被丢掉,从而造成一定误差,因此要进行舍入处理。
在IEEE754标准中,舍入处理提供了四种可选方法:
就近舍入其实质就是通常所说的"四舍五入"。例如,尾数超出规定的23位的多余位数字是10010,多余位的值超过规定的最低有效位值的一半,故最低有效位应增1。若多余的5位 是01111,则简单的截尾即可。对多余的5位10000这种特殊情况:若最低有效位现为0,则截 尾;若最低有效位现为1,则向上进一位使其变为 0。
朝0舍入 即朝数轴原点方向舍入,就是简单的截尾。无论尾数是正数还是负数,截尾都使取值的绝对值比原值的绝对值小。这种方法容易导致误差积累。
朝+∞舍入 对正数来说,只要多余位不全为0则向最低有效位进1;对负数来说则是简单的截尾。
朝-∞舍入 处理方法正好与 朝+∞舍入情况相反。对正数来说,只要多余位不全为0则简单截尾;对负数来说,向最低有效位进1。
- 溢出处理:溢出是对于阶码溢出的处理:
浮点数的溢出是以其阶码溢出表现出来的。在加\减运算过程中要检查是否产生了溢出:若阶码正常,加(减)运算正常结束;若阶码溢出,则要进行相应处理。另外对尾数的溢出也需要处理(上溢,尾数右移,阶码+1)。
阶码上溢 超过了阶码可能表示的最大值的正指数值,一般将其认为是+∞和-∞。
阶码下溢 超过了阶码可能表示的最小值的负指数值,一般将其认为是0。
尾数上溢 两个同符号尾数相加产生了最高位向上的进位,将尾数右移,阶码增1来重新对齐。
尾数下溢 在将尾数右移时,尾数的最低有效位从尾数域右端流出,要进行舍入处理。
如上所示,在浮点数的结构和运算过程中可知,有效精度位和运算过程中的规格化和舍入处理可知,浮点数的运算并不一定精确而是存在误差。因此在Java中对于浮点数进行运算需要能够接受其误差,不能接受其误差可使用Decimal类来进行运算。另外,切忌对浮点数结果进行等值判断,因为该结果存在误差。