tags:

views:

295

answers:

3

Hello:

I have designed a quick and basic vector arithmetic library in C++. I call the program from the command line when I need a rapid cross product, or angle between vectors. I don't use Matlab or Octave or related, because the startup time is larger than the computation time. Again, this is for very basic operations.

I am extending this program, and I will make it work as an RPN calculator, for operations of the type:

1 2 3
4 5 6
x
out: -3 6 -3

(give one vector, another vector, and the "cross" operator; spit out the cross product)

The stack must accept 3d vectors or scalars, for operations like:

1 2 3
2
*
out: 2 4 6

The lexer and parser for this mini-calculator are trivial, but I cannot seem to think of a good way for creating the internal stack. How would you create a stack of for containing vectors or doubles (I rolled up my own very simple vector class - less than one hundred lines and it does everything I need).

How can I create a simple stack which accepts elements of class Vector or type double?

Thank you.

+1  A: 

The simplest way would be just to create an Operand struct that contains a double for the scalar and a Vector object for the vector:

struct Operand
{
    double scalar_;
    Vector vector_;
    bool isVector_;
};

(you can set isVector_ to true if it is a vector operand, and false if it is a scalar operand)

For the actual stack, you can just use std::stack<Operand>.

Other options include inheritance (creating scalar and vector types derived from an operand base type) or something like boost::variant, but for something simple like this, a composition struct like the Operand shown above is probably the easiest way to do it.

James McNellis
I think this is simple and effective enough. I'll try to implement it. Thanks!
Arrieta
+3  A: 

Have you looked at boost::any?

gbrandt
boost::any might be to abstract. Especially since you probably need a lot of overloading operators to handle all the calculations any way. But I still vote for boost::any.
jpyllman
I have, but I wanted something way simpler. Also I'm interested in distributing my source code as a single file, and Boost would complicate this. Thanks!
Arrieta
+2  A: 

Well, one solution is to use unions. With unions, you can use same memory area for different structs. For example, you can have one double and one struct in union. They share the same memory and you can only use one of them. You can use some enum to tell which one to use.

Unions are a bit hacky, because they make usage of objects trickier. Compiler does not know how to construct, destruct or copy them, because many objects may share the same memory. Here is a little example how I would do this if I would like to save memory (okay, enum takes four bytes and thus is not memory efficient, but let's forget that ;)

#include <cstdlib>
#include <iostream>

struct Vector
{
    double x, y, z;
};

struct Element
{
    enum Type { SCALAR, VECTOR };
    Type type;
    union {
        double scalar;
        Vector v;
    } data;
};

int main(void)
{
    Element vector_element;
    vector_element.type = Element::VECTOR;
    vector_element.data.v.x = 1;
    vector_element.data.v.y = 2;
    vector_element.data.v.z = 3;

    Element scalar_element;
    scalar_element.type = Element::SCALAR;
    scalar_element.data.scalar = 3.142;

    std::cout << "The size of type Element without enum would be: " << (sizeof(Element) - sizeof(Element::Type)) << " bytes." << std::endl;

    return EXIT_SUCCESS;
}

By the way, for some strange reason, this results to 28 bytes. I expected 3 * 8 = 24 bytes.

Henrik Heino
Very helpful post. Thanks!
Arrieta
It is likely that `double` requires eight-byte alignment. If `sizeof(Type)` is four, then there would be four bytes of padding between the `type` and `data` members of `Element`. Hence the extra four bytes you are seeing.
James McNellis
Oh, thanks for the info, it was really interesting and now that you said it, it sounds very logical :)
Henrik Heino