许多图形程序实际上只是3D数字代码。在这类程序中,数值问题通常是至关重要的。在 “过去的日子里”,要以一种强大的、可移植的方式来处理这些问题是非常困难的,因为机器对数字有不同的内部表示,更糟糕的是,以不同的、不兼容的方式处理异常。幸运的是,几乎所有的现代计算机都符合IEEE浮点标准(IEEE标准协会1985)。这使得程序员可以对如何处理某些数字条件做出许多方便的假设。虽然IEEE浮点算法有很多特点,在编码数字算法时很有价值,但对于图形学中遇到的大多数情况来说,只有少数几个特点是必须了解的。首先,也是最重要的一点,就是要了解IEEE浮点中的实数有三个 “特殊 “值。
1. 无限大(∞)。这是一个比其他所有有效数字都大的有效数字。
2. 负无穷大(-∞)。这是一个有效数字,比其他所有有效数字都小。
3. 不是一个数字(NaN)。这是一个无效的数字,是由一个具有未定义后果的操作引起的,如零除以零。
IEEE浮点的设计者做出了一些决定对程序员来说是非常方便的。其中很多这些决定与上述三个特殊值有关,用于处理例外情况,比如除以零。在这些情况下,一个异常被记录下来,但在许多情况下,程序员可以忽略这一点。
具体来说,对于任何正实数a,以下涉及无限值除法的规则是成立的。人们所期望的方式。同样对于正数a,其行为是如下。
IEEE浮点有两种零的表示方法,一种被视为正数,另一种被视为负数。0和+0之间的区别只是偶尔会出现,但在出现的时候还是值得记住的。
+a/(+∞) = +0,
−a/(+∞) = −0,
+a/(−∞) = −0,
−a/(−∞) = +0。
其他涉及无限值的操作的行为与人们预期的一样。同样对于正a,其行为如下。
∞ + ∞ = +∞
∞ − ∞ = NaN,
∞ × ∞ = ∞,
∞/∞ = NaN,
∞/a = ∞,
∞/0 = ∞,
0/0 = NaN。
涉及无限值的布尔表达式中的规则与预期一致。
1. 所有有限的有效数字都小于+∞。
2. 所有有限的有效数字都大于-∞。
3. -∞小于+∞。
涉及有NaN值的表达式的规则很简单。
1. 任何包括NaN的算术表达式的结果都是 NaN。
2. 任何涉及NaN的布尔表达式都是假的。
也许IEEE浮点法最有用的地方是如何处理除以零的问题;对于任何正实数a,以下涉及除以零值的规则都成立
+a/ + 0 = +∞,
−a/ + 0 = ∞。
如果程序员利用了IEEE的规则,许多数字计算就会变得简单得多。例如,考虑表达式。
a = 1/(1/b + 1/c)
如果可能出现负零(-0),必须采取一些谨慎措施。
这样的表达方式出现在电阻和透镜上。如果除零会导致程序崩溃(在IEEE浮点运算之前的许多系统中都是如此),那么就需要两个if语句来检查b或c的小值或零值。
相反,在IEEE浮点运算中,如果b或c为零,我们会如愿得到a的零值。另一种避免特殊检查的常用技术是利用NaN的布尔特性。考虑一下下面的代码段。
a = f(x)
if (a > 0) then
do something
在这里,函数f可能会返回 “ugly”的值,如∞或NaN,但if条件仍然是定义明确的:当a=NaN或a=-∞时为假,a=+∞时为真。在决定返回哪些值时要小心,通常if可以做出正确的选择,而不需要特别的检查。这使得程序更小,更健壮,更有效率。