Algorithm 对`rootn(x,n)的优化低精度近似`
Algorithm 对`rootn(x,n)的优化低精度近似`,algorithm,math,floating-point,bit-manipulation,Algorithm,Math,Floating Point,Bit Manipulation,rootn(float\u t x,int\u t n)是一个计算第n个根x1/n的函数,一些编程语言支持它,例如。当使用IEEE-754浮点数时,可以基于对底层位模式的简单操作生成任何n的有效低精度起始近似值,假设只需要处理规范化操作数x root(x,n)的二进制指数将是x的二进制指数的1/n。IEEE-754浮点数的指数字段有偏差。我们可以简单地将有偏差的指数除以n,然后应用一个偏移量来补偿先前忽略的偏差,而不是取消对指数的偏置、对其进行分割并重新对结果进行偏置。此外,我们可以简单地将整个
rootn(float\u t x,int\u t n)
是一个计算第n个根x1/n的函数,一些编程语言支持它,例如。当使用IEEE-754浮点数时,可以基于对底层位模式的简单操作生成任何n
的有效低精度起始近似值,假设只需要处理规范化操作数x
root(x,n)
的二进制指数将是x
的二进制指数的1/n。IEEE-754浮点数的指数字段有偏差。我们可以简单地将有偏差的指数除以n
,然后应用一个偏移量来补偿先前忽略的偏差,而不是取消对指数的偏置、对其进行分割并重新对结果进行偏置。此外,我们可以简单地将整个操作数x
,重新解释为整数,而不是提取然后分割指数字段。所需的偏移量很容易找到,因为对于任何n
,参数1将返回结果1
如果我们有两个助手函数,一个是将IEEE-754binary32
重新解释为int32
,另一个是将int32
操作数重新解释为binary32
,我们得到了rootn(x,n)的以下低精度近似值
以直截了当的方式:
rootn (x, n) ~= __int_as_float((int)(__float_as_int(1.0f)*(1.0-1.0/n)) + __float_as_int(x)/n)
整数除法\uuuu float\u as\u int(x)/n
可以减少为移位或乘法加移位。一些工作实例如下:
rootn (x, 2) ~= __int_as_float (0x1fc00000 + __float_as_int (x) / 2) // sqrt (x)
rootn (x, 3) ~= __int_as_float (0x2a555556 + __float_as_int (x) / 3) // cbrt (x)
rootn (x, -1) ~= __int_as_float (0x7f000000 - __float_as_int (x) / 1) // rcp (x)
rootn (x, -2) ~= __int_as_float (0x5f400000 - __float_as_int (x) / 2) // rsqrt (x)
rootn (x, -3) ~= __int_as_float (0x54aaaaaa - __float_as_int (x) / 3) // rcbrt (x)
对于所有这些近似值,只有当整数m
的x
=2n*m时,结果才会精确。否则,与真实的数学结果相比,近似值将提供高估。我们可以通过稍微减少偏移量,使最大相对误差大约减半,从而实现低估和高估的平衡组合。通过使用区间[1,2n]中的所有浮点数作为测试用例,对最佳偏移量进行二进制搜索,很容易实现这一点。这样,我们发现:
rootn (x, 2) ~= __int_as_float (0x1fbb4f2e + __float_as_int(x)/2) // max rel err = 3.47474e-2
rootn (x, 3) ~= __int_as_float (0x2a51067f + __float_as_int(x)/3) // max rel err = 3.15547e-2
rootn (x,-1) ~= __int_as_float (0x7ef311c2 - __float_as_int(x)/1) // max rel err = 5.05103e-2
rootn (x,-2) ~= __int_as_float (0x5f37642f - __float_as_int(x)/2) // max rel err = 3.42128e-2
rootn (x,-3) ~= __int_as_float (0x54a232a3 - __float_as_int(x)/3) // max rel err = 3.42405e-2
有些人可能会注意到,rootn(x,-2)
的计算基本上是计算的初始部分
基于观察原始偏移量和优化以最小化最大相对误差的最终偏移量之间的差异,我可以制定二次校正的启发式方法,从而得出最终优化偏移量值
然而,我想知道是否有可能通过某种封闭形式的公式来确定最佳偏移量,例如,对于[1,2n]中的所有x
,相对误差的最大绝对值max(|)(约(x,n)-x1/n)/x1/n |)最小化。为了便于说明,我们可以限制为binary32
(IEEE-754单精度)数字
我知道,一般来说,对于极大极小近似没有闭式解,但是我的印象是,对于代数函数的多项式近似,如n次方根,确实存在闭式解。在这种情况下,我们有(分段)线性近似。这里是一些倍频程(MATLAB)假设下面的猜测,计算正n的偏移量的代码。似乎适用于2和3,但我怀疑其中一个假设在n太大时失效。现在没有时间调查
% finds the best offset for positive n
% assuming that the conjectures below are true
function oint = offset(n)
% find the worst upward error with no offset
efrac = (1 / log(2) - 1) * n;
evec = [floor(efrac) ceil(efrac)];
rootnvec = 2 .^ (evec / n);
[abserr i] = max((1 + evec / n) ./ rootnvec);
relerr = abserr - 1;
rootnx = rootnvec(i);
% conjecture: z such that approx(z, n) = 1
% should have the worst downward error
fun = @(o) relerr - o / rootnx + (1 / (1 + o * n) ^ (1 / n) - 1);
oreal = fzero(fun, [0 1]);
oint = round((127 * (1 - 1 / n) - oreal) * 2 ^ 23);
只有正n的部分答案——假设我们不向下调整偏移量,我只想通过猜测最坏的高估值来稍作修改 让我们为[1,2^n]中的
x定义一个理想化的近似值
我们希望最大化rootn-A(x,n)/x^(1/n)
从实验上看,最大值出现在x
是2的幂时。在这种情况下,有效位项为零,floor(lg(x))=lg(x)
,因此我们可以最大化
(1 + lg(x)/n) / x^(1/n).
替换y=lg(x)/n
,我们可以最大化[0,1)
中y的(1+y)/2^y
,这样n*y
是一个整数。去掉完整性条件,这是一个微积分练习,表明这个凹函数的最大值在y=1/log(2)-1
,约为0.4426950408889634
。因此,x
的二次幂的最大值在x=2^层((1/log(2)-1)*n)
或x=2^层((1/log(2)-1)*n)
。我猜想其中一个实际上是全局最大值
在低估端,似乎我们想要x
这样rootn(x,n)的输出
是1
,至少对于小的n
。希望以后会有更多。我不完全清楚你的目标函数是什么。你想最小化平均相对误差?最差的投射相对误差?均方根相对误差?相对误差高于某个阈值的情况数?目标是最小化最大相对误差。我会澄清这个问题。我意识到我回避了这个问题,但你可能最高兴的是在初始近似值之后只做一两个牛顿-拉斐逊步骤。对于这样条件良好的系统,每一个步骤都会使精度提高一倍。我完全了解提炼恒星的常用方法n次方根的ting近似。旁注:我经常使用三次收敛的迭代,而不是只提供二次收敛的Newton Raphson。我也知道,使用上述方法的最佳起始近似所需的偏移量将根据后续迭代的确切性质略有变化。如何现在我一直在想,是否存在一个仅用于最优近似本身的封闭表达式,这似乎是一个足够困难的问题。最优偏移近似值相对最大的输入似乎总是略小于a
(1 + lg(x)/n) / x^(1/n).