0

I am writing a predictor corrector numerical solver. I have written a working circular array to keep track of the previous values of my function.

#include <cmath>
// Circular array
// this is fixed sized container to hold the last n update of a function
// written by Keivan Moradi 2014
template <typename T>
class carray
{
    public:
        carray(int s)
        {
            size = exp2(ceil(log2(s)));
            array =  new T[size];
            SizeNegOne = size-1;
            head = SizeNegOne;
        }
        void initialize(T n)
        {
            for (head=0; head<size; head++)
                array[head]=n;
            head = SizeNegOne;
        }
        void update(T h)
        {
            // bitwise modulus:
            // if "size" is in power of 2:
            //(head+1) & SizeNegOne = (head+1) % size
            // in contrast to modulus, this method is guaranteed to get positive values
            head = (head+1) & SizeNegOne;
            array[head]=h;
        }
        T operator[](int index)
        {
            // bitwise modulus:
            // if "size" is in power of 2:
            // (head + index) & SizeNegOne = (head + index) % size
            // in contrast to modulus, this method is guaranteed to get positive values
            return array[(head + index) & SizeNegOne];
        }
        ~carray()
        {
            delete [] array;
        }
    protected:
    private:
        T *array;
        int size, SizeNegOne, head;
};

The following code shows how this code is supposed to work:

int main()
{
    carray<float> phi(3);
    phi.initialize(-64);
    std::cout<<phi[0]<<" "<<phi[-1]<<" "<<phi[-2]<<" "<<phi[-3]<<" "<<phi[-4]<<" "<<phi[-5]<<" "<<phi[-6]<<" "<<phi[-7]<<" "<<phi[-8]<<std::endl<<std::endl;

    phi.update(6.1);
    std::cout<<phi[0]<<" "<<phi[-1]<<" "<<phi[-2]<<" "<<phi[-3]<<" "<<phi[-4]<<" "<<phi[-5]<<" "<<phi[-6]<<" "<<phi[-7]<<" "<<phi[-8]<<std::endl<<std::endl;

    phi.update(7.1);
    std::cout<<phi[0]<<" "<<phi[-1]<<" "<<phi[-2]<<" "<<phi[-3]<<" "<<phi[-4]<<" "<<phi[-5]<<" "<<phi[-6]<<" "<<phi[-7]<<" "<<phi[-8]<<std::endl<<std::endl;

    phi.update(8.1);
    std::cout<<phi[0]<<" "<<phi[-1]<<" "<<phi[-2]<<" "<<phi[-3]<<" "<<phi[-4]<<" "<<phi[-5]<<" "<<phi[-6]<<" "<<phi[-7]<<" "<<phi[-8]<<std::endl<<std::endl;

    phi.update(9.1);
    std::cout<<phi[0]<<" "<<phi[-1]<<" "<<phi[-2]<<" "<<phi[-3]<<" "<<phi[-4]<<" "<<phi[-5]<<" "<<phi[-6]<<" "<<phi[-7]<<" "<<phi[-8]<<std::endl<<std::endl;

    phi.update(10.1);
    std::cout<<phi[0]<<" "<<phi[-1]<<" "<<phi[-2]<<" "<<phi[-3]<<" "<<phi[-4]<<" "<<phi[-5]<<" "<<phi[-6]<<" "<<phi[-7]<<" "<<phi[-8]<<std::endl<<std::endl;

    return 0;
}

now I want to nest this class inside a predictor class so that I can use it something like this:

int main()
{
    predictor<float> phi(4);
    phi.update(10);
    phi.update(11);
    phi.update(12);
    phi.update(13);
    std::cout<<phi.predict2ndOrder()<<std::endl;
}

This code shows my failing best attempt:

