问候。我正在尝试近似函数
Log10 [x ^ k0 + k1],其中.21&lt; k0&lt; 21,0 <&lt; k1&lt; 〜2000,x是整数&lt; 2 ^ 14
k0&amp; k1是常数。出于实际目的,您可以假设k0 = 2.12,k1 = 2660.所需精度为5 * 10 ^ -4相对误差。
这个函数实际上与Log [x]相同,除了0附近,它有很大不同。
我已经提出了一个比简单查找表快1.15倍的SIMD实现,但是如果可能的话我想改进它,我认为由于缺乏有效的指令而非常困难。
我的SIMD实现使用16位定点算法来评估三次多项式(我使用最小二乘拟合)。多项式对不同的输入范围使用不同的系数。有8个范围,范围i跨越(64)2 ^ i到(64)2 ^(i + 1)。 这背后的理性是Log [x]的导数随x快速下降,这意味着多项式将更准确地拟合它,因为多项式非常适合于导数超出某个阶数的函数。
使用单个_mm_shuffle_epi8()非常有效地完成SIMD表查找。我使用SSE的float到int转换来获得指数和有效数,用于固定点近似。我还将软件流水线化,以获得~1.25倍的加速,因此可能不太可能进行进一步的代码优化。
我问的是,如果在更高的水平上有更高效的近似值? 例如:
因此消除了处理不同范围(表查找)的需要。我认为的主要问题是添加k1术语会杀死我们所知道和喜爱的所有那些不错的日志属性,这使得它无法实现。或者是吗?
迭代方法?不这么认为,因为log [x]的牛顿方法已经是一个复杂的表达式
利用邻近像素的位置? - 如果8个输入的范围落在相同的近似范围内,那么我可以查找单个系数,而不是查找每个元素的单独系数。因此,我可以将其用作快速常见的情况,并在不使用时使用较慢的通用代码路径。但是对于我的数据,在该属性占70%的时间之前,范围需要大约2000,这似乎不会使这种方法具有竞争力。
请给我一些意见,特别是如果你是一名应用数学家,即使你说它不能完成。感谢。
答案 0 :(得分:2)
一个观察: 你可以找到x需要多大的表达式作为k0和k1的函数,这样术语x ^ k0在k1中足以支配近似值:
x ^ k0 + k1~ = x ^ k0,允许您近似评估函数
K0 *日志(x)的
这会照顾所有x以上的值。
答案 1 :(得分:2)
您应该能够使用Chebyshev approximation改进最小二乘拟合。 (想法是,你正在寻找一个范围内最坏情况偏差最小的近似;最小二乘代替寻找平方差最小的那个。)我猜这不会产生巨大的差异。对于你的问题,但我不确定 - 希望它可以减少你需要拆分的范围数量。
如果已经快速实现log(x)
,则可以计算P(x) * log(x)
,其中P(x)是由切比雪夫近似选择的多项式。 (而不是试图将整个函数作为多项式进行近似 - 需要更少的范围减少。)
我在这里是个业余爱好者 - 只是因为没有很多答案而蘸我的脚趾。
答案 2 :(得分:0)
我最近阅读了sRGB模型如何将物理三刺激值压缩为存储的RGB值。
它基本上与我尝试近似的函数非常相似,除了它是明确定义的:
k0 x,x < 0.0031308
k1 x ^ 0.417 - 否则为k2
我被告知Log [x ^ k0 + k1]中的常量加法是使函数的开头更加线性。但是,通过分段近似可以很容易地实现这一点。这将使近似更加“均匀” - 只有2个近似范围。由于不再需要计算近似范围索引(整数对数)和进行SIMD系数查找,因此计算成本应该更低。
目前,我认为这将是最好的方法,即使它并不精确地逼近函数。困难的部分是提出这种改变并说服人们使用它。