c++ method sometimes returns unexpected high values - c++

I've traced a bug down to a function which should be returning float values between 20 and 100 or so, but is sometimes (1 time in 10) returning values much much higher than that. The problem exists when I have an expression in the last line of the method, like this:
return snap(baseNumber, targets) + (octave * NOTES_PER_OCTAVE);
If I store the return value in a variable first, then return that variable, the problem goes away:
float ret = snap(baseNumber, targets) + (octave * NOTES_PER_OCTAVE);
return ret;
Here's the complete method:
static inline float octaveSnap(float number, std::vector<float>* targets){
static const int NOTES_PER_OCTAVE = 12;
int octave = number / NOTES_PER_OCTAVE;
float baseNumber = number - (octave * NOTES_PER_OCTAVE);
float ret = snap(baseNumber, targets) + (octave * NOTES_PER_OCTAVE);
return ret;
}
and here's 'snap':
// given a single value and a list of values (a scale), return the member of the list which is closest to the single value
static inline float snap(float number, std::vector<float>* targets){
float ret;
float leastDistance = -1;
for(int i = 0; i<targets->size(); i++){
float distance = targets->at(i) - number;
if(distance < 0){
distance = -distance;
}
if(leastDistance == -1){
leastDistance = distance;
}
if(distance < leastDistance){
leastDistance = distance;
ret = targets->at(i);
}
}
return ret;
}
I'm completely baffled by this. Any idea why the first explodes and the second works perfectly?

My psychic debugging powers tell me that when you use the temp variable the problem only appears to go away and that either you're accidentally doing targets[<foo>] inside snap or you use it correctly but rarely run off the end, returning garbage.
EDIT for comment:
I should elaborate a bit: targets is a pointer to vector so using [] on it will select one of several vectors, NOT elements from the vector. That said I can't understand how you could call .at on such a pointer, so I suspect the code in your program is not the code you showed us.

In snap() the local variable ret is never initialized so if the input vector is either zero-sized or the "found" element is the first one then your return value is unspecified.
Try modifying snap to be:
static inline float snap(float number, std::vector<float>* targets){
float ret = 0;
float leastDistance = -1;
for(int i = 0; i<targets->size(); i++){
float distance = targets->at(i) - number;
if(distance < 0){
distance = -distance;
}
if(leastDistance == -1){
leastDistance = distance;
ret = targets->at(i);
}
else if(distance < leastDistance){
leastDistance = distance;
ret = targets->at(i);
}
}
return ret;
}
and see if that fixes things.
Edit: I realized this doesn't address why adding a temporary variable appears to fix things in the original question. The uninitialized ret will probably take on whatever value is left on the stack: this, of course, is unspecified and system/platform dependent. When a new local variable is added to store the result of snap(), however, this shifts the stack such that ret has a different position, most likely, a different uninitialized value. The return result is still "wrong" but it may simply appear "less wrong" due to whatever uninitialized value ret has.

Related

Is there a way to 'reset' a functions variables?

