一、基本概念
IEEE 754是由IEEE(电气和电子工程师学会)制定的二进制浮点数算术标准,它定义了双精度(double)、单精度(float)和扩展精度(extended)等多种浮点数格式,并规定了数值的编码方式、最小规格值、舍入和异常处理等操作。
在计算机中,浮点数常用于表示非整数的实数(如π和根号2),由于实数集合无限大,因此需要寻求一种规律性的编码方式,IEEE 754浮点数标准就是实现这一目的的标准。
二、浮点数表示
IEEE 754浮点数使用一位符号位、多位指数位和多位尾数位来表示一个实数,它的尾数是一个小数,其值的大小可以在不同的位数上进行改变。例如,单精度浮点数的符号位占1位,指数位占8位,尾数位占23位。
//单精度浮点数的定义
typedef union {
float f;
struct {
unsigned int mantissa : 23;
unsigned int exponent : 8;
unsigned int sign : 1;
} parts;
} float_cast;
在上述代码中,符号位sign占用了最高位(最左边),指数位exponent占用了中间8位,尾数位mantissa占用了最后23位。由于exponent占用8位,其最大值为2^8-1=255,因此指数范围为-126~127(实际指数还需减去127)。
三、舍入规则
在IEEE 754浮点数中,舍入有几种不同的规则,包括向最近的偶数舍入、向0取整、向正无穷方向舍入和向负无穷方向舍入。容易想象,不同的舍入规则对于某些值而言,得到的结果会有所不同。
以单精度浮点数为例,下面的代码演示了四种不同的舍入规则的实现:
//单精度浮点数的舍入方法
float round_to_nearest_even(float x) {
float y = round(x);
if (fabs(x - y) == 0.5) {
y = 2.0 * round(x / 2.0);
}
return y;
}
float round_toward_zero(float x) {
return (x > 0.0) ? floor(x) : ceil(x);
}
float round_up(float x) {
return ceil(x);
}
float round_down(float x) {
return floor(x);
}
四、溢出和下溢
当一个数字超出了浮点数所能表示的范围时,就会发生溢出,它会被舍入为正无穷大或负无穷大。相反,当一个数字太小,无法被正确地表示时,就会发生下溢,它将被舍入为0。
在IEEE 754浮点数中,规定当指数大于最大可表示值时,为正无穷大,当指数小于最小可表示值时,为0,这就是浮点数溢出和下溢的表现。例如,对于单精度浮点数而言,最大值为3.4e38,最小值为1.2e-38。
五、异常处理
在计算机中,存在一些特殊情况,例如除以0、无限大加上无限小等,这些情况称为异常或非数值(NaN)。IEEE 754浮点数标准规定了这些情况应该如何处理。
对于除以0,IEEE 754规定其结果应该是正无穷大或负无穷大,具体是哪一个由符号位sign指定;对于0除以0,应该得到未定义的结果(NaN);对于无限大减无限大,应该得到未定义的结果(NaN);对于不确定式(0/0、无限大/无限大或NaN/任何数值)的计算结果都是NaN。
//单精度浮点数的异常处理
float handle_exception(float x) {
if (x == 1.0 / 0.0) {
return 1.0;
} else if (x == -1.0 / 0.0) {
return -1.0;
} else if (x != x) {
return 0.0;
} else {
return x;
}
}
六、总结
IEEE 754浮点数标准提供了一种标准的方式来表示和处理浮点数,对于计算机科学领域而言非常重要。在编写计算机程序时,需要了解这些标准,才能保证程序的正确性和可靠性。