Search code examples
c++typesdoublerounding

Why is this loop seeming to change the value of a variable?


The following code is meant to calculate 7 terms: tcapneg, tcappos, tneg1, tneg2, tpos1, tpos2, tzcap (only the calculation of tpos1 and tpos2 is shown here), and determine the entry that satisfies the condition of being the smallest positive non-zero entry.

int hitb;
double PCLx = 2.936728;
double PCLz = -0.016691;
double PDCx = 0.102796;
double PDCz = 0.994702;
double q = 0.002344;
double s = 0.0266;
double v = 0.0744;
double a = -q * PDCx * PDCx;
double b = s * PDCx - 2 * q*PCLx*PDCx - PDCz;
double c = -1.0*(PCLz + q * pow(PCLx, 2) - s * PCLx + v);
double d = b * b - 4 * a*c;

if (d >= 0.0f) // only take solution if t real
{
    tpos1 = (-b + sqrt(d)) / (2 * a);
    tpos2 = (-b - sqrt(d)) / (2 * a);
}

printf("\n %f %f %f %f %f %f %f", tcapneg, tcappos, tneg1, tneg2, tpos1, tpos2, tzcap);

yielding the result:

 0.000000 0.000000 -40326.381162 -0.156221 -40105.748386 0.000194 0.016780

It is seen that the expected result should be smallest = tpos2 = 0.000194.

double smallest = -1.0;
double tlist[7] = { tcapneg, tcappos, tneg1, tneg2, tpos1, tpos2, tzcap };
const int size = sizeof(tlist) / sizeof(int);
for (int i = 0; i < size; i++)
{
    if (tlist[i] > EPSILON && (smallest == -1.0 || tlist[i] < smallest))
    {
        smallest = tlist[i];
    }
}
printf("\n %f", smallest);

The output for smallest = 0.000192, thus smallest != tpos2 != 0.00194. Why is there this small change in value for the selected smallest entry?

The result of smallest will be fed to the following code:

            if (smallest == tneg1 || smallest == tneg2)
            {
                hitb = 1;
            }
            else if (smallest == tpos1 || smallest == tpos2)
            {
                hitb = 2;
            }
            else if (smallest == tcappos)
            {
                hitb = 3;
            }
            else if (smallest == tcapneg)
            {
                hitb = 4;
            }
            else if (smallest == tzcap)
            {
                hitb = 5;
            }

In this case, we should satisfy the condition to write hitb = 2, however this is failing due to the inequality above.


Solution

  • Your array double tlist[7] is in double with 7 elements. sizeof(double) is 8, so sizeof(tlist) is 8*7 = 56. While sizeof(int) is 4, so your size = sizeof(tlist) / sizeof(int) is 56/4 = 14. Your loop goes beyond number of elements in the array. It counts 7 more double values after the array in memory, because the array name is used as a pointer.

    Here is my code to verify the above nanalysis

    #include <iostream>
    using namespace std;
    int main()
    {
        double da[7] = {0.0, 0.0, -40326.381162, -0.156221, -40105.748386, 0.000194, 0.016780};
        const int sda = sizeof(da);
        const int sin = sizeof(int);
        const int siz = sda/sin;
        cout << "sda:" << sda << " sin:" << sin << " siz:" << siz << endl;
    
        for( int i=0; i<siz; i++ ) {
            cout << "da[" << i << "] = " << da[i] << endl;
        }
    
        return 0;
    }
    

    Here is the output

    sda:56 sin:4 siz:14
    da[0] = 0
    da[1] = 0
    da[2] = -40326.4
    da[3] = -0.156221
    da[4] = -40105.7
    da[5] = 0.000194
    da[6] = 0.01678
    da[7] = 2.07324e-317
    da[8] = 8.48798e-314
    da[9] = 1.9098e-313
    da[10] = 0
    da[11] = 1.31616e-312
    da[12] = 0
    da[13] = 6.95332e-310
    

    The correct code is

    size = sizeof(tlist) / sizeof(double);
    

    Use the following option for GCC to report runtime error in this case

    g++ -fsanitize=bounds -o main.e main.cpp