Optimization 近似log10[x^k0+;k1]

Optimization 近似log10[x^k0+;k1],optimization,math,sse,simd,approximation,Optimization,Math,Sse,Simd,Approximation,你好。我在试着近似这个函数 Log10[x^k0+k1],其中.21

你好。我在试着近似这个函数

Log10[x^k0+k1],其中.21 k0和k1是常数。出于实际目的,可以假设k0=2.12,k1=2660。所需精度为5*10^-4相对误差

该函数实际上与Log[x]相同,只是接近0,在0附近差异很大

我已经提出了一个SIMD实现,它比一个简单的查找表快约1.15倍,但如果可能的话,我想对它进行改进,我认为这是非常困难的,因为缺乏有效的指令

我的SIMD实现使用16位定点算法计算三次多项式(我使用最小二乘拟合)。对于不同的输入范围,多项式使用不同的系数。共有8个范围,范围i跨越(64)2^i到(64)2^(i+1)。 这背后的原因是Log[x]的导数随x迅速下降,这意味着多项式将更精确地拟合它,因为多项式精确地拟合导数为0的函数超过某个阶数

使用单个_mm_shuffle_epi8(),SIMD表查找非常有效。我使用SSE的浮点到整数转换来获得用于定点近似的指数和有效位。我还通过软件管道化循环,以获得约1.25倍的加速,因此进一步的代码优化可能不太可能

我想问的是,在更高的层次上是否有更有效的近似? 例如:

  • 这个函数可以分解为具有有限域的函数吗 log2((2^x)*有效位)=x+log2(有效位)
  • 因此无需处理不同的范围(表查找)。我认为主要的问题是,添加k1术语会杀死我们所知道和喜爱的所有好的日志属性,使之不可能。还是这样

  • 迭代法?不要这样认为,因为对数[x]的牛顿法已经是一个复杂的表达式

  • 利用相邻像素的局部性?-如果8个输入的范围在相同的近似范围内,那么我可以查找单个系数,而不是查找每个元素的单独系数。因此,我可以将此作为一种快速的通用情况,并在不需要时使用较慢的通用代码路径。但根据我的数据,在这个属性占据70%的时间之前,这个范围必须是~2000,这似乎并不能使这个方法具有竞争力

  • 请给我一些意见,特别是如果你是一个应用数学家,即使你说这不可能做到。谢谢。

    一个观察: 您可以找到一个表达式,表示作为k0和k1的函数,x需要有多大,以便项x^k0足以支配k1,从而达到近似值:

    x^k0+k1~=x^k0,允许您将函数近似计算为

    k0*Log(x)


    这将考虑到高于某个值的所有x。

    您应该能够通过使用改进最小二乘拟合。(这个想法是,你在寻找一个近似值,它在一个范围内的最坏情况偏差是最小的;而最小二乘法寻找的是一个平方差总和最小的近似值。)我想这对你的问题没有太大的影响,但我不确定——希望它能减少你需要划分的范围的数量,有点

    如果已经有了
    log(x)
    的快速实现,可以计算
    p(x)*log(x)
    ,其中p(x)是切比雪夫近似选择的多项式。(而不是尝试将整个函数作为多项式近似值来执行--需要更少的范围缩减。)


    我是这里的一个业余爱好者——我只是随便说说,因为还没有很多答案。

    我最近读到了sRGB模型如何将物理三刺激值压缩为存储的RGB值

    它基本上与我试图近似的函数非常相似,只是它是逐段定义的:

    k0x,x<0.0031308

    k1 x^0.417-k2否则

    我被告知Log[x^k0+k1]中的常数加法是为了使函数的开头更线性。但这很容易通过分段近似实现。这将使近似更加“一致”——只有2个近似范围。由于不再需要计算近似范围索引(整数日志)和执行SIMD系数查找,因此计算成本应该更低


    现在,我认为这将是最好的方法,即使它不能精确地近似函数。最困难的部分是提出这一改变并说服人们使用它。

    那些投票决定结束的人,因此认为数值方法不是编程主题的人,在来世应该遵守克努斯的判断。你得到了什么样的准确度,你需要什么样的准确度?对不起,我忘了说明准确度。我不确定,但我认为一个相对误差,你可以试着用泰勒级数得到一个多项式近似值。然而,导数必须在x=1中计算,因为分数k0使得x=0中的导数未定义。不,这是个坏主意。泰勒级数只使用局部信息,可能是一个非常糟糕的全局拟合。考虑一下用泰勒级数拟合abs(x)。