strange behaviour vector.size()

Hey guys,
I have a strange bug in my current simulation programm.
In my subfunction update_eta_force, I calculate eta_force via the size of the submitted vector vel. The vector is created in the main function (there called v) through the readin function. The readin is working fine.
Now vel.size() does have a value of 144, as it should be. But the result of the initializing calculation eta_force=-2*vel.size()*T; somehow yields a value of the order 10^9. After the calculation, I check wether vel.size() is normal again, which it is.
So why does my calculation give such a result?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <cmath>
#include <fstream>
#include <vector>

using namespace std;

struct particle{
double x;
double y;
};

void readin_file(string& filename, vector <particle>& p, vector <particle>& v){
    ifstream inFile;
    inFile.open(filename);
    if(inFile.fail()){                  // Error test
        cerr<< "Error opening file"<<endl;
        exit(1);
    }
    double x,y,vx,vy;
    while(inFile >> x >> y >> vx >> vy){
        p.push_back({x,y});
        v.push_back({vx,vy});
    }
    inFile.close();
}


void update_eta_force(vector <particle>& vel, double& eta_force, double& T){
		cout<< vel.size()<<endl;
		eta_force=-2*vel.size()*T;
		cout << eta_force<<endl;
		cout<<vel.size()<<endl;
	for (int i=0;i<vel.size();i++){
		eta_force+=(vel[i].x * vel[i].x) + (vel[i].y * vel[i].y);
	}
}


  int main(){
double dt=0.0005;
double R=pow(2,1./6);
double L=14;
double Ekin;
double Epot;
double T=1.5;  //thermostat temperature
double temp;   //instantaneous temperature
double eta=1;
double p_eta=1;
double p_eta_half;
double eta_force;
double Q_bar=100; //coupling constant
string initial_dat="initial.txt";
vector <particle> p,v;
readin_file(initial_dat,p,v);
vector <particle> F(p.size());
double Q=Q_bar*2*p.size();
update_forces(F,p,R,L,Epot);
update_eta_force(v,eta_force,T);
}


Cheers
Last edited on
This is an unfortunate side-effect of unsigned integers. :-/

vel.size() returns an unsigned integer.
-2 is a signed integer.

When you multiply a signed integer with an unsigned integer (and the size of the unsigned integer type is at least as big as the signed integer type and at least as big as an int) the signed integer will be converted to the unsigned integer type before the multiplication takes place.

To avoid this issue you can cast the size to signed int (or to double)

 
-2 * static_cast<int>(vel.size()) * T; 

or you can make sure that the size is multiplied with the double before being multiplied with the signed integer by using parentheses (or by reordering the operands).

 
-2 * (vel.size() * T); 

Turning the -2 constant into a double will also work.

 
-2.0 * vel.size() * T; 
Last edited on
Thank you for the answer, I did not take that into consideration.


When you multiply a signed integer with an unsigned integer (and the size of the unsigned integer type is at least as big as the signed integer type and at least as big as an int) the signed integer will be converted to the unsigned integer type before the multiplication takes place.


And this conversion leads to undefined behaviour? I would have guessed -2 would be converted to +2 then, but that's probably too simple minded.
It's not undefined behaviour.

Unsigned arithmetic wraps around so when you go below zero you start counting from the highest positive value. -2 converted to unsigned is the second highest unsigned value, which is 4294967294 for a 32-bit unsigned type and 18446744073709551614 for a 64-bit unsigned type.
Ah, that's why the value got so high.

What would be considered "good practice" in that situation? Would you use static_cast or simply write 2.0?
I would've preferred -2.0. You are working with floating point values so I think it makes sense to use floating literals, not just here. The implicit conversion from unsigned integer to a floating point number is perfectly safe so no need for casting.
Alright, thank you for the help!
Registered users can post here. Sign in or register to post.