简而言之,我们只有知道浮点数的表示格式,才能确切地知道它是否为零。
实际上,我们将
x
与一个小数进行比较。如果
x
小于这个数,我们就认为
x
在功能上与零相同(但大多数情况下,我们的小数仍然大于零)。这种方法非常简单、高效,并且可以跨平台使用。
实际上,浮点数和双精度数已经被以特殊格式呈现,目前硬件中广泛使用的是
IEEE 754,它将数字分成符号、指数和尾数(有效数字)位。
因此,如果我们想要确切地检查浮点数是否为
零,我们可以检查指数和尾数是否都为零,参见
这里。
在IEEE 754二进制浮点数中,零值由偏置指数和尾数均为零表示。负零的符号位设置为1。
以
float
为例,我们可以编写一个简单的代码来提取指数和尾数位,然后进行检查。
#include <stdio.h>
typedef union {
float f;
struct {
unsigned int mantissa : 23;
unsigned int exponent : 8;
unsigned int sign : 1;
} parts;
} float_cast;
int isZero(float num) {
int flag = 0;
float_cast data;
data.f = num;
if(data.parts.exponent == 0u && data.parts.mantissa == 0u) {
flag = 1;
} else {
flag = 0;
}
return(flag);
}
int main() {
float num1 = 0.f, num2 = -0.f, num3 = 1.2f;
printf("\n is zero of %f -> %d", num1, isZero(num1));
printf("\n is zero of %f -> %d", num2, isZero(num2));
printf("\n is zero of %f -> %d", num3, isZero(num3));
return(0);
}
测试结果:
```
# 是 0 的零点为 0.000000 -> 1
# 是 -0 的零点为 -0.000000 -> 1
# 是 1.200000 的零点为 -> 0
```
更多例子:
让我们用代码检查浮点数何时变为实际的零。
void test() {
int i =0;
float e = 1.f, small = 1.f;
for(i = 0; i < 40; i++) {
e *= 10.f;
small = 1.f/e;
printf("\nis %e zero? : %d", small, isZero(small));
}
return;
}
is 1.0000e-01 zero? : NO
is 1.0000e-02 zero? : NO
is 1.0000e-03 zero? : NO
is 1.0000e-04 zero? : NO
is 1.0000e-05 zero? : NO
is 1.0000e-06 zero? : NO
is 1.0000e-07 zero? : NO
is 1.0000e-08 zero? : NO
is 1.0000e-09 zero? : NO
is 1.0000e-10 zero? : NO
is 1.0000e-11 zero? : NO
is 1.0000e-12 zero? : NO
is 1.0000e-13 zero? : NO
is 1.0000e-14 zero? : NO
is 1.0000e-15 zero? : NO
is 1.0000e-16 zero? : NO
is 1.0000e-17 zero? : NO
is 1.0000e-18 zero? : NO
is 1.0000e-19 zero? : NO
is 1.0000e-20 zero? : NO
is 1.0000e-21 zero? : NO
is 1.0000e-22 zero? : NO
is 1.0000e-23 zero? : NO
is 1.0000e-24 zero? : NO
is 1.0000e-25 zero? : NO
is 1.0000e-26 zero? : NO
is 1.0000e-27 zero? : NO
is 1.0000e-28 zero? : NO
is 1.0000e-29 zero? : NO
is 1.0000e-30 zero? : NO
is 1.0000e-31 zero? : NO
is 1.0000e-32 zero? : NO
is 1.0000e-33 zero? : NO
is 1.0000e-34 zero? : NO
is 1.0000e-35 zero? : NO
is 1.0000e-36 zero? : NO
is 1.0000e-37 zero? : NO
is 1.0000e-38 zero? : NO
is 0.0000e+00 zero? : YES <-- 1e-39
is 0.0000e+00 zero? : YES <-- 1e-40
b - a
不完全等于零,操作c / (b - a)
仍可能溢出并将值发送到+/-INF
。 - Mysticial0
将产生+INF
或-INF
?如果我错了,有人能纠正我吗? - Mysticial0.0 / 0.0
是NaN,并且在启用异常时会触发不同的FP异常。 - cHaosmall_number
而不是b-a
。 - Mark Ransom