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.

 

*        Download the 'Sine' source code, including C++ Builder 6.0 project (zip).

 

UnitSineMain.cpp

 

 

//---------------------------------------------------------------------------

/*

Sine, a class that uses a look-up table to calculate a sine

Copyright (C) 2009 Richel Bilderbeek

 

This program is free software: you can redistribute it and/or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation, either version 3 of the License, or

(at your option) any later version.

 

This program is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.

 

You should have received a copy of the GNU General Public License

along with this program. If not, see <http://www.gnu.org/licenses/>.

*/

//---------------------------------------------------------------------------

// From http://www.richelbilderbeek.nl

//---------------------------------------------------------------------------

#pragma hdrstop

//---------------------------------------------------------------------------

#include <cassert>

#include <limits>

#include <iostream>

#include <cmath>

#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

 

 

//---------------------------------------------------------------------------

/*

Sine, a class that uses a look-up table to calculate a sine

Copyright (C) 2009 Richel Bilderbeek

 

This program is free software: you can redistribute it and/or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation, either version 3 of the License, or

(at your option) any later version.

 

This program is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.

 

You should have received a copy of the GNU General Public License

along with this program. If not, see <http://www.gnu.org/licenses/>.

*/

//---------------------------------------------------------------------------

// From http://www.richelbilderbeek.nl

//---------------------------------------------------------------------------

#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

 

 

//---------------------------------------------------------------------------

/*

Sine, a class that uses a look-up table to calculate a sine

Copyright (C) 2009 Richel Bilderbeek

 

This program is free software: you can redistribute it and/or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation, either version 3 of the License, or

(at your option) any later version.

 

This program is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.

 

You should have received a copy of the GNU General Public License

along with this program. If not, see <http://www.gnu.org/licenses/>.

*/

//---------------------------------------------------------------------------

// From http://www.richelbilderbeek.nl

//---------------------------------------------------------------------------

#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)

 

 

Internal links

  • std::sin

  • Sine approximation by using a parabola

     

    External links

  • None

     

    References

    [0]          None

     

     

     

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

    Go back to Richel Bilderbeek's homepage.