I recently made a function to compare an array of numbers to a single value which returns the closest value to the single value out of the array. This works perfectly well when you only use it only once but if I use it again in another instance of the code, It returns an unexpected value (usually the previous single value used before). Here is the function that I am using:
double closestval (double num1, int amountofnums, double *comps){
double storagecomps[amountofnums];
for (int i = 0; i < amountofnums; i++){
storagecomps[i] = {comps[i]};
/* Storing the array of numbers for later as I will be changing them */
}
double smallval = 0.0001; /* tiny value used to increment/decrement
values in the array to the comparison variable.*/
int_fast64_t compi [amountofnums]; /* this variable keeps track of how many times it needs to decrement/increment the values in the array to approach the variable*/
for (int i = 0; i < amountofnums; i++){
compi[i] = 0;
}
for (int i = 0; i <= amountofnums; i++){
while (comps[i] > num1){
comps[i] -= smallval;
compi[i]++;
}
while (comps[i] < num1){
comps[i] += smallval;
compi[i]++;
}
double recholder[3] = {10000000, 0,};
// This area finds the
for (int i = 0; i < amountofnums; i++){
if (compi[i] < recholder[0]){
recholder[0] = compi[i];
recholder [1] = i;
recholder[2] = storagecomps[i]; /* if the amount of iterations to approach the single variable is less than the previous record holder, it becomes the new one.
*/
}
}
return recholder[2];
}
I am relatively sure this is because (in one way or another) the variables in the function are not being redefined properly or at all. Much thanks if you can show me where I've gone wrong!
The problem isn't resetting the variables. The problem is that you are modifying the arguments passed to the function.
To prevent modifications you should use the const keyword:
double closestval (double num1, int amountofnums, const double *comps){
and then fix the errors the compilers throws at you.
If you do want to modify the comps inside the functions but not have it affect the values outside the functions then you should usestd::vector so you can pass them by value and the compiler will copy them:
double closestval (double num1, int amountofnums, std::vector<double> comps){
You should really do that anyway as you should forget all about C-style arrays till you are an expert.

use of 'n' before deduction of 'auto' C++

I'm trying to have my function return 3 values (n, down and across) I've read online how 'auto' can be used but must be doing something wrong.
The function takes in a 2D vector of integers (as well as other variables) and checks for how many numbers are connected to board[0][0] such that they are the same number.
I've tried putting auto in front of the function inside the function itself, tried leaving it blank, tried just having chain = chainNodes(...) but I always seem to get an error. Here's the code:
tuple<int, int, int> chainNodes(vector<vector<int>> board, int originalNum,
unsigned int across, unsigned int down, int ijSum,
int n)
{
struct chain {
int n, down, across;
};
if(down + across > ijSum) {
ijSum = down + across;
} else if((down + across == ijSum) &&
((down - across) * (down - across) < (ijSum) * (ijSum))) {
ijSum = down + across;
}
board[down][across] = 0;
n += 1;
// Check below
if((down != (board.size() - 1)) && (board[down + 1][across]) == originalNum) {
down += 1;
auto [n, iPoint, jPoint] = chainNodes(board, originalNum, across, down, ijSum, n);
down -= 1;
}
// Check right, up and left (I've removed so its not too messy here)
return chain{n, down, across};
}
Sorry, I forgot to include the error message.
error: use of 'n' before deduction of 'auto'
It occurs on the line that uses auto.
Issue with
auto [n, iPoint, jPoint] = chainNodes(board, originalNum, across, down, ijSum, n);
is similar to
auto n = foo(n); // `foo(n)` uses `n` from `auto n`,
// not the one from outer scope as function parameter
The construct int a = a + 1; is legal but lead to UB as reading uninitialized variable.
That kind of construct allows legal and valid behavior void* p = &p;.
Your code has other errors and it is not clear for me expected behavior of the function.
So not sure if following is the correct fix, but you might want:
n = std::get<0>(chainNodes(board, originalNum, across, down, ijSum, n));

Function always returns 1

I´m trying to write a simple branch predictor that should output either TAKEN (1) or NOT_TAKEN (0) depending on history stored in int. However it always outputs TAKEN instead of dynamicaly changing the prediction.
#define PHT_CTR_MAX 3
#define PHT_CTR_INIT 2
class PREDICTOR{
private:
UINT32 counter;
public:
PREDICTOR(void);
bool GetPrediction(UINT64 PC);
void UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget);
};
PREDICTOR::PREDICTOR(void){
counter = PHT_CTR_INIT;
}
bool PREDICTOR::GetPrediction(UINT64 PC){
if(counter > (PHT_CTR_MAX/2)){
return TAKEN;
}else{
return NOT_TAKEN;
}
}
void PREDICTOR::UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget){
if(resolveDir == TAKEN){
SatIncrement(counter, PHT_CTR_MAX);
}else{
SatDecrement(counter);
}
}
PREDICTOR::PREDICTOR is used to "build" the predictor (create arrays, set initial values...), it is called right in the beginning.
PREDICTOR::GetPrediction should return either TAKEN (when counter = 3 or 2) or NOT_TAKEN (when counter = 0 or 1).
PREDICTOR::UpdatePredictor is called after GetPrediction. It updates the predictor via resolveDir - resolveDir is the actual direction of the branch.
If resolveDir = 1 it does saturated increment of counter (saturated means it never exceeds PHT_CTR_MAX).
If resolveDir = 0 it decrements the counter.
Although this predictor is really simple it does not work. It throws out exactly same results as if I just did GetPrediction{return TAKEN} which is obviously wrong. My coding skills aren´t really great so I might have done something wrong - probably in the GetPrediction or UpdatePredictor function.
Here is an example of predictor that works just fine, although this one is little bit more complex:
#define PHT_CTR_MAX 3
#define PHT_CTR_INIT 2
#define HIST_LEN 17
class PREDICTOR{
private:
UINT32 ghr; // global history register
UINT32 *pht; // pattern history table
UINT32 historyLength; // history length
UINT32 numPhtEntries; // entries in pht
public:
PREDICTOR(void);
bool GetPrediction(UINT64 PC);
void UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget);
PREDICTOR::PREDICTOR(void){
historyLength = HIST_LEN;
ghr = 0;
numPhtEntries = (1<< HIST_LEN);
pht = new UINT32[numPhtEntries];
for(UINT32 ii=0; ii< numPhtEntries; ii++){
pht[ii]=PHT_CTR_INIT;
}
}
bool PREDICTOR::GetPrediction(UINT64 PC){
UINT32 phtIndex = (PC^ghr) % (numPhtEntries);
UINT32 phtCounter = pht[phtIndex];
if(phtCounter > (PHT_CTR_MAX/2)){
return TAKEN;
}
else{
return NOT_TAKEN;
}
}
void PREDICTOR::UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget){
UINT32 phtIndex = (PC^ghr) % (numPhtEntries);
UINT32 phtCounter = pht[phtIndex];
if(resolveDir == TAKEN){
pht[phtIndex] = SatIncrement(phtCounter, PHT_CTR_MAX);
}else{
pht[phtIndex] = SatDecrement(phtCounter);
}
// update the GHR
ghr = (ghr << 1);
if(resolveDir == TAKEN){
ghr++;
}
}
This predictor works in the same way as my simple one, except that it uses an array of counters instead of single one. When GetPrediction is called the array is indexed by last 17 bits of resolveDir (branch history, global history register or ghr) that are XORed with PC (adress of current branch). This selects the appropriate counter from array that is then used to do the prediction. UpdatePredictor works the same way, array is indexed and then counter is choosen. Counter is updated with information from resolveDir. Lastly the global history buffer (ghr, branch history, call it what you want) is also updated.
Code of the SatIncrement and SatDecrement functions:
static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if(x<max) return x+1;
return x;
}
static inline UINT32 SatDecrement(UINT32 x)
{
if(x>0) return x-1;
return x;
}
Thanks for help.
The reason the code doesn't work as expected is that SatIncrement and SatDecrement take arguments by-value and return the new value, which then must be assigned back to the variable that is supposed to be incremented/decremented.
SatIncrement(counter, PHT_CTR_MAX);
will pass the value of counter but will not modify counter itself. The return value with the new value is not used and so effectively this line does nothing. The same is true for SatDecrement(counter);.
Therefore your branch predictor never changes state and always returns the same prediction.
Fix it by following the other code example:
counter = SatIncrement(counter, PHT_CTR_MAX);
and
counter = SatDecrement(counter);
Given that this is an exercise you probably cannot change SatIncrement and SatDecrement, however in practice one would probably let these functions take arguments by-reference, so that they can modify the passed variable directly, avoiding the repetition of counter at the call site:
static inline void SatIncrement(UINT32& x, UINT32 max)
{
if(x<max) x++;
}
If the original signature were chosen, then since C++17 one can add the [[nodiscard]] attribute to the function to make the compiler print a warning if the return value is not used:
[[nodiscard]] static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if(x<max) return x+1;
return x;
}
It would have warned you here and made the problem clearer.

