3

I would like to build a space-efficient modular arithmetic class. The idea is that the modulus M is an immutable attribute that gets fixed during instantiation, so if we have a large array (std::vector or another container) of values with the same M, M only needs to be stored once.

If M can be fixed at compile time, this can be done using templates:

template <typename num, num M> class Mod_template
{
    private:
        num V;
    public:
        Mod_template(num v=0)
        {
            if (M == 0)
                V = v;
            else
            {
                V = v % M;
                if (V < 0)
                    V += M;
            }
        }
        // ...
};

Mod_template<int, 5> m1(2); // 2 mod 5

However, in my application, we should be able to express M runtime. What I have looks like this:

template <typename num> class Mod
{
    private:
        const num M;
        num V;
    public:
        Mod(num m, num v=0): M(abs(m))
        {
            if (M == 0)
                V = v;
            else
            {
                V = v % M;
                if (V < 0)
                    V += M;
            }
        }
        // ...
};

Mod<int> m2(5, 2); // 2 mod 5
Mod<int> m3(3);    // 0 mod 3

This works, but a large vector of mod M values uses 2x the space it needs to.

I think the underlying conceptual problem is that Mod's of different moduli are syntactically of the same type even though they "should" be different types. For example, a statement like

m2 = m3;

should raise a runtime error "naturally" (in my version, it does so "manually": check is built into the copy constructor, as well as every binary operator I implement).

So, is there a way to implement some kind of dynamic typing so that the Mod object's type remembers the modulus? I'd really appreciate any idea how to solve this.

This is a recurring problem for me with various mathematical structures (e.g. storing many permutations on the same set, elements of the same group, etc.)

EDIT: as far as I understand,

  • templates are types parametrized by a class or literal.

  • what I want: a type parametrized by a const object (const num in this case, const Group& or const Group *const for groups, etc.).

Is this possible?

  • Read about [type erasure](http://akrzemi1.wordpress.com/2013/11/18/type-erasure-part-i/) – Manu343726 Jun 23 '14 at 16:56
  • @Manu343726 : Thanks, this is really interesting, but I couldn't figure out how to apply it to do what I would like. Would you care to elaborate on this? – EdgarTheWise Jun 23 '14 at 17:28
  • 1
    What if you provide both the class with runtime member and the template, with an implicit conversion from `Mod_template` to `Mod`, and an explicit conversion (which might throw or assert or something) from `Mod` to `Mod_template`? I admit defining the operators would then be even trickier... – aschepler Jun 23 '14 at 19:23
  • @aschepler: Thanks! One challenge here is that I need to know -- in advance -- all `M`s that might be used. But it may be feasible. – EdgarTheWise Jun 25 '14 at 18:20
  • No, you shouldn't need to list a set of possible values of `M`. – aschepler Jun 25 '14 at 22:17

1 Answers1

1

It will be difficult to do it in zero storage space if the class needs to know what M should be without any outside help. Likely the best you can do is store a pointer to a shared M, which may be a little better depending on how large num is. But it's not as good as free.

It will be easier to design if M is a passed-in value to all the functions that need it. Then you can do things like make a pool of objects that all share the same M (there are plenty of easy ways to design this; e.g. map<num, vector<num> >) and only store M once for the pool. The caller will need to know which pool the Mod object came from, but that's probably something it knows anyway.

It's hard to answer this question perfectly in isolation... knowing more about the calling code would definitely help you get better answers.

StilesCrisis
  • 15,972
  • 4
  • 39
  • 62
  • Thanks for this reply! Passing M around is a valid technique, but it would take away from the readability of the code. Context: I would like to do things like add two vectors of the same length. Yes, we could store an array of num's and typecast to Mod, add, typecast back to num. I was hoping there is a better way. – EdgarTheWise Jun 23 '14 at 17:39
  • Why wouldn't you just always keep them as `Mod`s? A `Mod` at this point would just be a wrapped-up `num` with additional methods for doing arithmetic. – StilesCrisis Jun 23 '14 at 18:06
  • When I do arithmetic with huge vectors/matrices, the twofold difference in space can actually count. Also, it aesthetically bothers me that type checks are manual: e.g. when adding m1 + m2, my code has to explicitly check that they have the same modulus. – EdgarTheWise Jun 23 '14 at 18:09
  • There's no twofold difference. I'm not sure you understood my suggestion. – StilesCrisis Jun 23 '14 at 18:22
  • Probably I didn't. I thought you were suggesting storing all the values in an `std::vector`. Each `Mod` object stores `M` (which is the same throughout the vector) as well as `V`. (A `Mod_template` object doesn't need to store `M`, but `M` needs to be hard-coded.) – EdgarTheWise Jun 23 '14 at 18:26
  • 1
    Yeah, that's not what I meant. Re-read what I wrote and focus on the second paragraph... I don't know how to explain it any more clearly. Store a single `M` value and then make a pool of every `Mod` object that shares the `M`. The `Mod` object will no longer know what its `M` is, which is why you pass it in to all the functions as needed. – StilesCrisis Jun 23 '14 at 19:47