0

I have an admittedly very basic problem: I need to compare two numbers of type double for >=. For some reason, however, my code evaluates to true for values I know to be less than the threshold.

EDIT: My code (the error occurs in the countTrig() method of the Antenna class):

#define k 0.0000000000000000000000138064852    // Boltzmann's constant

class Antenna{

    vector<vector<double> > output;

    int channels, smplrate, smpldur, samples, timethld;
    double resistance, temp, bandwidth, lnanoise, lnagain, RMS;

    public:
        Antenna(
            const int    _channels,   const int    _smplrate, const int    _smpldur,
            const double _resistance, const double _temp,     const double _bandwidth,
            const double _lnanoise,   const double _lnagain
        ){
            channels    = _channels;    smplrate    = _smplrate;    smpldur   = _smpldur;
            resistance  = _resistance;  temp        = _temp;        bandwidth = _bandwidth;
            lnanoise    = _lnanoise;    lnagain     = _lnagain;

            RMS     = 2 * sqrt(4 * k * resistance * temp * bandwidth);
            RMS    *= lnagain * pow(10,(lnanoise/10));
            samples = smplrate/smpldur;

            timethld = 508; //= (1/smplrate) * 0.127;

        }

        void genThrml(int units);
        void plotTrig(int timethld, double voltsthld);
        void plotThrml();
        int countTrig(double snrthld, int iter);

};

double fabs(double val){ if(val < 0){ val *= -1; } return val; }

void Antenna::genThrml(int units){

    output.resize(samples, vector<double>(channels));
    samples *= units;

    gRandom->SetSeed(time(NULL));
    for(int i = 0; i < samples; ++i){
        for(int j = 0; j < channels; ++j){
            output[i][j] = gRandom->Gaus(0,RMS);
        }
    }

}

void Antenna::plotThrml(){
    //Filler
}

int  Antenna::countTrig(double snrthld, int iter){

    int count = 0;

    int high = iter + timethld;
    int low  = iter - timethld;

    if(low < 0){ low = 0; }
    if(high > samples){ high = samples; }

    for(int i = low; i < high; ++i){

        for(int j = 0; j < channels; ++j){
           if(output[i][j] >= snrthld) count++; std::cout << output[i][j] << " " << snrthld << "\n";
        }
    }

    if(iter >= 3) return 1;
    else         return 0;

}

void Antenna::plotTrig(int timethld, double voltsthld){

    double snrthld = voltsthld / RMS;

    for(int i = 0; i < samples; ++i){
        for(int j = 0; j < channels; ++j){
            countTrig(snrthld, i);
        }
    }

}

int main(){

    Antenna test(20,4000,1,50,290,500000000,1.5,60);

    test.genThrml(1);
    test.plotTrig(400,0.0005);

    return 0;

}

With a threshold of 0.147417, I get output like this:

 0.0014238 
-0.00187276

I believe I understand the problem (unless there's some obvious mistake I've made and not caught), and I understand the reasoning behind floating point errors, precision, etc. I don't, however, know, what the best practice is here. What is a good solution? How can I reliably compare values of type double? This will be used in an application where it is very important that values be precise and comparisons be reliable.

EDIT: A smaller example:

int  countTrig(double snrthld, int iter, vector<vector<double> > output, int timethld){

    int count = 0;

    int high = iter + timethld;
    int low  = iter - timethld;

    if(low < 0){ low = 0; }
    if(high > 3){ high = 3; }

    for(int i = low; i < high; ++i){

        for(int j = 0; j < 3; ++j){
           if(fabs(output[i][j]) >= snrthld) count++; std::cout << output[i][j] << " " << snrthld << "\n";
        }
    }

    if(iter >= 3) return 1;
    else         return 0;

}

void plotTrig(int timethld, double snrthld){

vector<vector<double> > output = {{0.000028382, -0.0028348329, -0.00008573829},
                                  {0.183849939,  0.9283829020, -0.92838200021},
                                  {-0.00292889,  0.2399229929, -0.00081009189}};

    for(int i = 0; i < 3; ++i){
        for(int j = 0; j < 3; ++j){
            countTrig(snrthld, i, output, timethld);
        }
    }

}

int main(){

    plotTrig(1,0.1);
    return 0;

}
10GeV
  • 453
  • 2
  • 14
  • 1
    Could you make a [mre]? Hard code some input, it should only be a few lines. – cigien Sep 19 '20 at 17:15
  • @cigien Sure! Just a moment. – 10GeV Sep 19 '20 at 17:15
  • The above code doesn't do what you describe. Your actual code has bugs that the above code does not, and the above code has bugs that your actual code does not. Us trying to fix bugs in the above code is pointless. This is why we want an actual example that actually produces the actual bugs that you are actually seeing. As a trivial example, the above code doesn't print newlines; it prints `n` instead. Ridiculous, but your actual code has a similar issue that is causing your problem, and we can't see it, because we don't have it. – Yakk - Adam Nevraumont Sep 19 '20 at 17:17
  • @Yakk-AdamNevraumont I've posted my exact code. – 10GeV Sep 19 '20 at 17:21
  • That's much better. Now you need to find the first place that the code doesn't do what you want. A debugger would be good, but even printing intermediate results will help. – cigien Sep 19 '20 at 17:22
  • @cigien The issue is in the `if(output[i][j]...` line of the `countTrig()` method (or, at least, that's where I first notice the issue). Everything up to then seems to work fine. – 10GeV Sep 19 '20 at 17:23
  • In that case, remove everything else, and provide hard-coded inputs to that function. – cigien Sep 19 '20 at 17:25
  • @cigien I've added that to the post. I'll see what else (if anything) I can remove in the meantime. – 10GeV Sep 19 '20 at 17:30
  • Even better. Keep removing stuff, my guess is you can shorten your problem to about 5-6 lines in `main`. – cigien Sep 19 '20 at 17:35

1 Answers1

1

You have a typo.

       if(output[i][j] >= snrthld) count++; std::cout << output[i][j] << " " << snrthld << "\n";

this line means

       if(output[i][j] >= snrthld)
         count++;
       std::cout << output[i][j] << " " << snrthld << "\n";

aka

       if(output[i][j] >= snrthld)
       {
         count++;
       }
       std::cout << output[i][j] << " " << snrthld << "\n";

and you want:

       if(output[i][j] >= snrthld)
       {
         count++;
         std::cout << output[i][j] << " " << snrthld << "\n";
       }
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524