Direct3D 11 支持多个浮点表示形式。 所有浮点计算都在 IEEE 754 32 位单精度浮点规则的定义的子集下运行。
32 位浮点规则
有两组规则:符合 IEEE-754 的规则,以及那些偏离标准的规则。
推崇的 IEEE-754 规则
这些规则中的一些是 IEEE-754 提供选择的单个选项。
- 除以 0 产生 +/- INF,除了会导致 NaN 的 0/0 以外。
- (+/-) 0 的 log 产生 -INF。 负值(-0 除外)的 log 产生 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)。
- 比较 NE 时,如果任一或两个操作数为 NaN,则返回 TRUE。
- 任何非 NaN 值与 +/- INF 的比较返回正确的结果。
IEEE-754 规则的偏差或其他要求
IEEE-754 要求浮点运算产生结果,该结果是最接近无限精确结果的可表示值,称为最近舍入。 Direct3D 11 定义了相同的要求:32 位浮点运算生成的结果与在无限精确结果的最后 0.5 个单位 (ULP) 以内。 这意味着,例如,允许硬件将结果截断为 32 位,而不是执行舍入到最接近的偶数,这将导致最多 0.5 ULP 的错误。此规则仅适用于加法、减法和乘法。
不支持浮点异常、状态位或陷阱。
Denorm 在任何浮点数学运算的输入和输出上被刷新为符号保留的零。 对于任何不涉及数据操作的数据输入/输出或数据传输操作,均有例外。
包含浮点值的状态(如 Viewport MinDepth/MaxDepth、BorderColor 值)可以作为非正规化数提供,并且在硬件使用它们之前可能会被刷新,也可能不会被刷新。
最小值或最大值运算会刷新 denorm 以进行比较,但结果可能会或可能不会刷新 denorm。
在运算中输入 NaN 始终在输出上产生 NaN。 但是,NaN 的确切位模式不需要保持不变(除非操作是原始移动指令——不修改数据)。
在最小或最大运算中,如果只有一个操作数是 NaN,则返回另一个操作数作为结果(这与我们之前查看的比较规则相反)。 这是 IEEE 754R 规则。
Direct3D 10 及更高版本中的算术规则不会区分“quiet”和“signaling”NaN 值(QNaN 与 SNaN)。 所有“NaN”值都以相同的方式进行处理。
如果 min() 或 max() 的两个输入均为 NaN,则返回任何 NaN。
IEEE 754R 规则规定,min(-0,+0) == min(+0,-0) == -0, and max(-0,+0) == max(+0,-0) == +0,这体现了符号的保留。 这与带符号零的比较规则(如上所述)形成鲜明对比。 Direct3D 11 在此处建议 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 行为要求。
双精度数据需要支持生成非标准化值(无刷新到零行为)。 同样地,指令不将非标准化数据读取为符号零,它们接受 denorm 值。
16 位浮点规则
Direct3D 11 还支持浮点数的 16 位表示形式。
格式:
- 1 个符号位 (s) 在 MSB 位位置
- 5 位偏置指数 (e)
- 10 位的分数 (f),具有附加的隐藏位
float16 值(v)遵循以下规则:
- 如果 e == 31 和 f != 0,则 v 是 NaN 而不考虑 s
- 如果 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 位浮点数保留 denorm。
11 位和 10 位浮点规则
Direct3D 11 还支持 11 位和 10 位浮点格式。
格式:
- 没有符号位
- 5 位偏置指数 (e)
- 6 位分数 (f) 表示 11 位格式,5 位分数 (f) 表示 10 位格式,在任一情况下都附加隐藏位。
float11/float10 值(v)遵循以下规则:
- 如果 e == 31 和 f != 0,则 v 为 NaN
- 如果 e == 31 和 f == 0,则 v = +infinity
- 如果 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 位浮点数保留 denorm。
- 任何会导致数字小于零的操作都限制为零。
相关主题