最近在写lua的时候,调用C++库,打印了一些异常信息。以前也见过类似的,但是都没管,今天在这里整理,做个记录
32位浮点数在机器中的表示按照IEEE的标准是这样的:
+------+----------------+-------------------------------+
| 1bit | 8bit | 23bit |
+------+----------------+-------------------------------+
其中:1bit表示符号位(0表示正,1表示负),8bit表示指数(0~255,实际指数取值还要减去127,即指数取值区间为-127~128),23bit表示尾数。
这里所要说的浮点异常值就是这种表示产生的几种特殊值,IEEE规定根据指数和尾数的不同分别可表示如下几种特殊值:
1. 零值:按上述的浮点表述形式如果指数部分全部为0,并且尾数全部为0,则表示为浮点0.0,并且规定-0 = +0
2. 非规格化值:如果指数全部为0,尾数非0,则表示非规格化的值,16进制看到的就是[80xxxxxx]h或者[00xxxxxx]h
3. 无穷值:如果指数全部为1,尾数全部为0,则根据符号位分别表示正无穷大和负无穷大,16进制看到的就是[FF800000]h或者[7F800000]h
4. NAN:如果指数全部为1,尾数非0,则表示这个值不是一个真正的值(Not A Number)。NAN又分成两类:QNAN(Quiet NAN)和SNAN(Singaling NAN)。QNAN与SNAN的不同之处在于,QNAN的尾数部分最高位定义为1,SNAN最高位定义为0;QNAN一般表示未定义的算术运算结果,最常见的莫过于除0运算;SNAN一般被用于标记未初始化的值,以此来捕获异常。
会返回 NaN 的运算有如下三种: 1. 操作数中至少有一个是 NaN 的运算 2. 未定义操作 下列除法运算:0/0、∞/∞、∞/−∞、−∞/∞、−∞/−∞ 下列乘法运算:0×∞、0×-∞ 下列加法运算:∞ + (−∞)、(−∞) + ∞ 下列减法运算:∞ - (−∞)、(−∞) - ∞ 3. 产生复数结果的实数运算。例如: 对负数进行开方运算 对负数进行对数运算 对比-1小或比+1大的数进行反正弦或反余弦运算那么既然NAN不是一个真实的数值,在程序如何判断变量是否变成了NAN呢?大部分语言中针对NAN值都有一系列的函数定义,C语言中最常见的三个函数:
5. INF / inf:这个值表示“无穷大 (infinity 的缩写)”,即超出了计算机可以表示的浮点数的最大范围(或者说超过了 double 类型的最大值)。例如,当用 0 除一个整数时便会得到一个1.#INF / inf值;相应的,如果用 0 除一个负整数也会得到 -1.#INF / -inf值。
6. IND / nan:这个的情况更复杂,一般来说,它们来自于任何未定义结果(非法)的浮点数运算。"IND"是 indeterminate 的缩写,而"nan"是 not a number 的缩写。产生这个值的常见例子有:对负数开平方,对负数取对数,0.0/0.0,0.0*∞, ∞/∞ 等。
这里有个lua下的判断NAN的方法,参考http://snippets.luacode.org/snippets/Test_for_NaN_75
function
isnan(x)
return
x ~
=
x
end
Tests/Usage
if
_TEST
then
-- test suite
assert
(isnan(
0
/
0
))
assert
(
not
(isnan(math.huge)
or
isnan(-math.huge)))
assert
(
not
(isnan(
nil
)
or
isnan(
false
)
or
isnan(
0
)))
local
t
=
setmetatable
(
{
}
,
{
__eq
=
function
()
return
false
end
}
)
assert
(
not
isnan(t))
print
'OK'
end