Ok, so I used commenting to chase it down and I was wrong, it's definitely the regression element that's causing the problem because commenting it out prevents the exception from being thrown. Must not have tested it as thoroughly as I thought! I guess the next step is figuring out where in here the problem is coming from.
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
|
void Food::get_history_reg(bool isoptimist){
//http://en.wikipedia.org/wiki/Simple_linear_regression#Numerical_example
//quick brush up on regression w/ example
const int historysize = history_gather.size(); //reinforces that vector should not change size
get_avg_gather(isoptimist);
//create time
std::vector<int> time;
for (int i=0; i<historysize; i++)
time.push_back(i);
const int timesize = time.size();
//stime block
int stime = accumulate(time.begin(), time.end(), 0);
//sgather block
int sgather = accumulate(history_gather.begin(), history_gather.end(), 0);
//timextime block, would prefer to do this in vector<int> time rather than toss into new vector
//would have to move below stxg init if that happened
std::vector<int> timextime;
for (int i=0; i<timesize; i++)
timextime.push_back(time.at(i)*time.at(i));
int stxt = accumulate(timextime.begin(), timextime.end(), 0);
//timexgather block, this one needs the new vector, might still be a quicker way to do it
std::vector<int> timexgather;
for (int i=0; i<historysize; i++)
timexgather.push_back(history_gather.at(i)*time.at(i));
int stxg = accumulate(timexgather.begin(), timexgather.end(), 0);
//this can result in a double, not too concerned about losing tail
int top = ((timesize * stxg)-(stime*sgather));
int bottom = ((timesize * stxt)-(stime*stime));
int slope = top/bottom;
//standard deviation block
std::vector<int> gather_devs;
for (int i=0; i<historysize; i++) {
int left = history_gather.at(i) - mean;
gather_devs.push_back(left * left);
}
double dev_sum = accumulate(gather_devs.begin(), gather_devs.end(), 0);
double avg_dev_sum = dev_sum/historysize;
int std_dev = sqrt(avg_dev_sum);
//sds is a struct that holds slope and std dev
sds.slope = slope;
sds.std_dev = std_dev;
sds.average = mean;
}
|
get_avg_gather() (the code for it follows) is the only function call in get_history_reg(). It gets called first. When I look through the call stack, here's what I see:
1 2 3 4 5 6
|
> robo2.exe!std::_Vector_const_iterator<int,std::allocator<int> >::operator+=(int _Off = 2) Line 163 C++
robo2.exe!std::_Vector_iterator<int,std::allocator<int> >::operator+=(int _Off = 2) Line 375 + 0xc bytes C++
robo2.exe!std::_Vector_iterator<int,std::allocator<int> >::operator+(int _Off = 2) Line 382 + 0x12 bytes C++
robo2.exe!std::_Copy_opt<std::_Vector_iterator<int,std::allocator<int> >,std::_Vector_iterator<int,std::allocator<int> >,std::random_access_iterator_tag>() Line 2504 + 0xe bytes C++
robo2.exe!std::copy<std::_Vector_iterator<int,std::allocator<int> >,std::_Vector_iterator<int,std::allocator<int> > >() Line 2563 + 0x11e bytes C++
robo2.exe!Food::get_avg_gather(bool = false) Line 40 + 0xb9 bytes C++
|
The problem is I'm only halfway certain what most of that means! But it seems to indicate that the problem occurs somewhere in get_avg_gather(), or at least that there's no function call that follows it. Here's the get_avg_gather():
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
|
int Food::get_avg_gather(bool isoptimist) {
const int historysize =history_gather.size();
if (historysize ==0)
return (0);
std::vector<int> local_history;
copy(history_gather.begin(), history_gather.end(), local_history.begin());
sort (local_history.begin(), local_history.end());
const long sum = accumulate (history_gather.begin(), history_gather.end(), 0);
mean = sum/historysize;
int median =0, arg =0;
if (historysize%2 !=0)
median = local_history.at((historysize/2)+1);
else {
arg = historysize/2;
int left1 = local_history.at(arg);
int left2 = local_history.at(arg+1);
median = (left1 + left2)/2;
}
if (isoptimist ==0)
return (std::min(median, mean));
else
return (std::max(mean, median));
}
|
I think this might be the problem here:
|
copy(history_gather.begin(), history_gather.end(), local_history.begin());
|
All the debugger stuff seems to reference copying. This is the only copy in the function. I'm going to try writing the following code and see if it fixes the problem:
1 2 3 4
|
for (int i=0; i<historysize; i++){
int higath = history_gather.at(i);
local_history.push_back(higath);
}
|
Update:
So, that change did nothing. I now get the following error box:
1 2 3 4
|
An unhandled exception of type
'System.Runtime.InteropServices.SEHException' occurred in robo2.exe
Additional information: External component has thrown an exception.
|
Which is a little arcane. The call stack reads the following:
1 2 3 4 5 6 7
|
> kernel32.dll!7c812afb()
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
[Managed to Native Transition]
robo2.exe!std::vector<int,std::allocator<int> >::_Xran() Line 1265 + 0x28 bytes C++
robo2.exe!std::vector<int,std::allocator<int> >::at(unsigned int _Pos = 2) Line 755 C++
robo2.exe!Food::get_avg_gather(bool = false) Line 58 + 0xf bytes C++
|
Which is a little more arcane. I'm guessing it means the problem is somewhat lower than the copy function, but I dunno. Googling produces nothing other than the potential that I've left out a library, which isn't likely since this is being run out of the IDE.
Update:
A chance peek at Output showed me this little bit:
|
First-chance exception at 0x7c812afb in robo2.exe: Microsoft C++ exception: std::out_of_range at memory location 0x0012eae0..
|
Which I think I understand. And it made a lot more sense when it led me to this:
1 2 3 4
|
static void _Xran()
{ // report an out_of_range error
_THROW(out_of_range, "invalid vector<T> subscript");
}
|
I'm betting it has something to do with this section:
1 2 3 4 5 6 7 8 9 10
|
if (historysize%2 !=0){
int loc = (historysize/2)+1;
median = local_history.at(loc);
}
else {
arg = historysize/2;
int left1 = local_history.at(arg);
int left2 = local_history.at(arg+1);
median = (left1 + left2)/2;
}
|
My money is on it being the first one. It divides by 2, then adds 1 -- SOP for getting a median, but since vector positions start at zero, if it divides 2/2=1, and then adds 1 then it'll be trying to get somevector.at(2) when there are only two elements it'll get, well, an error. This MUST be it! My LORD this is insidious as hell! No wonder people pull their hair out over logic errors!