1

I require a vector of integers, where I can distinguish between 0 and -0. So far i've come up with the idea of defining a new class called zero_int for this special case..

However, now I can't push both normal integers and the zero_int into the same vector. The solution std::variant has the size of 8 Bytes and I need to retain the size of 4 per variable.. Defining a virtual base class my_int and setting zero_int to be its derived class increases the size of zero_int to 32 Bytes...

I'm aware one could use something like a vector<void*> but I don't know how.. - Also, are objects pointed to by the pointers in a vector of pointers contiguous in memory?? - This is important in this case.

I would appreciate any suggestions on how to solve this

Adam
  • 743
  • 1
  • 6
  • 11

2 Answers2

4

The solution std::variant has the size of 8 Bytes and I need to retain the size of 4 per variable..

That's impossible, unless you don't mind losing one possible non-zero int value.

Which brings us to the "obvious" solution: treat 0 as -0, and every positive number as itself minus one.

    vec[i]:  -5 -4 -3 -2 -1  0 +1 +2 +3 +4 +5
my "value":  -5 -4 -3 -2 -1 -0 +0 +1 +2 +3 +4

(Or do it the other way around, which gives you symmetry in positive and negative ranges; whatever you like.)

Make whatever class wraps your vector handle this "mapping" in whatever way is appropriate for your project.


are objects pointed to by the pointers in a vector of pointers contiguous in memory??

No.

You don't want more indirection here.


Someone will suggest using floating-point, since IEEE 754 supports signed zero. However, I submit that switching to floating-point for representing real numbers in any case is likely to introduce more problems than it solves.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
  • You lose the value (2^31)-1 with this solution, but that is probably ok? Basically need to be careful of overflow and such... – Michael Dorgan Jun 11 '20 at 18:49
  • I'd be tempted to go the other way: treat non-negative numbers as their natural value, and treat negative numbers as their value plus one. That way, positive numbers are all positive and negative numbers are all negative. It also removes the asymmetry in the range of twos-complement numbers. – Pete Becker Jun 11 '20 at 18:54
  • Yeah, or that. Whatever the OP needs. But the basic idea is a simple off-by-one mapping to add a slot for neg zero. – Asteroids With Wings Jun 11 '20 at 18:57
  • Great solution thanks!, I have no problem with giving up one int value – Adam Jun 11 '20 at 19:21
  • Seems to me like the "obvious" solution is to give up -2^31 and use one's complement. That gives you a symmetric range of representable values, whereas this answer has two more representable negative values than positive values. – user2357112 Jun 11 '20 at 21:30
  • As the others have said, yes. OP can adjust to their needs. – Asteroids With Wings Jun 12 '20 at 10:36
0

I'd consider using an unsigned type and explicitly managing the top bit as a sign bit:

class my_int {
public:
    my_int(int v) { set(v); }
    explicit operator int() const { return get(); }
    bool is_negative() const { return value & sign_bit; }
private:
    const static unsigned sign_bit =
        1u << (std::numeric_limits<unsigned>::digits - 1);
    unsigned value;
    void set(int v) { value = v < 0 ? (-v) & sign_bit : v;
    }
    int get() const { return value & sign_bit ? -(value & ~sign_bit) : value; }
};

Caution: written but not tested.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165