c# - 快速 Exp 计算 : possible to improve accuracy without losing too much performance?

标签 c# performance floating-accuracy exp

我正在尝试以前在 this 中描述的快速 Exp(x) 函数回答关于提高 C# 计算速度的 SO 问题:

public static double Exp(double x)
{
  var tmp = (long)(1512775 * x + 1072632447);
  return BitConverter.Int64BitsToDouble(tmp << 32);
}

该表达式使用了一些 IEEE 浮点“技巧”,主要用于神经集中。该函数比常规 Math.Exp(x) 函数快大约 5 倍。

不幸的是,相对于常规 Math.Exp(x) 函数,数值精度仅为 -4% -- +2%,理想情况下我希望精度至少在 sub-百分比范围。

我绘制了近似和常规 Exp 函数之间的商,从图中可以看出,相对差异似乎以几乎恒定的频率重复。

Quotient between fast and regular exp function

是否可以利用这种规律性进一步提高“fast exp”函数的准确性,而不会显着降低计算速度,或者提高准确性的计算开销是否会超过原始表达式的计算增益?

(作为旁注,我还尝试了在同一个 SO 问题中提出的 one of the alternative 方法,但这种方法在 C# 中似乎计算效率不高,至少在一般情况下不是这样。)

5 月 14 日更新

应@Adriano 的要求,我现在执行了一个非常简单的基准测试。我已经使用每个替代 exp 函数对 [-100, 100] 范围内的浮点值执行了 1000 万次计算。由于我感兴趣的值范围从 -20 到 0,我还明确列出了 x = -5 处的函数值。以下是结果:

      Math.Exp: 62.525 ms, exp(-5) = 0.00673794699908547
Empty function: 13.769 ms
     ExpNeural: 14.867 ms, exp(-5) = 0.00675211846828461
    ExpSeries8: 15.121 ms, exp(-5) = 0.00641270968867667
   ExpSeries16: 32.046 ms, exp(-5) = 0.00673666189488182
          exp1: 15.062 ms, exp(-5) = -12.3333325982094
          exp2: 15.090 ms, exp(-5) = 13.708332516253
          exp3: 16.251 ms, exp(-5) = -12.3333325982094
          exp4: 17.924 ms, exp(-5) = 728.368055056781
          exp5: 20.972 ms, exp(-5) = -6.13293614238501
          exp6: 24.212 ms, exp(-5) = 3.55518353166184
          exp7: 29.092 ms, exp(-5) = -1.8271053775984
      exp7 +/-: 38.482 ms, exp(-5) = 0.00695945286970704

ExpNeural 等同于本文开头指定的 Exp 函数。 ExpSeries8formulation我最初声称在 .NET 上效率不高;当完全像 Neil 一样实现它时,它实际上非常快。 ExpSeries16 是类似的公式,但有 16 次乘法而不是 8 次。exp1exp7 是与下面 Adriano 的回答不同的函数。 exp7 的最终变体是检查 x 符号的变体;如果为负,则函数返回 1/exp(-x)

不幸的是,Adriano 列出的 expN 函数都没有在我考虑的更广泛的负值范围内就足够了。 Neil Coffey的级数扩展方法似乎更适合“我的”值范围,尽管它与较大的负 x 发散太快,尤其是在“仅”使用 8 次乘法时。

最佳答案

泰勒级数近似值(例如 Adriano's answer 中的 expX() 函数)在接近零时最准确,在 -20 甚至 -5 时可能会有很大的误差。如果输入具有已知范围,例如像原始问题一样的 -20 到 0,您可以使用一个小的查找表和一个额外的乘法来大大提高准确性。

诀窍是认识到 exp() 可以分为整数和小数部分。例如:

exp(-2.345) = exp(-2.0) * exp(-0.345)

小数部分始终介于 -1 和 1 之间,因此泰勒级数近似值将非常准确。整数部分只有 exp(-20) 到 exp(0) 的 21 个可能值,因此这些可以存储在一个小的查找表中。

关于c# - 快速 Exp 计算 : possible to improve accuracy without losing too much performance?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10552280/

相关文章:

PHP:脚本大小限制

Java 与 C float : "x * x" differs from "pow(x,2)"?

math - float 学有问题吗?

c# - System.Web.Caching.Cache Dispose 对象是否从缓存中清除?

c# - 使用 Entity Framework 代码保存分离的对象图首先导致主键冲突

c# - xaml.cs 中连续的 2 个括号是什么意思?

php - 在一张表中插入数据,从另一张表中删除数据,在mysql中使用时间戳条件

sql - 优化对不相关表的大量插入

mysql - 在 Ruby on Rails 中处理定点/精度小数的最佳方法

c# - 如何保护 ASP.NET Web API