快速的物流功能

时间:2010-09-24 11:51:17

标签: c algorithm math

我正在寻找一种实现快速逻辑功能的方法。后勤功能的经典定义是:

y(x) = 1 / (1 + (1/e^x))其中^是取幂。

或同等地:y(x) = (e^x) / (e^x + 1)

但是,我的特殊逻辑函数有一个基数E而不是e,所以:

y(x) = E^x / (E^x + 1)

在我的情况下,E和x是32位整数,16.16类型的基数2中的固定点。 E尽可能接近真正的常数e。

这种功能的最快算法是什么?我不希望没有查找表。比特操作应该是完美的。

<小时/> 更新:

直觉上,我觉得存在一种非常快速简单的方法,基于欧拉公式:

e^(i*x) = cos(x) + i*sin(x)

其中我是想象单位。

4 个答案:

答案 0 :(得分:8)

记住溢出和下溢。即使结果大约为1,代码exp(x)/(1 + exp(x))也会溢出x的大正值。您可以使用1/(1 + exp(-x))来避免这种情况。对于x的大值,这将下溢为0,但根据您的上下文可能没问题,因为在这种情况下确切的结果几乎为零。

如果正在为x的大的正值或负值调用代码,则可以通过为将要表示为0或1的值返回0或1来节省一点时间,并避免调用exp 。所以你的代码可能就像

if (x > positive cutoff) return 1;
if (x < negative cutoff) return 0;
return 1 / (1 + exp(-x))

这实际上是否更有效取决于您的特定环境以及您获得超过截止值的参数的频率。

答案 1 :(得分:3)

我要谈论花车,而不是整体,因为这就是技术似乎的地方。

这样计算函数的标准方法是使用一些特殊情况逻辑,这样你只需要在某个范围内表示函数[a,b],用一个有理函数逼近它 - 一个多项式除以另一个,然后修补你必须做的任何事情以减少范围。 http://www.netlib.org/fdlibm/e_exp.c处的exp(x)源似乎遵循这种模式。

这给出了a(x)/ b(x)形式的exp(x)的近似值。你真的想要1 /(1 + exp(-x))。你应该能够重新安排一个(x)/ b(x)的实现,以便让它做b(-x)/(a(-x)+ b(-x)),这样你才有一个除法指令,在重新排列的exp(x)中,而不是在其中的一个除法指令和一个在它外面的除法指令。

这将为您节省一些费用,具体取决于您机器上的分配费用是多少 - 如果您的内部循环真的是90%调用后勤功能,则可能会注意到这一点。范围缩小加理性近似的模式是如此根深蒂固,以至于我怀疑你会在不牺牲高精度的情况下做得更好,尽管如果你使用整数,你可能会做好准备。

如果你努力工作,我敢说你可以把它转移到定点世界。我担心我会倾向于回到表格中的值之间的线性插值,也就是说,假设我找不到从内部循环中获取逻辑函数的方法。

答案 2 :(得分:2)

电源不容易转换为位移,因为

E^x = 2^log2(E^x) = 2^(x*log2(E))

这将为您提供一小部分要移位的位数。您可以计算x * log2(E)然后将功率分解为单独的位移的总和,但这不太可能像查找表那样快,然后是牛顿方法的几次迭代。然后,这取决于定点算术运算的成本。

答案 3 :(得分:0)

  

比特操作应该是完美的

看看:http://www.schraudolph.org/pubs/Schraudolph99.pdf