如何用查找表替换Sin函数?

时间:2014-06-18 00:55:28

标签: c++ lookup sin

好的,所以Sin函数接受半径,并返回该半径的正弦值。

我听说几乎任何功能都可以用查找表替换。

无论我如何使用sin函数,我如何使用自己的查找表代替sin?

让我们举一个简单的例子found here.

/* sin example */
#include <stdio.h>      /* printf */
#include <math.h>       /* sin */

int main ()
{
  double param, result;
  param = 0.53;
  result = sin (param);
  printf ("The sine of %f is %f.\n", param, result );
  return 0;
}

假设我想用我自己的256个浮点查找表替换sin函数。

#define TableSize 256.f

float SinArray[TableSize];
for(int i = 0; i < TableSize; i++) 
{
    // sin
    SinArray[i] = static_cast<float>(sin( (i/TableSize)*(2.f*m_pi) ));
}

我现在如何使用此表替代使用sin函数。

您可能会问“为什么?为什么不使用sin函数?”好吧,因为我正在使用sin函数来波形输入音频。如果我可以使用查找表,我可以创建锯齿形或三角形

由于sin函数采用半径并返回该半径的正弦值,如何使用查找表复制此操作?我怎么做呢?

4 个答案:

答案 0 :(得分:1)

您需要在表格中的两个值之间进行插值

伪代码:

float sin(float radius) {
  radius = radius modulo 2*m_pi;
  int idx = floor(TableSize * radius/2*m_pi);
  float r = TableSize * radius/2*m_pi - idx;
  return SinArray[idx] * (1-r) + SinArray[idx+1] * r;
}

答案 1 :(得分:0)

定期将半径映射到他们的罪恶值,这是你的表。当你想要使用它时,你想要一个值到表中最近的键的半径,那就是你的罪恶值。

或者绕半径,你想要一个值为最接近的整数并索引到一个数组。

答案 2 :(得分:0)

无法理解为什么要在普通/现代机器上执行此操作 - sin()是硬件说明。

但是,为了好玩,你可以这样做:

const double tau = 2 * M_PI;

class Sin
{
public:
    Sin(int tableSize = 256)
        : tableSize_(tableSize)
    {
        initSinTable();
    }
    double operator()(double radians) const
    {
        double mapped = mapDomain(radians);
        int idx = (int)floor(tableSize_ * mapped / tau);
        double lambda = tableSize_ * mapped / tau - idx;
        double lower = sinArray[idx] ;
        double upper = 0;
        if (idx < tableSize_ - 1)
            upper = sinArray[idx + 1];
        double res = lower * (1 - lambda) + upper *lambda;
        return res;
    }
private:
    static double mapDomain(double d) 
    {

        double mapped = fmod(d, tau);
        if (mapped < 0)
            mapped += tau;
        return mapped;

    }
    int tableSize_;
    std::vector<double> sinArray;
    void initSinTable()
    {

        sinArray.resize(tableSize_);
        for (int i = 0; i < tableSize_; ++i)
        {
            sinArray[i] = sin((i*1.0 / tableSize_)*tau);
        }
    }
};

int main()
{
    Sin mySin(512); 
    std::cout << mySin(tau / 6) << std::endl;
    std::cout << sin(tau / 6) << std::endl;
}

关于tau的使用,请参阅:Wikipedia

答案 3 :(得分:0)

这是另一个实现,通用可重用于任意函数:

#include <iostream>
#include <vector>

#include <cmath>

#define LOG(X) (std::cout << X << '\n')

template <typename Num>
class Lookup
{
  public:
    Lookup(Num (*func)(Num), Num from, Num to, size_t num_samples)
      : from_(from), to_(to), x_(double(num_samples - 1) / (to - from))
    {
        for (size_t i = 0; i < num_samples; ++i)
        {
            Num num = (to - from) * i / (num_samples - 1);
            Num sample = func(num);
            LOG("[" << i << "] f(" << num << ") == " << sample);
            samples_.push_back(sample);
        }
    }

    Num operator()(Num n) const
    {
        size_t index = round((n - from_) * x_);
        LOG("(" << n << ") ~@ [" << (n - from_) << " / " << (to_ - from_)
            << " * " << (samples_.size() - 1) << "] == [" << index << "] == "
            << samples_.at(index) << "]");
        return samples_.at(index);
    }

  private:
    static Num round(Num n) { return std::floor(n + 0.5); }

    std::vector<Num> samples_;
    Num from_, to_, x_;
};

int main()
{
    Lookup<double> lsin(std::sin, 0.0, 1.0, 21);

    for (double d = 0; d <= 1.0; d += 0.1)
        std::cout << d << ' ' << sin(d) << ' ' << lsin(d) << '\n';
}

它适用于floatdouble类型 - 可能不会使用floor以及过早截断为整数的除法之外的任何其他内容有问题。

&#34;神秘地&#34;已预先计算名为x_以加快operator()(Num);它可以被计算为除以的数量,但乘法有时在时钟周期方面更快。

记录只是表明它按预期工作:

[0] f(0) == 0
[1] f(0.05) == 0.0499792
[2] f(0.1) == 0.0998334
[3] f(0.15) == 0.149438
[4] f(0.2) == 0.198669
[5] f(0.25) == 0.247404
[6] f(0.3) == 0.29552
[7] f(0.35) == 0.342898
[8] f(0.4) == 0.389418
[9] f(0.45) == 0.434966
[10] f(0.5) == 0.479426
[11] f(0.55) == 0.522687
[12] f(0.6) == 0.564642
[13] f(0.65) == 0.605186
[14] f(0.7) == 0.644218
[15] f(0.75) == 0.681639
[16] f(0.8) == 0.717356
[17] f(0.85) == 0.75128
[18] f(0.9) == 0.783327
[19] f(0.95) == 0.813416
[20] f(1) == 0.841471
(0) ~@ [0 / 1 * 20] == [0] == 0]
0 0 0
(0.1) ~@ [0.1 / 1 * 20] == [2] == 0.0998334]
0.1 0.0998334 0.0998334
(0.2) ~@ [0.2 / 1 * 20] == [4] == 0.198669]
0.2 0.198669 0.198669
(0.3) ~@ [0.3 / 1 * 20] == [6] == 0.29552]
0.3 0.29552 0.29552
(0.4) ~@ [0.4 / 1 * 20] == [8] == 0.389418]
0.4 0.389418 0.389418
(0.5) ~@ [0.5 / 1 * 20] == [10] == 0.479426]
0.5 0.479426 0.479426
(0.6) ~@ [0.6 / 1 * 20] == [12] == 0.564642]
0.6 0.564642 0.564642
(0.7) ~@ [0.7 / 1 * 20] == [14] == 0.644218]
0.7 0.644218 0.644218
(0.8) ~@ [0.8 / 1 * 20] == [16] == 0.717356]
0.8 0.717356 0.717356
(0.9) ~@ [0.9 / 1 * 20] == [18] == 0.783327]
0.9 0.783327 0.783327
(1) ~@ [1 / 1 * 20] == [20] == 0.841471]
1 0.841471 0.841471