Big Calculator gets out of hand

    Calculator

    I want to devote this article to a problem that few people think about. More and more widely applied modeling of various processes using a computer. This is great, the ability to save time and materials on meaningless chemical, biological, physical and other experiments. Blowing a wing model on a computer can several times reduce the number of layouts that will then be tested in a real wind tunnel. Numerical experiments are being trusted more and more. However, no one pays attention to the growing complexity of programs behind the triumph of numerical modeling. In the computer and in the programs they see only a tool for obtaining a result. It disturbs me that not everyone knows and thinks that increasing the size of a program leads to a nonlinear increase in the number of errors. It is dangerous to use a computer as just a big calculator.


    Large calculator


    In the beginning, I wanted to call this article something like this: “If programmers cannot make medicines, then why can doctors program?” An abstract programmer should not be involved in the invention and manufacture of drugs. The reason is clear - he does not have the appropriate education. But programming is not so simple. It seems that an abstract medic, having mastered programming, will automatically bring benefits. Fortunately, learning how to program somehow is easier than understanding organic chemistry and the principles of creating drugs.

    Here lies the catch. A numerical experiment requires no less accuracy than a real one. Learn to wash tubes after experiments and monitor their sterility. But few people are seriously concerned about the problem that some kind of array may accidentally be uninitialized.

    Programmers know that the more complex the software, the more complex and not more obvious errors appear in it. In other words, I'm talking about a non-linear increase in the number of errors with increasing code size. But programs for chemical and other calculations are far from simple. This is where the trouble lies. It's not scary that the medical programmer makes mistakes. They are made by any programmer, regardless of professionalism. It is scary that such results are beginning to be increasingly trusted. They considered something and went on to go about their business.

    Those whose main activity is programming know the dangers of such an approach. They know what indefinite behavior is and how a program can pretend to produce the correct result. There are articles and books on how to write unit tests correctly and how best to verify the correctness of calculations.

    This is the world of programmers. In the world of chemists / physicists / doctors, I'm afraid this is not the case. They do not write a complicated program. Rather, they do not think in this direction. They just use a computer as a Big Calculator. Such a comparison was brought by one of the readers. I will quote his quote here in full, so that after the translation of the article, English-speaking readers can also get to know it.

    I have something to say on this subject based on personal experience. Being a professional programmer, I am a hereditary physicist by training. It just so happened that at the moment when I was choosing a university, the voice of blood turned out to be stronger than faith in the bright future of IT. And I entered a rather prestigious physical higher school by local standards, which, in fact, is a “kindergarten” at a large research institute in the native city of Nizhny Novgorod. People who know the topic will recognize both the research institute and the name of the school.

    During my studies, it turned out quite naturally that in terms of programming (including mathematical methods of physical modeling) I was one of the best. And there the following facts became clear:

    1. Physicists see the computer as a large multi-functional calculator that allows you to build a graph of This versus Theta with Gamma tending to infinity. Moreover, in an obvious way, for them the goal is a schedule, and not at all the program that draws it.

    2. As a consequence of this fact, a programmer is not a profession. A programmer is just that person who knows how to use the Big Calculator to build a designated schedule. How the schedule will be built does not matter. Absolutely. How-how did you say? Static analysis? Version control? Look around, dear! C ++ is a language for programmers. Physicists write on Fortran!

    3. As a consequence of the previous paragraph, a person seeking to devote his life to writing physical programs. modeling, even universal, even very, very cool - no more than an application to a calculator. He’s not a man at all, but so ... And this, by the way, extended not only to me (to me, wretched already), but even to the best numerical calculator at the research institute, which taught us numerical methods and which, when I arrived to do term papers for him, he told me in almost plain text: "They will despise you, get ready to endure."

    I did not want to endure, and after graduation I left modeling in an area where programmers are not considered second-class people. I hope this example explains why initiatives such as introducing static analysis even on relatively large (up to 20-30 people) mathematical modeling projects are a bad job. There simply may not be a person who knows what it is. And if such a person exists, they will most likely be trampled on, because these newfangled programmer gadgets are not needed. We lived without them for a hundred years - and we will continue to live.

    And for those who are not bored, a second example. My father, being in retirement age, nonetheless works in a very large defense engineering enterprise, here in Nizhny (the largest in the city and one of the largest in the country - those who guess the subject again;)). He has been programming in Fortran all his life. Started with punch cards. I don't blame him for not teaching C ++. It was too late for him 10 years ago - he is still holding on well. But at the enterprise, where 2/3 of the employees are somehow programming, the following security measures have been taken:

    1. No internet. Absolutely. Need literature - go to your local library. Stack overflow? What is this? Even if you want to send a letter by e-mail, you must write a statement to the boss, where you will explain to whom this letter is and why. Only a select few have the Internet “on receipt”. Thank goodness there is even an internal network.

    2. No administrative rights on the working computer. Perhaps this rule is reasonable for office plankton, but it's hard for me to imagine a programmer who would like it.

    3. (irrelevant, just an illustration) You can’t even carry a camera phone (and where have you seen others now)?

    As a result, even youngsters write in Fortran, and there are only a few literally literate in programming. I know, because I pulled up on programming one guy, about 25 years old, who was recommended to me by my father as promising.
    My verdict: there is the 80s. Even though they pay pretty well there, I won’t go there for any haircuts.

    These are two examples from the life of the intellectual elite. I don’t want to denigrate anyone - people do their job well and so, but sometimes depending on what kind of windmills my father sometimes fights, whom I recently (thank God!) Could still transplant into git, my heart contracts. No OOP in the project for a million lines of code, no static analysis.

    It’s just that people tend to be very conservative in areas that are not their main ridge.


    (Ilya Maysus.Original comment .)

    The most important thing here is that the computer is just a Big Calculator. And if so, then you can know about him no more than his youngest relative deserves - “pocket calculator”. Yes, that's exactly what they use it for. In different areas. Let's digress for a second and look into the world of physics. Let's see how the next theory finds confirmation. To do this, I will again have to quote a large quote. The source is Brian Green's book “The Elegant Universe (superstrings, hidden dimensions and searches for the final theory)” [1]:

    We all crowded around Morrison's computer in our office. Aspinwall explained to Morrison how to run the program and what exact form the data entered into it should have. Morrison brought the results obtained at night to the desired form, and now everything was ready.

    Roughly speaking, the calculation that had to be done was reduced to determining the mass of a particular particle, which is the vibrational mode of the string during its movement in the universe, the Calabi component of which we studied all fall. We hoped that, in accordance with our chosen strategy, the mass would turn out to be exactly the same as the mass in the case of the CalabiYau manifold that arose after flop-reconstruction with a gap in space. The last mass was easy to calculate, and we had done this a few weeks earlier. The answer turned out to be 3 in a certain system of units, which we used. And since a numerical calculation was carried out on a computer, the expected result should have been close to the number 3, something like 3,000001 or 2,999999; the difference from the exact answer would be due to rounding errors.

    Morrison sat at the computer. His finger hovered over the Enter key. The tension grew. Morrison exhaled "let's go" and run the program. After a couple of seconds, the computer issued an answer: 8.999999. My heart sank. Is it really true that flop reconstructions with a gap in space break mirror symmetry, which means they hardly exist in reality? But the next moment we realized that there was some kind of stupid mistake. If there really is a difference in the masses of particles on the two manifolds, it is almost unbelievable that the computer would produce a result so close to an integer. If our ideas are wrong, then with the same success, the computer could give out an answer consisting of completely random numbers. We got the wrong answer, but it was wrong of the kind from which the conclusion was drawn that somewhere we made a banal mistake.

    Of course, the coincidence of the result after the error is found is only half convincing. If the desired result is known, it is very easy to find a way to get it. We urgently needed another example. Having all the necessary programs, it was not difficult to come up with it. We calculated the mass of another particle on the upper Calabi Yau manifold, this time with particular care, to avoid another mistake. The answer was 12. We surrounded the computer again and started the program. After a few seconds, an answer of 11.999999 was received. Consent. We have proved that the proposed mirror space is a mirror space, and flops with space gaps are part of string theory.

    I jumped out of the chair and, intoxicated with victory, made a circle around the room. Morrison, beaming, was sitting at a computer. And only Aspinwall's reaction was non-standard. “Great. I had no doubt that everything would be so, ”Aspinwall calmly said. “Where is my beer?”

    I believe they are geniuses. But imagine that this approach calculated the value of the integral by ordinary students. I do not think that then programmers would consider such an approach serious. And if the program immediately issued 3? What then? A mistake in the program would be considered proof? I think that later an error would come up when they were double-checked by themselves or other scientists. But still, the "ideal spherical programmer in a vacuum" is scared from this approach.

    Here is such a reality. This is how not only personal computers are used, but also cluster systems in scientific computing. And most importantly, people trust the results of the programs. And the further, the more such calculations will be. And the greater will be the danger of errors in their code.

    Maybe it's time to change something?

    I have the right to stick a patch on my own. I can recommend that, in my opinion, it is worth a drink with a cold. But not more. I can’t drill a tooth or write a prescription.

    Perhaps when the responsibility of the created software system goes beyond a certain framework, should its developers also confirm their qualifications?

    I know about various certifications. But I'm talking about something else. Certification is aimed at ensuring that the code of the programs complies with certain standards. Indirectly, this partially protects against trash. However, the list of areas where certification is required is rather narrow. It clearly does not cover the entire spectrum where inaccurate handling of the Large Calculator can do much harm.

    Danger example


    I think for many my experiences seem too abstract. Therefore, let's look at something from practice. There is an open package Trans-Proteomic Pipeline (TPP), for solving problems in the field of biology. It is clearly used. It is used by those who develop and possibly third-party organizations. It seems to me that the presence of any error in it is already a potential problem. Are there any mistakes in it? Yes there is. And all new ones appear. A year ago, we checked this project and wrote the note " Verification of the Trans-Proteomic Pipeline (TPP) project ."

    Has anything changed since then? Nothing changed. The project continues to evolve and grow into new bugs. Big Calculator won. Developers are not busy writing a high-quality project with as few errors as possible. They just solve problems. If it were different, they would have somehow reacted to the previous article and thought about introducing some kind of static analysis tools. I do not mean that they were required to choose PVS-Studio. There are many other static code analyzers. The important thing is that typical errors continue to appear in the responsible application. Let's see what's new.

    1. Some unluckiness continues to write incorrect cycles


    In the previous article, I already wrote about incorrect conditions in cycles. There are such errors and the new version of the package.
    double SpectraSTPeakList::calcDot(SpectraSTPeakList* other) {
      ....
      for (i = this->m_bins->begin(), j = other->m_bins->begin(); 
           i != this->m_bins->end(), j != other->m_bins->end();
           i++, j++) {
        d = (*i) * (*j);
        dot += d; 
      }
      ....
    }

    PVS-Studio diagnostic message: V521 Such expressions using the ',' operator are dangerous. Make sure the expression is correct. spectrastpeaklist.cpp 504

    In the test "i! = this-> m_bins-> end (), j! = other-> m_bins-> end ()", the expression before the decimal point does not check anything. The comma operator ',' is used to execute expressions on both sides of it in the order from left to right and returns the value of the right expression . A valid check should look like this:
    i != this->m_bins->end() && j != other->m_bins->end()

    Similar bloopers can be seen here:
    • spectrastpeaklist.cpp 516
    • spectrastpeaklist.cpp 529
    • spectrastpeaklist.cpp 592
    • spectrastpeaklist.cpp 608
    • spectrastpeaklist.cpp 625
    • spectrastpeaklist.cpp 696

    2. Dereferencing a null pointer


    Such an error will not lead to incorrect calculation results. There will be a program crash, which is much better. However, not writing about these errors will also be strange.
    voidASAPRatio_getDataStrctRatio(dataStrct *data, ....){
      ....
      int *outliers, *pepIndx=NULL;
      ....
      //pepIndx не изменяется
      ....
      if(data->dataCnts[i] == 1 && pepIndx[i] == 0)  
         data->dataCnts[i] = 0;
      ....
    }

    PVS-Studio diagnostic message: V522 Dereferencing of the null pointer 'pepIndx' might take place. asapcgidisplay2main.cxx 534

    The null pointer is also dereferenced here:
    • Pointer 'peptides'. asapcgidisplay2main.cxx 556
    • Pointer 'peptides'. asapcgidisplay2main.cxx 557
    • Pointer 'peptides'. asapcgidisplay2main.cxx 558
    • Pointer 'peptides'. asapcgidisplay2main.cxx 559
    • Pointer 'peptides'. asapcgidisplay2main.cxx 560
    • Pointer 'pepIndx'. asapcgidisplay2main.cxx 569

    3. Uncleaned arrays


    staticvoidclearTagNames(){
       std::vector<constchar *>ptrs;
       for (tagname_set::iterator i = tagnames.begin();
            i!=tagnames.end();i++) {
          ptrs.push_back(*i);
       }
       for (tagname_set::iterator j = attrnames.begin();
            j!=attrnames.end();j++) {
          ptrs.push_back(*j);
       }
       tagnames.empty();
       attrnames.empty();
       for (size_t n=ptrs.size();n--;) {
          delete [] (char *)(ptrs[n]); // cast away const
       }
    }

    The analyzer noticed two uncleaned arrays here right away:

    V530 The return value of function 'empty' is required to be utilized. tag.cxx 72

    V530 The return value of function 'empty' is required to be utilized. tag.cxx 73

    Instead of the empty () function, you must call the clear () function.

    4. Uninitialized class objects


    classExperimentCycleRecord {public:
      ExperimentCycleRecord() {
        ExperimentCycleRecord(0,0,0,True,False);
      }
      ExperimentCycleRecord(long lExperiment, long lCycleStart,
                            long lCycleEnd, Boolean bSingleCycle,
                            Boolean bRangleCycle)
      {
        ....
      }
      ....
    }

    PVS-Studio diagnostic message: V603 The object was created but it is not being used. If you wish to call constructor, 'this-> ExperimentCycleRecord :: ExperimentCycleRecord (....)' should be used. mascotconverter.cxx 101

    The constructor ExperimentCycleRecord () does not fulfill its purpose. It does not initialize anything. A developer may be a good chemist, but if he does not know how to work with the C ++ language, then it is worthless for calculations that use uninitialized memory. It's like taking a dirty test tube.

    The line “ExperimentCycleRecord (0,0,0, True, False);” the place where another constructor is called, creates a temporary object that will be destroyed. I examined this error pattern in more detail in the article “ Without Knowing the Ford, Do Not Go Into Water - Part One ”.

    Similar incorrect constructors can be found here:
    • asapratiopeptideparser.cxx 57
    • asapratiopeptidecgidisplayparser.cxx 36
    • cruxdiscrimfunction.cxx 36
    • discrimvalmixturedistr.cxx 34
    • mascotdiscrimfunction.cxx 47
    • mascotscoreparser.cxx 37
    • tandemdiscrimfunction.cxx 35
    • tandemkscoredf.cxx 37
    • tandemnativedf.cxx 37

    5. Comments that violated the logic


    intmain(int argc, char** argv){
      ....
      if (getIsInteractiveMode())  
        //p->writePepSHTML();//p->printResult();// regression test?if (testType!=NO_TEST) {
         TagListComparator("InterProphetParser",testType,
           outfilename,testFileName);
      ....
    }

    PVS-Studio diagnostic message: V628 It's possible that the line was commented out improperly, thus altering the program's operation logics. interprophetmain.cxx 175

    After the 'if' statement, the lines executing the actions were commented out. As a result, the program logic did not change as the programmer planned. He wanted nothing to happen when the condition was met. Instead, the if statement has an effect on the code below. The result - running tests now depends not only on the condition "testType! = NO_TEST", but also on the condition "getIsInteractiveMode ()". A test may not test anything. I highly recommend not relying entirely on one testing methodology (e.g. TDD).

    6. Typos


    Typos are everywhere and always. It’s not scary if, due to such an error in the game, you will have fewer lives after the explosion than planned. And what do the incorrect data mean in chemical calculations?
    voidASAPRatio_getProDataStrct(proDataStrct *data, char **pepBofFiles){
      ....
      if (data->indx == -1) {
        data->ratio[0] = -2.;
        data->ratio[0] = 0.;
        data->inv_ratio[0] = -2.;
        data->inv_ratio[1] = 0.;
        return;
      }
      ....
    }

    PVS-Studio diagnostic message: V519 The 'data-> ratio [0]' variable is assigned values ​​twice successively. Perhaps this is a mistake. Check lines: 130, 131. asapcgidisplay2main.cxx 131

    Randomly two times wrote values ​​to the same variable. It should have been:
    data->ratio[0] = -2.;
    data->ratio[1] = 0.;

    And then, we also copied this fragment to other places in the program:
    • asapcgidisplay2main.cxx 338
    • asapcgidisplay2main.cxx 465
    • asapratioproteincgidisplayparser.cxx 393
    • asapratioproteincgidisplayparser.cxx 518

    7. Comparison of signed and unsigned numbers.


    You must be able to compare signed and unsigned numbers. There are no unsigned numbers in ordinary calculators. But in C ++ there is.
    size_type size()const;
    voidcomputeDegenWts(){
      ....
      int have_cluster = 0;
      ....
      if ( have_cluster > 0 && ppw_ref.size() - have_cluster > 0 )
      ....
    }

    PVS-Studio diagnostic message: V555 The expression 'ppw_ref.size () - have_cluster> 0' will work as 'ppw_ref.size ()! = Have_cluster'. proteinprophet.cpp 6767

    I wanted to run the check “ppw_ref.size ()> have_cluster”. But it turned out quite different.

    For simplicity, let us have the type 'size_t' be 32-bit. Suppose the function “ppw_ref.size ()” returns 10 and the variable have_cluster is 15. The function ppw_ref.size () returns the unsigned type 'size_t'. According to the rules of C ++, before subtraction, the right operator in the minus operation will also become of type 'size_t'. So far so good. On the left we have 10u, on the right 15u.

    Subtract:

    10u - 15u

    And here the trouble is. All the same C ++ rules say that the result of subtracting two variables of an unsigned type,

    This means that 10u - 15u = FFFFFFFBu. And, as you know, 4294967291 is greater than 0.

    The riot of the Big Calculator succeeds. It is not enough to write the correct theoretical algorithm. You must also write the correct code.

    A similar error is here:
    double SpectraSTPeakList::calcXCorr() {
      ....
      for (int tau = -75; tau <= 75; tau++) {
        float dot = 0.0;
        for (unsignedint b = 0; b < numBins; b++) {
          if (b + tau >= 0 && b + tau < (int)numBins) {
            dot += (*m_bins)[b] * theoBins[b + tau] / 10000.0;
          }
        }
        ....
      ....
    }

    PVS-Studio diagnostic message: V547 Expression 'b + tau> = 0' is always true. Unsigned type value is always> = 0. spectrastpeaklist.cpp 2058

    As you can see from the code, the 'tau' variable takes values ​​in the range [-75, 75]. In order not to go beyond the bounds of the array, there is a check: b + tau> = 0. I think you already realized that this check does not work. The variable 'b' is of type 'unsigned'. This means that the expression "b + tau" is of type unsigned. A value of type unsigned is always greater than or equal to 0.

    8. Strange cycle


    constchar* ResidueMass::getStdModResidues(....) {
      ....
      for (rmap::const_iterator i = p.first; i != p.second; ++i) {
        const cResidue &r = (*i).second;
        if (r.m_masses[0].m_nterm) {
            n_term_aa_mod = true;
        } elseif (r.m_masses[0].m_cterm) {
            c_term_aa_mod = true;
        }
        return r.m_residue.c_str();
      }
      if(! strcmp(mod, "+N-formyl-met (Protein)")) {
        return"n";
      } if (! strcmp(mod, "13C6-15N2 (K)")) {
        return"K";
      } if (! strcmp(mod, "13C6-15N4 (R)")) {
        return"R";
      ....  
    }

    Warning issued by PVS-Studio: V612 An unconditional 'return' within a loop. residuemass.cxx 1442

    Inside the loop there is a 'return' statement, which is invoked anyway. A loop can only perform one iteration, after which the function will end. I think here is either a typo or there is not enough condition before the 'return' operator.

    9. Rough computing


    double RTCalculator::getUsedForGradientRate() {
      if (rts_.size() > 0)
        return used_count_ / rts_.size();
      return0.;
    }

    Warning issued by PVS-Studio: V636 The 'used_count_ / rts_.size ()' expression was implicitly casted from 'int' type to 'double' type. Consider utilizing an explicit type cast to avoid the loss of a fractional part. An example: double A = (double) (X) / Y ;. rtcalculator.cxx 6406

    Since the function returns double values, it is reasonable to assume the following.

    If the variable 'used_count_' is 5, and the rts_.size () function returns 7, then the result should be approximately 0.714. The only function getUsedForGradientRate () in this case will return 0. The

    variable 'used_count_' is of type int. The rts_.size () function also returns a value of type 'int'. Integer division occurs. The result is obvious. It is zero. Then zero is implicitly cast to double.

    To fix the situation, you can write like this:
    returnstatic_cast<double>(used_count_) / rts_.size();

    Similar flaws:
    • cgi_pep3d_xml.cxx 3203
    • cgi_pep3d_xml.cxx 3204
    • asapratiopeptideparser.cxx 4108

    10. The Great and Mighty Copy-Paste


    The setPepMaxProb () function contains several large blocks of the same type. It immediately feels that Copy-Paste methodology was not without it. And as a result, the code contains an error. I had to VERY drastically reduce the sample code. In a shortened version, the error is easily visible. In the program code, to notice it is almost not realistic. Yes, this is an advertisement for static analysis tools in general, and PVS-Studio in particular.
    voidsetPepMaxProb( bool use_nsp, bool use_fpkm, 
      bool use_joint_probs, bool compute_spectrum_cnts ){  
      double prob = 0.0;
      double max2 = 0.0;
      double max3 = 0.0;
      double max4 = 0.0;
      double max5 = 0.0;
      double max6 = 0.0;
      double max7 = 0.0;
      ....
      if ( pep3 ) { ... if ( use_joint_probs && prob > max3 ) ... }
      ....
      if ( pep4 ) { ... if ( use_joint_probs && prob > max4 ) ... }
      ....
      if ( pep5 ) { ... if ( use_joint_probs && prob > max5 ) ... }
      ....
      if ( pep6 ) { ... if ( use_joint_probs && prob > max6 ) ... }
      ....
      if ( pep7 ) { ... if ( use_joint_probs && prob > max6 ) ... }
      ....
    }

    V525 The code containing the collection of similar blocks. Check items 'max3', 'max4', 'max5', 'max6', 'max6' in lines 4664, 4690, 4716, 4743, 4770. proteinprophet.cpp 4664

    Warning issued by PVS-Studio: V525 The code containing the collection of similar blocks. Check items 'max3', 'max4', 'max5', 'max6', 'max6' in lines 4664, 4690, 4716, 4743, 4770. proteinprophet.cpp 4664

    Unfortunately, the V525 diagnostic gives a lot of false positives and is referred to the third level warnings. But if you are not too lazy to study them, you can find such wonderful bugs.

    11. Pointer is not always initialized


    intmain(int argc, char** argv){
      ....
      ramp_fileoffset_t *pScanIndex;
      ....
      if ( (pFI=rampOpenFile(mzXmlPath_.c_str()))==NULL) {
        ....
      } else {
        ....
        pScanIndex = readIndex(pFI, indexOffset, &iAnalysisLastScan);
        ....
      }
      ....
      if (pScanIndex != NULL)
        free(pScanIndex);
      return0;
    }

    Warning issued by PVS-Studio: V614 Potentially uninitialized pointer 'pScanIndex' used. sqt2xml.cxx 476

    This program may crash at the end if the rampOpenFile () function returns NULL. Not critical, but unpleasant.

    Another variable that may not be initialized is here:
    • Potentially uninitialized pointer 'fp_' used. dta-xml.cpp 307

    12. No virtual destructor


    classDiscriminantFunction {public:
      DiscriminantFunction(int charge);
      virtual Boolean isComputable(SearchResult* result)= 0;
      virtualdoublegetDiscriminantScore(SearchResult* result)= 0;
      virtualvoiderror(int charge);
    protected:
      int charge_;
      double const_;
    }; // classclassCometDiscrimFunction :public DiscriminantFunction;
    classCruxDiscrimFunction :public DiscriminantFunction;
    classInspectDiscrimFunction :public DiscriminantFunction;
    .....
    classDiscrimValMixtureDistr :public MixtureDistr {
      ....
      DiscriminantFunction* discrim_func_;
      ....
    };
    DiscrimValMixtureDistr::~DiscrimValMixtureDistr() {
      delete[] posinit_;
      delete[] neginit_;
      delete discrim_func_;
    }

    Warning issued by PVS-Studio: V599 The virtual destructor is not present, although the 'DiscriminantFunction' class contains virtual functions. discrimvalmixturedistr.cxx 206

    Many classes are inherited from the DiscriminantFunction class. For example, the class DiscrimValMixtureDistr is the descendant. The destructor of this class frees memory, and therefore it is very desirable to call it. Unfortunately, the destructor in the DiscriminantFunction class is not declared virtual, with all the ensuing consequences.

    13. Miscellaneous


    You can find a lot of flaws that will not lead to serious consequences, but their presence in the code is unpleasant. There are simply suspicious, but not necessarily wrong places. Here is one of them:
    Boolean MixtureModel::iterate(int counter) {
      ....
      if (done_[charge] < 0) {
        done_[charge];
      }
      elseif (priors_[charge] > 0.0) {
        done_[charge] += extraitrs_;
      }
      ....
    }

    Warning issued by PVS-Studio: V607 Ownerless expression 'done_ [charge]'. mixturemodel.cxx 1558

    What is this? Incomplete code? Or would you like to emphasize that you do not need to do anything if the condition "done_ [charge] <0" is fulfilled?

    And here is the wrong memory release. With a high probability there will be no terrible consequences, but this code is with a smell.
    string Field::getText(....)
    {
      ....
      char* pepString = newchar[peplen + 1];
      ....
      delete pepString;
      ....
    }

    Warning issued by PVS-Studio: V611 The memory was allocated using 'new T []' operator but was released using the 'delete' operator. Consider inspecting this code. It's probably better to use 'delete [] pepString;'. pepxfield.cxx 1023 The word

    “delete [] pepString” should be written here. Such a place is far from one:
    • cruxdiscrimvalmixturedistr.cxx 705
    • cruxdiscrimvalmixturedistr.cxx 715
    • mascotdiscrimvalmixturedistr.cxx 426
    • mascotdiscrimvalmixturedistr.cxx 550
    • mascotdiscrimvalmixturedistr.cxx 624
    • phenyxdiscrimvalmixturedistr.cxx 692
    • probiddiscrimvalmixturedistr.cxx 487
    • probiddiscrimvalmixturedistr.cxx 659
    • tandemdiscrimvalmixturedistr.cxx 731
    • tandemdiscrimvalmixturedistr.cxx 741


    And here is the implementation of the "-" operator. Apparently it is not used anywhere. Otherwise, the error would quickly come to light.
    CharIndexedVectorIterator operator++(int)
    {  // postincrement
      CharIndexedVectorIterator _Tmp = *this;
      ++m_itr;
      return (_Tmp);
    }
    CharIndexedVectorIterator& operator--()
    {  // predecrement
      ++m_itr;
      return (*this);
    }

    Warning issued by PVS-Studio: V524 It is odd that the body of '-' function is fully equivalent to the body of '++' function. charindexedvector.hpp 81

    The "-" and "++" operators are implemented identically. And then, probably, they copied:
    • charindexedvector.hpp 87
    • charindexedvector.hpp 159
    • charindexedvector.hpp 165
    I will not continue further. This is not so interesting, and the article dragged on. As always, I ask developers not to dwell on editing these shortcomings. Download and test the project yourself using PVS-Studio. I could have missed many mistakes. We are ready to allocate a free key for a while.

    I summarize


    Unfortunately, the article turned out to be confusing. So what did the author want to say? I’ll try to repeat very briefly what thoughts I wanted to convey.
    1. We increasingly use and trust programs that perform calculations and modeling processes.
    2. Programs are very complicated. It is obvious to professional programmers that one cannot create a numerical simulation package in the same way as using a programmable calculator. An increase in complexity leads to an exponential increase in the number of errors [ 2 ].
    3. It turns out that physicists / biologists / physicians can no longer simply count something. One cannot ignore the increase in the complexity of programs and the consequences of incorrect calculations due to incomplete knowledge of the programming language.
    4. In the article, I argued that this is the case. The first quote is that people use a computer as a calculator. The second quote is yes, just like a calculator. Examples of mistakes are yes, and indeed they make mistakes. My fears are justified.


    And what is proposed to do?

    To start, I want people to become aware of this problem. And they told friends from related areas about her. It has long been obvious to programmers that the growth of complexity and stupid mistakes in large projects easily lead to trouble. People who use programming simply as a tool do not know about it and do not think about it. And they should be prompted to pay attention to this.

    Analogy. People took a club in their hand and began to hunt for the beast. While they are doing this, weapons are rapidly improving. The club in their hands turns into a stone hammer, then into a sword, then into a gun. And they still try to just jam the hares on her head. Not only is this ineffective, it has also become much more dangerous (you can shoot at yourself or at a colleague). Hunters from the tribe of "programmers" quickly adapt. And the others have no time. They are busy hunting hares. After all, the meaning is in the hare. These people need to be told whether they want it or not, they need to learn. So only everyone will be better. There is nothing to wave a gun.

    Sitelinks


    1. Brian Green “The Elegant Universe (superstrings, hidden dimensions and the search for the final theory. ISBN 978-5-453-00011-1 (URSS), ISBN 978-5-397-01575-2 (Book House“ Librocom ”)
    2. Andrey Karpov. Sensations confirmed by numbers. http://www.viva64.com/en/b/0158/

    Also popular now: