Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) Sine

 

Class to calculate the value of a sine (the standard function std::sin) by using a look-up table. You can view all code below or download the source code.

 

 

//main.cpp

#pragma hdrstop

#include <cassert>
#include <cmath>
#include <iostream>
#include <limits>
#include "UnitSine.h"

//From htpp://www.richelbilderbeek.nl/CppGetRandomUniform.htm
const double GetRandomUniform()
{
  return static_cast<double>(std::rand())/static_cast<double>(RAND_MAX);
}

//Range from [ - 3.0 * M_PI , 3.0 * M_PI ]
const double GetRandomNumber()
{
  return (-3.0 * M_PI) + (GetRandomUniform() * 6.0 * M_PI);
}

int main()
{
  Sine s;
  //Check special values
  s( 0.0 * M_PI);
  s( 0.5 * M_PI);
  s( 1.0 * M_PI);
  s( 1.5 * M_PI);
  s( 2.0 * M_PI);
  s(-0.0 * M_PI);
  s(-0.5 * M_PI);
  s(-1.0 * M_PI);
  s(-1.5 * M_PI);
  s(-2.0 * M_PI);
  for (int i=0; i!=1000000; ++i)
  {
    if (i % 100000 == 0) std::cout << ".";
    const double x = GetRandomNumber();
    const double y = s(x);
    const double yToo = std::sin(x);
    const double error = std::fabs(y - yToo);
    assert( error < s.GetMaxError());
  }
  std::cout << "Sine tested as safe" << std::endl;
}





UnitSine.h

#ifndef UnitSineH
#define UnitSineH

#include <vector>

struct Sine
{
  Sine(const int size = 1000, const double notInitializedValue = 123.0);
  double operator()(const double x);
  const double GetMaxError() const;

private:
  std::vector<double> mLut; //Look-up table
  const double mNotInitializedValue;
  const double Transform(const double f) const;
  const int CalculateIndex(const double f) const;
};

#endif



UnitSine.cpp

#pragma hdrstop

#include <cassert>
#include <cmath>

#include "UnitSine.h"

Sine::Sine(const int size, const double notInitializedValue)
  : mLut(size,notInitializedValue),
    mNotInitializedValue(notInitializedValue)
{
  //Calculate the value of mLut[1]
  //for the GetErrorMax method
  this->operator()( (M_PI * 0.5) / static_cast<double>(mLut.size()));
  assert(mLut[1] != mNotInitializedValue);
}

double Sine::operator()(const double x)
{
  const double di = 2.0 * M_PI;
  //preY e [ -di, di >
  const double preY = std::fmod(x,di);
  //y e [ 0.0 , di >
  const double y = (preY < 0.0 ? preY + di : preY);
  assert( y >= 0.0 );
  assert( y < di );
  //f = fractional part e [ 0.0, 4.0 >
  const double f = 4.0 * (y / di);
  assert( f >= 0.0 );
  assert( f < 4.0 );
  const bool addMinus = ( f < 2.0 ? false : true);
  const int index = CalculateIndex(f);
  assert(index >= 0);

  if (index == static_cast<int>(mLut.size()) )
    return ( addMinus == true ? -1.0 : 1.0);
  assert(index < static_cast<int>(mLut.size()) );
  //Check if already calculated
  if (mLut[index] == mNotInitializedValue)
  {
    mLut[index] = std::sin( std::fmod(y,M_PI) );
    assert(mLut[index] >= 0.0);
    assert(mLut[index] <= 1.0);
  }
  if (addMinus == true)
  {
    return -mLut[index];
  }
  else
  {
    return mLut[index];
  }
}

const double Sine::GetMaxError() const
{
  //The maximal error is twice the distance between
  //mLut[0] and mLut[1], because the sine is steepest there
  //Because mLut[0] == 0.0, it is twice the value of mLut[1]
  assert(mLut[1] != mNotInitializedValue);
  return mLut[1] * 2.0;
}

const int Sine::CalculateIndex(const double f) const
{
  const int size = mLut.size();
  assert( f >= 0.0 );
  assert( f < 4.0 );
  const double fTransformed = Transform(f);
  assert(fTransformed >= 0.0);
  assert(fTransformed <= 1.0);
  const int index = static_cast<int>(fTransformed * static_cast<double>(size));
  assert(index >= 0);
  assert(index <= size); // index == size is handled by caller (i.e. operator() )
  return index;
}

const double Sine::Transform(const double f) const
{
  assert( f >= 0.0 );
  assert( f < 4.0 );
  if (f < 1.0) return f;
  if (f < 2.0) return 1.0 - (f - 1.0);
  return Transform(f - 2.0);
}

#pragma package(smart_init)


 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict