simont
simont

Reputation: 72527

Taking sum of std::vector is using references instead of values?

I have a vector containing integer values, which I wish to sum. However, it's summing the total wrong - if the vector holds 10 ints between -10 and 10, my total should not be 18446744073709551602.

I declare the vector, and populate it with values:

std::vector<int> X;
for ( int i = 0; i < readings.size() ; ++i ) { 
    X.push_back(readings[i].x);

I then sum and display:

unsigned long temptotal = 0;
for ( int i = 0; i < readings.size() ; ++i ) {
    std::cout << "Value in X: " << X[i] << std::endl;
    temptotal += X[i];
}
std::cout << "Temp total: " << temptotal << std::endl;

which produces the following output: Temp total: 18446744073709551603.

When I step through the summation loop in GDB, (at temptotal += X[i];), I can print X[i]:

(gdb) p X[i]
$1 = (reference) @0x100100c80: -1

Printing temptotal before and after the addition is performed:

(gdb) p temptotal
$2 = 0
(gdb) p temptotal
$3 = 18446744073709551615

I'm fairly sure that I'm adding the memory locations rather than the values in the memory locations - I could be wrong on that - but I'm not sure why I'm not adding the values at X[i]. When I populate X with the values from readings[i].x, they're doubles, which I then type-cast to ints. Is this where my error is? Checking in GDB, my type-cast of the readings[i].x value should be an int, or, at least, a number of some kind:

(gdb) p (int)readings[i].x
$1 = -1

I'm stumped; if somebody could shed some light on why I'm not adding what I think I'm adding, I'd be grateful.

EDIT
It's the casting from int to unsigned long. I went over it and over it, pressed "submit question" and spotted my error. Although, I still don't understand why it's doing what it's doing - any light shed on that would be wonderful - why, if I'm adding an int to an unsigned long, does it not take the value from the int?

Upvotes: 1

Views: 152

Answers (3)

Alexander Kondratskiy
Alexander Kondratskiy

Reputation: 4275

You asked in your edit as to why this is happening. This is due to the binary representation of integral types in memory.

In the simple case of unsigned int you can think of any positive number as the direct representation of it in binary, that is

1 == 0b1
2 == 0b10
...
42 == 0b101010

Each number is stored in some limited amount of memory, and for int that is usually 32bits (or 4 bytes). This means that all the bits to the left of the representations above are zeros.

An int however, is signed, so that information has to be stored somewhere. It just so happens to be Twos complement is a convenient binary representation for signed integers in binary (read up on it). What it means is that for ints

0 = 0b0
-1 = 0b11111111111111111111111111111111 (32 bits of all ones)

As you might be realizing now, when you convert an int to an unsigned int instead of a negative number you get a very large positive number, due to the binary representations of these numbers. In general you don't want to mix unsigned and signed integers in your calculations unless you know precisely what you're doing.

Upvotes: 2

YXD
YXD

Reputation: 32511

No, you are taking 1 away from your unsigned long and it's wrapping round.

Also, use std::accumulate:

result = std::accumulate(readings.begin(), readings.end(), 0);

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726499

This is because your temptotal is unsigned. All numbers added to it are interpreted as unsigned, hence small negative numbers become large positive numbers in two's complement representation.

Upvotes: 4

Related Questions