Direct3D 支持多个浮点表示形式。 所有浮点计算都在 IEEE 754 32 位单精度浮点规则的定义的子集下运行。
32 位浮点规则
有两组规则:符合 IEEE-754 的规则,以及那些偏离标准的规则。
遵循 IEEE-754 规则
这些规则中的一些是 IEEE-754 提供选择的单个选项。
除以 0 产生 +/- INF,除了会导致 NaN 的 0/0 以外。
log of (+/-) 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)。
比较 NE 时,如果任一或两个操作数为 NaN,则返回 TRUE。
任何非 NaN 值与 +/- INF 的比较返回正确的结果。
IEEE-754 规则的偏差和额外要求
IEEE-754 要求浮点运算产生结果,该结果是最接近无限精确结果的可表示值,称为最近舍入。
Direct3D 11 及更高版本定义了与 IEEE-754 相同的要求:32 位浮点操作的结果与无限精确结果之间的差异不超过 0.5 个 ULP(单位在最后的位数)。 这意味着,例如,允许硬件将结果截断为 32 位,而不是执行向最接近偶数舍入,因为这样会导致最多 0.5 ULP 的误差。 此规则仅适用于加法、减法和乘法。
与 IEEE-754 相比,Direct3D 的早期版本定义了一种更宽松的要求:32 位浮点运算的结果与精确值相差不超过 1 个 ULP(单位最后一位)。 这意味着,例如,允许硬件将结果截断为 32 位,而不是执行舍入到最接近的偶数,因为这样最多会导致一个 ULP 出错。
不支持浮点异常、状态位或陷阱。
Denorm 在任何浮点数学运算的输入和输出上被刷新为符号保留的零。 对于任何不涉及数据操作的数据输入/输出或数据传输操作,均有例外。
包含浮点值(如 Viewport MinDepth/MaxDepth 或 BorderColor 值)的状态可以以非规格化值形式提供,并且在硬件使用它们之前可能会或不会被刷新。
用于比较的最小值或最大值操作会刷新非正常数,但结果可能会刷新非正常数,也可能不会。
在运算中输入 NaN 总是会在输出中得到 NaN。 但是,NaN 的确切位模式不需要保持不变(除非操作是原始移动指令,不会更改数据)。
当最小或最大操作中只有一个操作数为NaN时,返回另一个操作数作为结果(这与我们之前讨论的比较规则不同)。 这是 IEEE 754R 规则。
IEEE-754R 规范关于浮点数的最小值和最大值操作指出,如果 min 或 max 的一个输入是无声的 QNaN 值,则操作的结果是另一个参数。 例如:
min(x,QNaN) == min(QNaN,x) == x (same for max)
在 IEEE-754R 规范的修订中,当最小和最大函数的一个输入是“信号”SNaN 值而非 QNaN 值时,其行为表现出不同之处:
min(x,SNaN) == min(SNaN,x) == QNaN (same for max)
通常,Direct3D 遵循算术标准:IEEE-754 和 IEEE-754R。 但在这种情况下,我们有偏差。
Direct3D 10 及更高版本中的算术规则不会区分安静型 NaN 和信号型 NaN 值(QNaN 与 SNaN)。 所有 NaN 值都以相同的方式进行处理。 对于 min 和 max,任何 NaN 值的 Direct3D 行为类似于在 IEEE-754R 定义中处理 QNaN 的方式。 (出于完整性 - 如果两个输入均为 NaN,则返回任何 NaN 值。
另一个 IEEE 754R 规则是 min(-0, +0) == min(+0, -0) == -0,max(-0, +0) == max(+0, -0) == +0,这与我们之前看到的带符号的零的比较规则不同,前者保留了符号。 Direct3D 建议在此处遵循 IEEE 754R 标准行为,但不强制执行。允许结果为零的比较可以依赖于参数的顺序,并使用忽略符号的比较方式。
x*1.0f 的结果始终是 x(除了 denorm 刷新)。
x/1.0f 的结果始终是 x(除了 denorm 刷新)。
x +/- 0.0f 始终产生 x(非正数刷新除外)。 但 -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 时,驱动程序会将 DoublePrecisionFloatShaderOps 的 D3D11_FEATURE_DATA_DOUBLES 设置为 TRUE。 然后,驱动程序和硬件必须支持所有双精度浮点指令。
双精度指令遵循 IEEE 754R 行为要求。
双精度数据需要支持生成非标准化值(无刷新至零行为)。 同样地,指令不将非标准化数据读取为符号零,它们接受 denorm 值。
16 位浮点规则
Direct3D 还支持浮点数的 16 位表示形式。
格式:
- MSB 位位置中的 1 个符号位 (s)
- 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 位浮点数保留非序数。
11 位和 10 位浮点规则
Direct3D 还支持 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 位浮点数保留非序数。
- 任何导致结果小于零的操作都会被限制为零。
相关主题