#include <cmath>
template <typename T>
class predictor
{
    public:
        predictor(int s)
        {
            size = s;
        }
        void update(T a)
        {
            f.update(a);
        }
        T predict2ndOrder()
        {
            return f[0] + (3/2*(f[0]-f[-1])-1/2*(f[-1]-f[-2]));
        }
    private:
        int size;
        carray<T> f(size);
        class carray
        {
            public:
                carray(int s)
                {
                    size = exp2(ceil(log2(s)));
                    array =  new T[size];
                    SizeNegOne = size-1;
                    head = SizeNegOne;
                }
                ~carray()
                {
                    delete [] array;
                }
                void initialize(T n)
                {
                    for (head=0; head<size; head++)
                        array[head]=n;
                    head = SizeNegOne;
                }
                void update(T h)
                {
                    head = (head+1) & SizeNegOne;
                    array[head]=h;
                }
                T operator[](int index)
                {
                    return array[(head + index) & SizeNegOne];
                }
            private:
                T *array;
                int size, SizeNegOne, head;
        };
};

Would you please let me know how to fix this? I am a new c++ programmer so take it easy on me. ;)

user9224
  • 77
  • 8
  • I notice you don't follow the [Rule of Three](http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). – chris May 23 '14 at 11:53
  • Same for the [Rule of Zero](http://isocpp.org/blog/2012/11/rule-of-zero) – wonko realtime May 23 '14 at 12:00
  • So use `std::vector`. – Jarod42 May 23 '14 at 13:00
  • I did understand the Rule of Three and I can fix my code with respect these rules. However, I did not understand your explanation of Rule of Zero. std::vector is not a circular array to my patchy knowledge. – user9224 May 23 '14 at 14:28

1 Answers1

0

There are some typos in the sample code which I won't cover, but transporting the type T from predictor to carray is quite simple. Here's one possibility: Declare carray as a template class as you did in the first code fragment. To make the rest work, correct the typos, move the declarations of size and f below the class definition for carray and init size and f as initialisation list in the correct order in predictors constructor.

Here's the modified code which compiles fine for me in VS2010:

#include <cmath>
using namespace std;

template <typename T>
class predictor
{
public:
   predictor(int s)
      : size(s)
      , f(size)
   {
   }
   void update(int a)
   {
      f.update(a);
   }
   T predict2ndOrder(float deltaT)
   {
      return f[0] + deltaT*(3/4*(f[0]-f[1]-1/2*(f[1]-f[2])));
   }
private:
   template <typename S>
   class carray
   {
   public:
      carray(int s)
      {
         size = exp(ceil(log((S)s)));
         array =  new S[size];
         SizeNegOne = size-1;
         head = SizeNegOne;
      }
      ~carray()
      {
         delete [] array;
      }
      void initialize(S n)
      {
         for (head=0; head<size; head++)
            array[head]=n;
         head = SizeNegOne;
      }
      void update(S h)
      {
         head = (head+1) & SizeNegOne;
         array[head]=h;
      }
      S operator[](int index)
      {
         return array[(head + index) & SizeNegOne];
      }
   private:
      S *array;
      int size, SizeNegOne, head;
   };

   int size;
   carray<T> f;
};
wonko realtime
  • 545
  • 9
  • 26
  • I have tried your suggested code. I have fixed typos, but still I get these error in code::blocks: error: declaration of 'class T' error: shadows template parm 'class T'. In visual Studio 2013, there is no error, but there is no output either. I have a question also, (T)s is some kine of casting? If it is something else, what it is called so that I can learn more about it. Thanks – user9224 May 23 '14 at 14:19
  • @user9224 sorry about the shadowed template param; just change the carray-T-template-param to something different. You're right about the casting; I think it's needed to select the correct log implementation, f.e. between log(float) and log(double). You could as well have written static_cast(s) which is less C and more C++ like. About the output, I admit that I haven't had a look at the semantics at all. I updated the answer to the new template parameter name for carray. – wonko realtime May 23 '14 at 14:41
  • @user9224 I never work with code blocks, but running the code (incl. the suggested change to the template param name) does give me an output on VS2010 and i cannot see anything which might result in an empty output; since phi.predict2ndOrder returns a float, there will always be a value to print to std::cout. Please also note that predictor doesn't call initialise() for its carray member called array in the last main() you showed; maybe you wanted to call that in predictors constructor. – wonko realtime May 23 '14 at 15:02