Mantain the original value in a recursive function c++

I am trying to solve a square root in a recursive way. I do not want the code to solve that! I am almost done, but I do not know how to mantain the original value of the function:
float raizCuadrada(float num, float err) {
float nuevo = num / 2;
float resta=(nuevo*nuevo)-num;
if(resta>err){
return (raizCuadrada(nuevo, err));
}
else if (resta <= err) {
return (nuevo);
}
}
I basicly want to know how to "save" that first "num" call, somewhere, to use it ALWAYS in the "resta", the "- num" should be always the number that 1st put.
NOTES: I cannot input more inputs. I can only input 1 number and the error.
You can define a global variable at the top of your code.
float num_fixed;
float raizCuadrada(float num, float err) {
float nuevo = num / 2;
float resta=(nuevo*nuevo)-num_fixed;
if(resta>err){
return (raizCuadrada(nuevo, err));
}
else {
return (nuevo);
}
}
int main(void){
float num = 2.0;
float err = 0.000001;
float output;
num_fixed = num;
output = raizCuadrada(num, err);
}
I would recommend the two solutions that have been proposed. Either overload a function that takes three arguments or use a global.
If you for some reason don't want to do that, you can use some trickery:
float raizCuadrada(float num, float err) {
static float org = -1;
if(org<0)
org = num;
float nuevo = num / 2;
float resta=(nuevo*nuevo)-org;
float ret;
if(resta>err)
ret = raizCuadrada(nuevo, err);
else
ret = nuevo;
if(org>=0)
org=-1;
return ret;
}
I would not recommend this method unless you really have a special need for it. It is quite easy to do mistakes, and I cannot think of any real benefit. But since it is possible, I wanted to show it.
I basicly want to know how to "save" that first "num" call, somewhere,
to use it ALWAYS in the "resta", the "- num" should be always the
number that 1st put.
NOTES: I cannot input more inputs. I can only input 1 number and the
error. c++
The solution I most often use is to separate the two 'efforts' into two methods:
1) Start with a method (use your original method name) to save the first variable to a safe space. I will leave the 'where' up to you. Here I have simply made up a new variable name (origNum), in a scope available to the code of each method. In C++, I would expect that the class containing these methods would 'save' and use an instance data attribute.
float raizCuadrada(float num, float err) // same name as original
{
origNum = num; // "save" original 'num'
return (raizCuadrada2(num, err)); // continue normally
}
2) Then a mild re-factor of your previous code uses the "saved" value. Since you can not change the parameters, I suggest a slight method name change, here I created raizCuadrada with suffix '2'.
float raizCuadrada2(float num, float err) {
float nuevo = num / 2;
float resta=(nuevo*nuevo)-origNum; // use origNum here
if(resta>err){
return (raizCuadrada(nuevo, err));
}
else if (resta <= err) {
return (nuevo);
}
}
note - not compiled. not tested.

