LCOV - code coverage report
Current view: top level - lib - mathlib.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 181 194 93.3 %
Date: 2013-03-30 Functions: 24 28 85.7 %
Branches: 287 373 76.9 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Cppcheck - A tool for static C/C++ code analysis
       3                 :            :  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
       4                 :            :  *
       5                 :            :  * This program is free software: you can redistribute it and/or modify
       6                 :            :  * it under the terms of the GNU General Public License as published by
       7                 :            :  * the Free Software Foundation, either version 3 of the License, or
       8                 :            :  * (at your option) any later version.
       9                 :            :  *
      10                 :            :  * This program is distributed in the hope that it will be useful,
      11                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13                 :            :  * GNU General Public License for more details.
      14                 :            :  *
      15                 :            :  * You should have received a copy of the GNU General Public License
      16                 :            :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17                 :            :  */
      18                 :            : 
      19                 :            : 
      20                 :            : 
      21                 :            : #include "mathlib.h"
      22                 :            : #include "errorlogger.h"
      23                 :            : 
      24                 :            : #include <string>
      25                 :            : #include <sstream>
      26                 :            : #include <cstdlib>
      27                 :            : #include <cmath>
      28                 :            : #include <cctype>
      29                 :            : 
      30                 :     485785 : MathLib::bigint MathLib::toLongNumber(const std::string &str)
      31                 :            : {
      32                 :            :     // hexadecimal numbers:
      33         [ +  + ]:     485785 :     if (isHex(str)) {
      34         [ +  + ]:       3296 :         if (str[0] == '-') {
      35                 :         90 :             bigint ret = 0;
      36                 :         90 :             std::istringstream istr(str);
      37 [ +  - ][ +  - ]:         90 :             istr >> std::hex >> ret;
      38                 :         90 :             return ret;
      39                 :            :         } else {
      40                 :       3206 :             unsigned long long ret = 0;
      41                 :       3206 :             std::istringstream istr(str);
      42 [ +  - ][ +  - ]:       3206 :             istr >> std::hex >> ret;
      43                 :       3206 :             return (bigint)ret;
      44                 :            :         }
      45                 :            :     }
      46                 :            : 
      47                 :            :     // octal numbers:
      48         [ +  + ]:     482489 :     if (isOct(str)) {
      49                 :     158558 :         bigint ret = 0;
      50                 :     158558 :         std::istringstream istr(str);
      51 [ +  - ][ +  - ]:     158558 :         istr >> std::oct >> ret;
      52                 :     158558 :         return ret;
      53                 :            :     }
      54                 :            : 
      55                 :            :     // binary numbers:
      56         [ +  + ]:     323931 :     if (isBin(str)) {
      57                 :        315 :         bigint ret = 0;
      58 [ +  + ][ +  + ]:       1575 :         for (std::string::size_type i = str[0] == '0'?2:3; i < str.length(); i++) {
      59                 :       1260 :             ret <<= 1;
      60         [ +  + ]:       1260 :             if (str[i] == '1')
      61                 :        945 :                 ret |= 1;
      62                 :            :         }
      63         [ +  + ]:        315 :         if (str[0] == '-')
      64                 :         90 :             ret = -ret;
      65                 :        315 :         return ret;
      66                 :            :     }
      67                 :            : 
      68         [ +  + ]:     323616 :     if (str.find_first_of("eE") != std::string::npos)
      69                 :        451 :         return static_cast<bigint>(std::atof(str.c_str()));
      70                 :            : 
      71                 :     323165 :     bigint ret = 0;
      72                 :     323165 :     std::istringstream istr(str);
      73         [ +  - ]:     323165 :     istr >> ret;
      74                 :     485785 :     return ret;
      75                 :            : }
      76                 :            : 
      77                 :     158707 : std::string MathLib::longToString(const bigint value)
      78                 :            : {
      79                 :     158707 :     std::ostringstream result;
      80         [ +  - ]:     158707 :     result << value;
      81         [ +  - ]:     158707 :     return result.str();
      82                 :            : }
      83                 :            : 
      84                 :      16611 : double MathLib::toDoubleNumber(const std::string &str)
      85                 :            : {
      86         [ +  + ]:      16611 :     if (isHex(str))
      87                 :         90 :         return static_cast<double>(toLongNumber(str));
      88                 :            :     // nullcheck
      89         [ +  + ]:      16521 :     else if (isNullValue(str))
      90                 :       1622 :         return 0.0;
      91                 :            :     // otherwise, convert to double
      92                 :      14899 :     std::istringstream istr(str);
      93                 :            :     double ret;
      94         [ +  - ]:      14899 :     istr >> ret;
      95                 :      16611 :     return ret;
      96                 :            : }
      97                 :            : 
      98                 :       4006 : std::string MathLib::doubleToString(const double value)
      99                 :            : {
     100                 :       4006 :     std::ostringstream result;
     101                 :       4006 :     result.precision(12);
     102         [ +  - ]:       4006 :     result << value;
     103 [ +  - ][ +  - ]:       4006 :     if (result.str() == "-0")
         [ +  - ][ -  + ]
     104         [ #  # ]:          0 :         return "0.0";
     105 [ +  - ][ +  - ]:       4006 :     if (result.str().find(".") == std::string::npos)
         [ +  - ][ +  + ]
     106 [ +  - ][ +  - ]:       2790 :         return result.str() + ".0";
                 [ +  - ]
     107         [ +  - ]:       4006 :     return result.str();
     108                 :            : }
     109                 :            : 
     110                 :     310492 : bool MathLib::isFloat(const std::string &s)
     111                 :            : {
     112                 :            :     // every number that contains a . is a float
     113         [ +  + ]:     310492 :     if (s.find("." , 0) != std::string::npos)
     114                 :       1216 :         return true;
     115                 :            :     // scientific notation
     116                 :     309276 :     return(s.find("E-", 0) != std::string::npos
     117 [ +  + ][ -  + ]:     310492 :            || s.find("e-", 0) != std::string::npos);
     118                 :            : }
     119                 :            : 
     120                 :       2250 : bool MathLib::isNegative(const std::string &s)
     121                 :            : {
     122                 :            :     // remember position
     123                 :       2250 :     std::string::size_type n = 0;
     124                 :            :     // eat up whitespace
     125         [ -  + ]:       2250 :     while (std::isspace(s[n])) ++n;
     126                 :            :     // every negative number has a negative sign
     127                 :       2250 :     return(s[n] == '-');
     128                 :            : }
     129                 :            : 
     130                 :    6620951 : bool MathLib::isOct(const std::string& str)
     131                 :            : {
     132 [ +  + ][ +  + ]:    6620951 :     bool sign = str[0]=='-' || str[0]=='+';
     133 [ +  + ][ +  + ]:    6620951 :     return(str[sign?1:0] == '0' && (str.size() == 1 || isOctalDigit(str[sign?2:1])) && !isFloat(str));
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
     134                 :            : }
     135                 :            : 
     136                 :    6644473 : bool MathLib::isHex(const std::string& str)
     137                 :            : {
     138 [ +  + ][ +  + ]:    6644473 :     bool sign = str[0]=='-' || str[0]=='+';
     139 [ +  + ][ +  + ]:    6644473 :     return(str.compare(sign?1:0, 2, "0x") == 0 || str.compare(sign?1:0, 2, "0X") == 0);
         [ +  + ][ +  + ]
     140                 :            : }
     141                 :            : 
     142                 :    6123698 : bool MathLib::isBin(const std::string& str)
     143                 :            : {
     144 [ +  + ][ +  + ]:    6123698 :     bool sign = str[0]=='-' || str[0]=='+';
     145 [ +  + ][ +  + ]:    6123698 :     return((str.compare(sign?1:0, 2, "0b") == 0 || str.compare(sign?1:0, 2, "0B") == 0) && str.find_first_not_of("10bB", 1) == std::string::npos);
         [ +  + ][ +  + ]
                 [ +  - ]
     146                 :            : }
     147                 :            : 
     148                 :     272426 : bool MathLib::isInt(const std::string & s)
     149                 :            : {
     150                 :            :     // perform prechecks:
     151                 :            :     // ------------------
     152                 :            :     // first check, if a point is found, it is an floating point value
     153         [ +  + ]:     272426 :     if (s.find(".", 0) != std::string::npos) return false;
     154                 :            :     // check for scientific notation e.g. NumberE-Number this is obvious an floating point value
     155 [ +  + ][ +  + ]:     265633 :     else if (s.find("E-", 0) != std::string::npos || s.find("e-", 0) != std::string::npos) return false;
                 [ +  + ]
     156                 :            : 
     157                 :            : 
     158                 :            :     // prechecking has nothing found,...
     159                 :            :     // gather information
     160                 :            :     enum Representation {
     161                 :            :         eScientific = 0, // NumberE+Number or NumberENumber
     162                 :            :         eOctal,          // starts with 0
     163                 :            :         eHex,            // starts with 0x
     164                 :            :         eDefault         // Numbers with a (possible) trailing u or U or l or L for unsigned or long datatypes
     165                 :            :     };
     166                 :            :     // create an instance
     167                 :     265407 :     Representation Mode = eDefault;
     168                 :            : 
     169                 :            : 
     170                 :            :     // remember position
     171                 :     265407 :     unsigned long n = 0;
     172                 :            :     // eat up whitespace
     173         [ -  + ]:     265407 :     while (std::isspace(s[n])) ++n;
     174                 :            : 
     175                 :            :     // determine type
     176         [ +  + ]:     265407 :     if (s.find("E", 0) != std::string::npos) {
     177                 :        271 :         Mode = eScientific;
     178         [ +  + ]:     265136 :     } else if (isHex(s)) {
     179                 :        225 :         Mode = eHex;
     180         [ +  + ]:     264911 :     } else if (isOct(s)) {
     181                 :      76349 :         Mode = eOctal;
     182                 :            :     }
     183                 :            : 
     184                 :            :     // check sign
     185 [ +  + ][ +  + ]:     265407 :     if (s[n] == '-' || s[n] == '+') ++n;
                 [ +  + ]
     186                 :            : 
     187                 :            :     // check scientific notation
     188         [ +  + ]:     265407 :     if (Mode == eScientific) {
     189                 :            :         // check digits
     190         [ +  + ]:        542 :         while (std::isdigit(s[n])) ++n;
     191                 :            : 
     192                 :            :         // check scientific notation
     193         [ +  - ]:        271 :         if (std::tolower(s[n]) == 'e') {
     194                 :        271 :             ++n;
     195                 :            :             // check positive exponent
     196         [ +  + ]:        271 :             if (s[n] == '+') ++n;
     197                 :            :             // floating pointer number e.g. 124E-2
     198         [ -  + ]:        271 :             if (s[n] == '-') return false;
     199                 :            :             // check digits of the exponent
     200         [ +  + ]:        902 :             while (std::isdigit(s[n])) ++n;
     201                 :            :         }
     202                 :            :     }
     203                 :            :     // check hex notation
     204         [ +  + ]:     265136 :     else if (Mode == eHex) {
     205                 :        225 :         ++n; // 0
     206                 :        225 :         ++n; // x
     207         [ +  + ]:        585 :         while (std::isxdigit(s[n]))
     208                 :        360 :             ++n;
     209                 :            : 
     210 [ +  - ][ -  + ]:        225 :         while (std::tolower(s[n]) == 'u' || std::tolower(s[n]) == 'l') ++n; // unsigned or long (long)
                 [ -  + ]
     211                 :            :     }
     212                 :            :     // check octal notation
     213         [ +  + ]:     264911 :     else if (Mode == eOctal) {
     214                 :      76349 :         ++n; // 0
     215         [ +  + ]:      76529 :         while (isOctalDigit(s[n]))
     216                 :        180 :             ++n;
     217                 :            : 
     218 [ +  - ][ -  + ]:      76349 :         while (std::tolower(s[n]) == 'u' || std::tolower(s[n]) == 'l') ++n; // unsigned or long (long)
                 [ -  + ]
     219         [ +  - ]:     188562 :     } else if (Mode == eDefault) {
     220                 :            :         // starts with digit
     221                 :     188562 :         bool bStartsWithDigit=false;
     222         [ +  + ]:     472789 :         while (std::isdigit(s[n])) {
     223                 :     284227 :             bStartsWithDigit=true;
     224                 :     284227 :             ++n;
     225                 :            :         };
     226                 :            : 
     227 [ +  + ][ +  + ]:     190106 :         while (std::tolower(s[n]) == 'u' || std::tolower(s[n]) == 'l') ++n; // unsigned or long (long)
                 [ +  + ]
     228                 :            : 
     229         [ +  + ]:     188562 :         if (!bStartsWithDigit)
     230                 :        542 :             return false;
     231                 :            :     }
     232                 :            :     // eat up whitespace
     233         [ -  + ]:     264865 :     while (std::isspace(s[n]))
     234                 :          0 :         ++n;
     235                 :            : 
     236                 :            :     // if everything goes good, we are at the end of the string and no digits/character
     237                 :            :     // is here --> return true, but if something was found eg. 12E+12AA return false
     238                 :     272426 :     return(n >= s.length());
     239                 :            : }
     240                 :            : 
     241                 :       4101 : std::string MathLib::add(const std::string & first, const std::string & second)
     242                 :            : {
     243 [ +  + ][ +  + ]:       4101 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     244                 :       3921 :         return longToString(toLongNumber(first) + toLongNumber(second));
     245                 :            :     }
     246                 :            : 
     247                 :        180 :     double d1 = toDoubleNumber(first);
     248                 :        180 :     double d2 = toDoubleNumber(second);
     249                 :            : 
     250                 :        180 :     int count = 0;
     251 [ +  + ][ +  - ]:        360 :     while (d1 > 100000.0 * d2 && doubleToString(d1+d2)==first && ++count<5)
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
     252                 :        180 :         d2 *= 10.0;
     253 [ +  + ][ +  - ]:        180 :     while (d2 > 100000.0 * d1 && doubleToString(d1+d2)==second && ++count<5)
         [ +  - ][ -  + ]
         [ #  # ][ +  + ]
         [ -  + ][ #  # ]
     254                 :          0 :         d1 *= 10.0;
     255                 :            : 
     256                 :       4101 :     return doubleToString(d1 + d2);
     257                 :            : }
     258                 :            : 
     259                 :       2295 : std::string MathLib::subtract(const std::string &first, const std::string &second)
     260                 :            : {
     261 [ +  + ][ +  + ]:       2295 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     262                 :       2025 :         return longToString(toLongNumber(first) - toLongNumber(second));
     263                 :            :     }
     264                 :            : 
     265         [ +  + ]:        270 :     if (first == second)
     266         [ +  - ]:         45 :         return "0.0" ;
     267                 :            : 
     268                 :        225 :     double d1 = toDoubleNumber(first);
     269                 :        225 :     double d2 = toDoubleNumber(second);
     270                 :            : 
     271                 :        225 :     int count = 0;
     272 [ +  + ][ +  - ]:        405 :     while (d1 > 100000.0 * d2 && doubleToString(d1-d2)==first && ++count<5)
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
     273                 :        180 :         d2 *= 10.0;
     274 [ +  + ][ +  - ]:        225 :     while (d2 > 100000.0 * d1 && doubleToString(d1-d2)==second && ++count<5)
         [ +  - ][ -  + ]
         [ #  # ][ +  + ]
         [ -  + ][ #  # ]
     275                 :          0 :         d1 *= 10.0;
     276                 :            : 
     277                 :       2295 :     return doubleToString(d1 - d2);
     278                 :            : }
     279                 :            : 
     280                 :       1216 : std::string MathLib::divide(const std::string &first, const std::string &second)
     281                 :            : {
     282 [ +  + ][ +  + ]:       1216 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     283                 :        990 :         bigint b = toLongNumber(second);
     284         [ +  + ]:        990 :         if (b == 0)
     285 [ +  - ][ +  - ]:         45 :             throw InternalError(0, "Internal Error: Division by zero");
     286                 :        945 :         return longToString(toLongNumber(first) / b);
     287                 :            :     }
     288                 :       1171 :     return doubleToString(toDoubleNumber(first) / toDoubleNumber(second));
     289                 :            : }
     290                 :            : 
     291                 :       3422 : std::string MathLib::multiply(const std::string &first, const std::string &second)
     292                 :            : {
     293 [ +  + ][ +  - ]:       3422 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     294                 :       3152 :         return longToString(toLongNumber(first) * toLongNumber(second));
     295                 :            :     }
     296                 :       3422 :     return doubleToString(toDoubleNumber(first) * toDoubleNumber(second));
     297                 :            : }
     298                 :            : 
     299                 :        450 : std::string MathLib::mod(const std::string &first, const std::string &second)
     300                 :            : {
     301 [ +  + ][ +  + ]:        450 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     302                 :        225 :         bigint b = toLongNumber(second);
     303         [ +  + ]:        225 :         if (b == 0)
     304 [ +  - ][ +  - ]:         45 :             throw InternalError(0, "Internal Error: Division by zero");
     305                 :        180 :         return longToString(toLongNumber(first) % b);
     306                 :            :     }
     307                 :        405 :     return doubleToString(std::fmod(toDoubleNumber(first),toDoubleNumber(second)));
     308                 :            : }
     309                 :            : 
     310                 :       9144 : std::string MathLib::calculate(const std::string &first, const std::string &second, char action)
     311                 :            : {
     312   [ +  +  +  +  :       9144 :     switch (action) {
             +  +  +  -  
                      + ]
     313                 :            :     case '+':
     314                 :       3606 :         return MathLib::add(first, second);
     315                 :            : 
     316                 :            :     case '-':
     317                 :       1575 :         return MathLib::subtract(first, second);
     318                 :            : 
     319                 :            :     case '*':
     320                 :       2612 :         return MathLib::multiply(first, second);
     321                 :            : 
     322                 :            :     case '/':
     323                 :        676 :         return MathLib::divide(first, second);
     324                 :            : 
     325                 :            :     case '%':
     326                 :        450 :         return MathLib::mod(first, second);
     327                 :            : 
     328                 :            :     case '&':
     329                 :         90 :         return MathLib::longToString(MathLib::toLongNumber(first) & MathLib::toLongNumber(second));
     330                 :            : 
     331                 :            :     case '|':
     332                 :         90 :         return MathLib::longToString(MathLib::toLongNumber(first) | MathLib::toLongNumber(second));
     333                 :            : 
     334                 :            :     case '^':
     335                 :          0 :         return MathLib::longToString(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second));
     336                 :            : 
     337                 :            :     default:
     338 [ +  - ][ +  - ]:       9099 :         throw InternalError(0, std::string("Unexpected action '") + action + "' in MathLib::calculate(). Please report this to Cppcheck developers.");
         [ +  - ][ +  - ]
     339                 :            :     }
     340                 :            : }
     341                 :            : 
     342                 :          0 : std::string MathLib::sin(const std::string &tok)
     343                 :            : {
     344                 :          0 :     return doubleToString(std::sin(toDoubleNumber(tok)));
     345                 :            : }
     346                 :            : 
     347                 :            : 
     348                 :          0 : std::string MathLib::cos(const std::string &tok)
     349                 :            : {
     350                 :          0 :     return doubleToString(std::cos(toDoubleNumber(tok)));
     351                 :            : }
     352                 :            : 
     353                 :          0 : std::string MathLib::tan(const std::string &tok)
     354                 :            : {
     355                 :          0 :     return doubleToString(std::tan(toDoubleNumber(tok)));
     356                 :            : }
     357                 :            : 
     358                 :            : 
     359                 :          0 : std::string MathLib::abs(const std::string &tok)
     360                 :            : {
     361                 :          0 :     return doubleToString(std::abs(toDoubleNumber(tok)));
     362                 :            : }
     363                 :            : 
     364                 :       1080 : bool MathLib::isEqual(const std::string &first, const std::string &second)
     365                 :            : {
     366                 :            :     // this conversion is needed for formatting
     367                 :            :     // e.g. if first=0.1 and second=1.0E-1, the direct comparison of the strings whould fail
     368 [ +  - ][ +  - ]:       1080 :     return doubleToString(toDoubleNumber(first)) == doubleToString(toDoubleNumber(second));
         [ +  - ][ +  - ]
     369                 :            : }
     370                 :            : 
     371                 :        855 : bool MathLib::isNotEqual(const std::string &first, const std::string &second)
     372                 :            : {
     373                 :        855 :     return !isEqual(first, second);
     374                 :            : }
     375                 :            : 
     376                 :        315 : bool MathLib::isGreater(const std::string &first, const std::string &second)
     377                 :            : {
     378                 :        315 :     return toDoubleNumber(first) > toDoubleNumber(second);
     379                 :            : }
     380                 :            : 
     381                 :        765 : bool MathLib::isGreaterEqual(const std::string &first, const std::string &second)
     382                 :            : {
     383                 :        765 :     return toDoubleNumber(first) >= toDoubleNumber(second);
     384                 :            : }
     385                 :            : 
     386                 :        495 : bool MathLib::isLess(const std::string &first, const std::string &second)
     387                 :            : {
     388                 :        495 :     return toDoubleNumber(first) < toDoubleNumber(second);
     389                 :            : }
     390                 :            : 
     391                 :       1755 : bool MathLib::isLessEqual(const std::string &first, const std::string &second)
     392                 :            : {
     393                 :       1755 :     return toDoubleNumber(first) <= toDoubleNumber(second);
     394                 :            : }
     395                 :            : 
     396                 :      17241 : bool MathLib::isNullValue(const std::string &str)
     397                 :            : {
     398                 :      50461 :     return (str == "-0"        || str == "0"      || str == "+0"
     399                 :      47532 :             || str == "-0.0"   || str == "0.0"    || str == "+0.0"
     400                 :      31103 :             || str == "-0."    || str == "+0."
     401                 :      61846 :             || str == "-0E-00" || str == "-0E+00" || str == "+0E+00" || str == "+0E-00"
     402                 :      61576 :             || str == "-0e-00" || str == "-0e+00" || str == "+0e+00" || str == "+0e-00"
     403   [ +  +  +  +  :     252518 :             || str == "-0E-0");
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  -  +  
          +  +  -  +  +  
          +  -  +  -  +  
                -  +  - ]
                 [ -  + ]
     404                 :            : }
     405                 :            : 
     406                 :      80015 : bool MathLib::isOctalDigit(char c)
     407                 :            : {
     408 [ +  + ][ +  + ]:      80015 :     return(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7');
         [ +  + ][ +  + ]
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
     409                 :            : }

Generated by: LCOV version 1.9