浮點規則
Direct3D 支援多種浮點表示法。 所有浮點運算都會在 IEEE 754 32 位元單精確度浮點規則定義的子集下運作。
32 位元浮點規則
規則共有兩組:一組符合 IEEE-754,另一組則與標準有所偏離。
遵循的 IEEE-754 規則
上述部分規則為 IEEE-754 提供之眾多選項內的單一選項。
除以 0 會產生 +/- INF,但 0/0 的結果為 NaN。
(+/-) 0 的對數會產生 -INF。
負值 (-0 以外) 的對數會產生 NaN。
負數的倒數平方根 (rsq) 或平方根 (sqrt) 會產生 NaN。
-0 則為例外狀況;sqrt(-0) 會產生 -0,而 rsq(-0) 則會產生 -INF。
INF - INF = NaN
(+/-)INF / (+/-)INF = NaN
(+/-)INF * 0 = NaN
NaN (任何 OP) 任何值 = NaN
當任一或兩個運算元為 NaN 時,比較 EQ、GT、GE、LT 和 LE 會傳回 FALSE。
比較會忽略 0 的符號 (因此 +0 等於 -0)。
當任一或兩個運算元為 NaN 時,比較 NE 會傳回 TRUE。
比較任何非 NaN 值與 +/- INF 會傳回正確的結果。
偏離 IEEE-754 規則之處或額外需求
IEEE-754 要求浮點運算產生的結果應為最接近無限精確結果的可表示值,也就是四捨五入至最接近的偶數。
Direct3D 11 和更新版本定義了與 IEEE-754 相同的需求:32 位元浮點運算產生的結果會在無限精確結果的 0.5 最小精度單位 (ULP) 內。 這表示,硬體允許截斷至 32 位元,而非執行四捨五入至最接近的偶數,因為後者會造成最多為 0.5 ULP 錯誤。 這項規則僅適用於加法、減法和乘法。
舊版 Direct3D 定義的需求較 IEEE-754 鬆散:32 位元浮點運算產生的結果會在無限精確結果的一個最小精度單位 (1 ULP) 內。 這表示,硬體允許截斷至 32 位元,而非執行四捨五入至最接近的偶數,因為後者會造成最多為 1 ULP 錯誤。
不提供浮點例外狀況、狀態位元或陷阱等支援。
在任何浮點數學運算的輸入和輸出中,非正規化值會排清為保留正負號的 0。 任何不會操作資料的 I/O 或資料移動作業會發生例外狀況。
包含浮點值的狀態,例如 Viewport MinDepth/MaxDepth 或 BorderColor 等值,可能會做為非正規化值提供,且可能或可能不會在硬體使用它們前排清。
min 或 max 運算會排清 Denorm 以進行比較,但結果可能或可能不會排清 Denorm。
對任何運算進行 NaN 輸入,一律會在輸出產生 NaN。 但 NaN 的實際位元模式則無需保持不變 (除非運算未經處理移動指示,因而不會改變資料)。
只有一個運算元為 NaN 的 min 或 max 運算會傳回其他運算元,以做為結果 (與稍早提到的比較規則相反)。 這是 IEEE 754R 規則之一。
適用於浮點 min 或 max 運算的 IEEE-754R 規格指出:如果 min 或 max 的其中一個輸入為無訊息的 NaN 值,運算元的結果就會是另一個參數。 例如:
min(x,QNaN) == min(QNaN,x) == x (same for max)
IEEE-754R 規格的修訂版則會在其中一個輸入為「訊號」SNaN 值和 QNaN 值時,對 min 和 max 採用不同的行為:
min(x,SNaN) == min(SNaN,x) == QNaN (same for max)
一般而言,Direct3D 會依循算術標準 IEEE-754 和 IEEE-754R。 但在這個情況下,我們會與其有所偏離。
Direct3D 10 和更新版本中的算術規則,並不會在無訊息和訊號 NaN 值(QNaN 和 SNaN) 之間做出任何區分。 所有 NaN 值都會以相同的方式加以處理。 針對 min 和 max,Direct3D 對任何 NaN 值採取的行為,與 IEEE-754R 定義中處理 QNaN 的方式無異 (為了確保完整性,如果兩個輸入皆為 NaN,就會傳回任何 NaN 值)。
另一項 IEEE 754R 規則為 min(-0,+0) == min(+0,-0) == -0, and max(-0,+0) == max(+0,-0) == +0,這項規則會考量正負號,這點也與帶正負號之零的比較規則 (如同先前所述) 相反。 Direct3D 建議使用此處的 IEEE 754R 行為,但不會強制執行該行為;比較零的結果可以使用忽略正負號的比較,以依循參數順序。
x*1.0f 一律會產生 x (除了 Denorm 排清之外)。
x/1.0f 一律會產生 x (除了 Denorm 排清之外)。
x +/- 0.0f 一律會產生 x (除了 Denorm 排清之外)。 但 -0 + 0 = +0。
融合運算 (例如 mad、dp3) 產生的結果,其精確度不亞於非融合運算擴充評估的最糟連續順序。 在容錯方面,最糟順序的定義並非指定融合運算的固定定義;而會視輸入的特定值有所不同。 未融合擴充中的個別步驟都允許個別的 1 ULP 容錯 (或者,針對 Direct3D 使用較 1 ULP 鬆散的容錯叫出的任何指示,會允許更鬆散的容錯)。
融合運算會依循與非融合運算相同的 NaN 規則。
sqrt 和 rcp 有 1 ULP 容錯。 著色器倒數和倒數平方根命令 (rcp 和 rsq) 則有專屬且個別的寬鬆精確度需求。
乘法和除法會各自以 32 位元浮點精確度進行運算 (乘法的精確度為 0.5 ULP,倒數則為 1.0 ULP)。 如果直接實作 x/y,結果就必須大於或等於雙步驟方法的精確度。
64 位元 (雙精確度) 浮點規則
硬體和顯示器驅動程式會選擇性地支援雙精確度浮點。 若要表示支援,當您呼叫使用 D3D11_FEATURE_DOUBLES 呼叫 ID3D11Device::CheckFeatureSupport 時,驅動程式會將 D3D11_FEATURE_DATA_DOUBLES 的 DoublePrecisionFloatShaderOps 設為 TRUE。 隨後,驅動程式和硬體必須支援所有雙精確度浮點指示。
雙精確度指示會遵循 IEEE 754R 行為需求。
雙精確度資料需要適用於非正規化值產生的支援 (無排清至零行為)。 同樣地,指示不會將非正規化資料讀取為帶正負號的零,而是遵循非正規化值。
16 位元浮點規則
Direct3D 也支援浮點數的 16 位元表示法。
格式:
- MSB 位元位置中的 1 正負號位元 (s)
- 5 位元的偏誤指數 (e)
- 10 位元的小數 (f),當中含有額外的隱藏位元
float16 值 (v) 會遵循下列規則:
- 如果 e == 31 和 f != 0,則無論 s 為何,v 都會是 NaN
- 如果 e == 31 和 f == 0,則 v = (-1)s*無限大 (帶正負號的無限大)
- 如果 e 介於 0 到 31 之間,則 v = (-1)s*2(e-15)*(1.f)
- 如果 e == 0 和 f != 0,則 v = (-1)s*2(e-14)*(0.f) (非正規化數)
- 如果 e == 0 和 f == 0,則 v = (-1)s*0 (帶正負號的零)
32 位元浮點術規則也適用於 16 位元浮點數,且會根據稍早提到的位元配置做出調整。 例外狀況則包括:
- 精確度:16 位元浮點數之非融合運算所產生的結果,會是最接近無限精確結果的可表示值 (根據 IEEE-754 規定,16 位元值會套用四捨五入至最接近的偶數)。 32 位元浮點規則會依循 1 ULP 容錯,16 位元浮點則會針對非融合運算使用 0.5 ULP,並針對融合運算使用 0.6 ULP。
- 16 位元浮點數會保留非正規化值。
11 位元和 10 位元浮點規則
Direct3D 也支援 11 位元和 10 位元浮點格式。
格式:
- 無正負號位元
- 5 位元的偏誤指數 (e)
- 11 位元格式包含 6 位元小數 (f),10 位元格式則採用 5 位元小數 (f),而兩種情況都會有額外的隱藏位元。
float11/float10 值 (v) 會遵循下列規則:
- 如果 e == 31 和 f != 0,則 v 為 NaN
- 如果 e == 31 和 f == 0,則 v = +無限大
- 如果 e 介於 0 到 31 之間,則 v = 2(e-15)*(1.f)
- 如果 e == 0 和 f != 0,則 v = *2(e-14)*(0.f) (非正規化數)
- 如果 e == 0 和 f == 0,則 v = 0 (零)
32 位元浮點術規則也適用於 11 和 10 位元浮點數,且會根據稍早提到的位元配置做出調整。 例外狀況包含:
- 精確度:32 位元浮點規則會依循 0.5 ULP。
- 10/11 位元浮點數會保留非正規化值。
- 造成小於零之數字的任何運算,都會限縮為零。
相關主題