c++ type error message from compiler, what does it mean?

I'm using g++ on fedora linux 13.
I'm just practicing some exercises from my c++ textbook
and can't get this one program to compile. Here is the code:
double *MovieData::calcMed() {
double medianValue;
double *medValPtr = &medianValue;
*medValPtr = (sortArray[numStudents-1] / 2);
return medValPtr;
}
Here is the class declaration:
class MovieData
{
private:
int *students; // students points to int, will be dynamically allocated an array of integers.
int **sortArray; // A pointer that is pointing to an array of pointers.
double average; // Average movies seen by students.
double *median; // Median value of movies seen by students.
int *mode; // Mode value, or most frequent number of movies seen by students.
int numStudents; // Number of students in sample.
int totalMovies; // Total number of movies seen by all students in the sample.
double calcAvg(); // Method which calculates the average number of movies seen.
double *calcMed(); // Method that calculates the mean value of data.
int *calcMode(); // Method that calculates the mode of the data.
int calcTotalMovies(); // Method that calculates the total amount of movies seen.
void selectSort(); // Sort the Data using selection sort algorithm.
public:
MovieData(int num, int movies[]); // constructor
~MovieData(); // destructor
double getAvg() { return average; } // returns the average
double *getMed() { return median; } // returns the mean
int *getMode() { return mode; } // returns the mode
int getNumStudents() { return numStudents; } // returns the number of students in sample
};
Here is my constructor and destructor and selectSort():
MovieData::MovieData(int num, int movies[]) {
numStudents = num;
// Now I will allocate memory for student and sortArray:
if(num > 0) {
students = new int[num];
sortArray = new int*[num];
// The arrays will now be initialized:
for(int index = 0;index < numStudents;index++) {
students[index] = movies[index];
sortArray[index] = &students[index];
}
selectSort(); // sort the elements of sortArray[] that point to the elements of students.
totalMovies = calcTotalMovies();
average = calcAvg();
median = calcMed();
mode = calcMode();
}
}
// Destructor:
// Delete the memory allocated in the constructor.
MovieData::~MovieData() {
if(numStudents > 0) {
delete [] students;
students = 0;
delete [] sortArray;
sortArray = 0;
}
}
// selectSort()
// performs selection sort algorithm on sortArray[],
// an array of pointers. Sorted on the values its
// elements point to.
void MovieData::selectSort() {
int scan, minIndex;
int *minElement;
for(scan = 0;scan < (numStudents - 1);scan++) {
minIndex = scan;
minElement = sortArray[scan];
for(int index = 0;index < numStudents;index++) {
if(*(sortArray[index]) < *minElement) {
minElement = sortArray[index];
minIndex = index;
}
}
sortArray[minIndex] = sortArray[scan];
sortArray[scan] = minElement;
}
}
The compiler is giving this error:
moviedata.cpp: In memberfunction
'double * MovieData::calcMed()':
moviedata.cpp:82: error: invalid
operands of types 'int*' and 'double'
to binary 'operator/'
I'm not sure what to make of this error, i've tried static casting the types with no luck, what does this error message mean?
you are trying to divide a pointer by a double, which the compiler is saying it does not know how todo.
sortArray is probably defined by
int ** sortArray;
its also worth noting you are returning a pointer to a stack variable, who's value will be undefined as soon as you return out of the function.
sortArray[numStudents - 1] is a pointer to int, which can't be on the left side of a division (when you remember pointers are addresses, this makes sense). If you post more of your code, we can help you correct it.
Perhaps you want something like:
int *MovieData::calcMed() {
return sortArray[(numStudents - 1) / 2];
}
This returns the middle element in your array, which should be a pointer to the middle student. I'm not clear why you're sorting lists of pointers (not the actual values), or why you're returning a pointer here. The return value + 1 will be a pointer to the next value in students, which is not the next greater value numerically. So you might as well return the actual student (int from students). If you do this, you can also average the two middle elements when the count is even (this rule is part of the typical median algorithm).
Note that I changed the return type to int *, the type of sortArray's elements. Also, your comment is incorrect. This is the median, not the mean.
Also, your selection sort is wrong. The inner loop should start at scan + 1.
Your code shows a lack of understanding of pointers. You need to do more reading and practice on simpler examples.
More specifically:
double medianValue; creates a double variable. What for? You're apparently going to return a double * and returning a pointer to a local variable is always wrong, because local variables are "recycled" when their function ends.
double *medValPtr = &medianValue; creates a pointer called medValPtr and sets it to the location of medianValue. Well.
Due to the current contents of medValPtr, *medValPtr = (sortArray[numStudents-1] / 2); has the same effect as typing medianValue = (sortArray[numStudents-1] / 2); (supposing it were to compile at all).
Which it doesn't because sortArray[numStudents-1] is, at a guess, the last item in the array sortArray but happens to be a pointer to something else. You can't divide a pointer (numerically you can, but C++ disallows it's always wrong).
Finally you return medValPtr; which is wrong because medValPtr is pointing to a local variable.
You probably want something like:
int *MovieData::calcMed() {
return sortArray[numStudents/2];
}