首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >利用Taylor级数加速计算

利用Taylor级数加速计算
EN

Stack Overflow用户
提问于 2016-11-07 14:29:04
回答 2查看 1.7K关注 0票数 1

在数学中,泰勒级数是求函数逼近的重要方法,具有较小的多项式度。

我想看看这样的近似是如何有用的,例如,为了加速计算。让我们使用著名的Taylor系列:

代码语言:javascript
复制
log(1+x) = x + 0.5 * x^2 + (error term)

从道义上讲,计算2次多项式的值应该比计算log要快得多。

因此,测试这一点的代码:

代码语言:javascript
复制
import numpy, time

def f(t):
    return t + 0.5 * t ** 2
f = numpy.vectorize(f)  

s = time.time()
for i in range(100):
    x = numpy.random.rand(100000) 
    numpy.log(1 + x)
print time.time() - s          # 0.556999921799 seconds

s = time.time()
for i in range(100):
    x = numpy.random.rand(100000)
    f(x)
print time.time() - s          # arghh! 4.81500005722 seconds

为什么多项式方法比实际日志慢10倍?我期望相反。

PS:这个问题可能是在SO和math.SE的中间。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-09 15:19:52

使用Python+Numpy,可能会到处优化它,因此不可能真正对log(1+x)x + 0.5 * x^2进行基准测试。所以我搬到了C++。

结果:

每次有日志操作的时间:19.57ns 每次操作的时间-2阶Taylor展开对数:3.73ns

所以大概是一个x5因子!

代码语言:javascript
复制
#include <iostream>
#include <math.h>
#include <time.h>
#define N (1000*1000*100)
#define NANO (1000*1000*1000)

int main()
{
  float *x = (float*) malloc(N * sizeof(float));
  float y;
  float elapsed1, elapsed2;
  clock_t begin, end;
  int i;

  for (i = 0; i < N; i++) 
    x[i] = (float) (rand() + 1) / (float)(RAND_MAX);

  begin = clock();
  for (i = 0; i < N; i++) 
    y = logf(x[i]);
  end = clock();
  elapsed1 = float(end - begin) / CLOCKS_PER_SEC / N * NANO;

  begin = clock();
  for (i = 0; i < N; i++) 
    y = x[i] + 0.5 * x[i] * x[i];  
  end = clock();
  elapsed2 = float(end - begin) / CLOCKS_PER_SEC / N * NANO;

  std::cout << "Time per operation with log: " << elapsed1 << " ns\n";  
  std::cout << "Time per operation with order-2 Taylor epansion: " << elapsed2 << " ns";

  free(x);

}
票数 1
EN

Stack Overflow用户

发布于 2016-11-07 19:47:58

使用numpy的向量化操作几乎总是比您自己代码中的任何尝试优化都要快。正如@Divakar所提到的,vectorize实际上只是编写for循环的一种方便的方法,所以您的代码将比numpy的本地代码慢。

用标准python代码替换numpy的优化例程表明,您的方法的速度是相同的。

代码语言:javascript
复制
import math, numpy, time


def f(t):
    return t + 0.5 * t ** 2

x = numpy.random.rand(1000000)

s = time.time()
for num in x:
    math.log(1 + num)
print (time.time() - s  )  

s = time.time()
for num in x:
    f(num)
print (time.time() - s)      

结果:

代码语言:javascript
复制
1.1951053142547607
1.3485901355743408

近似速度稍慢,但指数计算非常昂贵。将t ** 2替换为t*t是一个很好的改进,它的近似性能略优于python的log

代码语言:javascript
复制
1.1818947792053223
0.8402454853057861

编辑:或者,由于这里最重要的一课是优化的,科学库几乎在一周中的任何一天都会比手工编码的解决方案更好,下面是使用numpy的矢量化操作的taylor级数近似,这是迄今为止最快的。注意,唯一的大变化是在逼近函数上没有调用vectorize,因此默认情况下使用numpy的向量化操作。

代码语言:javascript
复制
import numpy, time

def f(t):
    return t + 0.5 * t ** 2

x = numpy.random.rand(1000000)
s = time.time()
numpy.log(1 + x)
print (time.time() - s)

s = time.time()
x = numpy.random.rand(100000)
f(x)
print (time.time() - s  )

结果:

代码语言:javascript
复制
0.07202601432800293
0.0019881725311279297

有了它,向量化的近似比numpy的向量化log快一个数量级。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40467615

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档