这种分割近似算法如何工作?
我正在使用软件渲染器进行游戏,以获得最准确的PS1外观。 当我正在研究PS1图形/渲染系统的工作原理,摇摆顶点的原因等时,我遇到了一些关于他们分工的文档。 这里是它的链接:http://problemkaputt.de/psx-spx.htm#gteoverview(请参阅“GTE分区不准确性”部分)
相关代码:
if (H < SZ3*2) then ;check if overflow
z = count_leading_zeroes(SZ3) ;z=0..0Fh (for 16bit SZ3)
n = (H SHL z) ;n=0..7FFF8000h
d = (SZ3 SHL z) ;d=8000h..FFFFh
u = unr_table[(d-7FC0h) SHR 7] + 101h ;u=200h..101h
d = ((2000080h - (d * u)) SHR 8) ;d=10000h..0FF01h
d = ((0000080h + (d * u)) SHR 8) ;d=20000h..10000h
n = min(1FFFFh, (((n*d) + 8000h) SHR 16)) ;n=0..1FFFFh
else n = 1FFFFh, FLAG.Bit17=1, FLAG.Bit31=1 ;n=1FFFFh plus overflow flag
我很难理解这是如何工作的,这个'不'表是什么? 我们为什么要改变事情? 如果有人能够更详细地解释这件事实际上是如何实现鸿沟的,那将不胜感激。
该算法是[0,1)中两个无符号16位小数值的定点除法。 它首先通过表格查找计算除数倒数的初始9位近似值,并用单一的Newton-Raphson迭代对倒数xi + 1:= xi *(2-d * xi)进行精化,得到一个倒数精确到大约16位,最后乘以这个除数,在[0,2)中产生一个17位的商。
对于表格查找,除数首先通过应用比例因子2z归一化为[0.5,1],显然这个除数需要用相同的比例因子进行调整。 由于[0.5,1]中操作数的倒数将为[1,2],所以倒数的整数位已知为1,因此可以使用8位表格条目生成1.8个定点通过加上0x100
(= 1)来倒数。 这里使用0x101
的原因尚不清楚; 这可能是由于这个步骤总是高估了真正的互惠。
接下来的两个步骤是牛顿 - 拉夫逊迭代的逐字翻译,其中考虑了定点比例因子的倒数。 所以0x2000000
代表2.0。 该代码使用0x2000080
因为它将以下除以256的舍入常量0x80
(= 128)合并,用于重新缩放结果。 下一步同样会将0x00000080
作为舍入除法的舍入常量,加上256。如果不进行缩放,则这将是纯粹的乘法。
最终乘法n*d
乘以在倒数d
与被除数n
得到的商在33位。 再次,在除以65536之前应用舍入常数0x8000以重新调整到适当的范围,以1.16定点格式给出商。
连续重新缩放是固定点计算的典型代表,其中试图尽可能保持中间结果以最大化最终结果的准确性。 有点不寻常的是,四舍五入适用于所有中间算法,而不仅仅是最后一步。 也许有必要达到指定的准确度。
该函数并不是那么准确,但可能是由初始逼近中的不准确性所引起的。 在所有非例外情况下,2,424,807,756匹配正确舍入的1.16定点结果,780,692,403错误1 ulp,15,606,093有2-ulp错误,86,452有3-ulp错误。 以快速的实验中,在初始近似的最大相对误差u
是3.89e-3。 一种改进的查找表降低最大相对误差在u
至2.85E-3,减少但在最后的结果不消除3- ULP错误。
如果你想看一个具体的例子,考虑h
= 0.3( 0x4ccd
)除以SZ3
= 0.2( 0x3333
)。 那么z
= 2,因此d
= 0.2 * 4 = 0.8( 0xcccc
)。 这导致u
= 1.25( 0x140
)。 由于估计值非常准确,我们期望(2-d * u)接近1,实际上, d
= 1.000015( 0x10001
)。 精炼的倒数出现在d
= 1.250015( 0x14001
),因此商是n
= 1.500031( 0x18002
)。
上一篇: How does this division approximation algorithm work?
下一篇: Tensorflow: How to use a trained model in a application?