LCOV - code coverage report
Current view: top level - lib - mathlib.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 184 197 93.4 %
Date: 2013-06-09 Functions: 24 28 85.7 %
Branches: 291 379 76.8 %

           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                 :            : #include <limits>
      30                 :            : 
      31                 :     468324 : MathLib::bigint MathLib::toLongNumber(const std::string &str)
      32                 :            : {
      33                 :            :     // hexadecimal numbers:
      34         [ +  + ]:     468324 :     if (isHex(str)) {
      35         [ +  + ]:       3343 :         if (str[0] == '-') {
      36                 :         90 :             bigint ret = 0;
      37                 :         90 :             std::istringstream istr(str);
      38 [ +  - ][ +  - ]:         90 :             istr >> std::hex >> ret;
      39                 :         90 :             return ret;
      40                 :            :         } else {
      41                 :       3253 :             unsigned long long ret = 0;
      42                 :       3253 :             std::istringstream istr(str);
      43 [ +  - ][ +  - ]:       3253 :             istr >> std::hex >> ret;
      44                 :       3253 :             return (bigint)ret;
      45                 :            :         }
      46                 :            :     }
      47                 :            : 
      48                 :            :     // octal numbers:
      49         [ +  + ]:     464981 :     if (isOct(str)) {
      50                 :     155879 :         bigint ret = 0;
      51                 :     155879 :         std::istringstream istr(str);
      52 [ +  - ][ +  - ]:     155879 :         istr >> std::oct >> ret;
      53                 :     155879 :         return ret;
      54                 :            :     }
      55                 :            : 
      56                 :            :     // binary numbers:
      57         [ +  + ]:     309102 :     if (isBin(str)) {
      58                 :        315 :         bigint ret = 0;
      59 [ +  + ][ +  + ]:       1575 :         for (std::string::size_type i = str[0] == '0'?2:3; i < str.length(); i++) {
      60                 :       1260 :             ret <<= 1;
      61         [ +  + ]:       1260 :             if (str[i] == '1')
      62                 :        945 :                 ret |= 1;
      63                 :            :         }
      64         [ +  + ]:        315 :         if (str[0] == '-')
      65                 :         90 :             ret = -ret;
      66                 :        315 :         return ret;
      67                 :            :     }
      68                 :            : 
      69         [ +  + ]:     308787 :     if (str.find_first_of("eE") != std::string::npos)
      70                 :        451 :         return static_cast<bigint>(std::atof(str.c_str()));
      71                 :            : 
      72                 :     308336 :     bigint ret = 0;
      73                 :     308336 :     std::istringstream istr(str);
      74         [ +  - ]:     308336 :     istr >> ret;
      75                 :     468324 :     return ret;
      76                 :            : }
      77                 :            : 
      78                 :     148851 : std::string MathLib::longToString(const bigint value)
      79                 :            : {
      80                 :     148851 :     std::ostringstream result;
      81         [ +  - ]:     148851 :     result << value;
      82         [ +  - ]:     148851 :     return result.str();
      83                 :            : }
      84                 :            : 
      85                 :      16161 : double MathLib::toDoubleNumber(const std::string &str)
      86                 :            : {
      87         [ +  + ]:      16161 :     if (isHex(str))
      88                 :         90 :         return static_cast<double>(toLongNumber(str));
      89                 :            :     // nullcheck
      90         [ +  + ]:      16071 :     else if (isNullValue(str))
      91                 :       1622 :         return 0.0;
      92                 :            :     // otherwise, convert to double
      93                 :      14449 :     std::istringstream istr(str);
      94                 :            :     double ret;
      95         [ +  - ]:      14449 :     istr >> ret;
      96                 :      16161 :     return ret;
      97                 :            : }
      98                 :            : 
      99                 :       4006 : std::string MathLib::doubleToString(const double value)
     100                 :            : {
     101                 :       4006 :     std::ostringstream result;
     102                 :       4006 :     result.precision(12);
     103         [ +  - ]:       4006 :     result << value;
     104 [ +  - ][ +  - ]:       4006 :     if (result.str() == "-0")
         [ +  - ][ -  + ]
     105         [ #  # ]:          0 :         return "0.0";
     106 [ +  - ][ +  - ]:       4006 :     if (result.str().find(".") == std::string::npos)
         [ +  - ][ +  + ]
     107 [ +  - ][ +  - ]:       2790 :         return result.str() + ".0";
                 [ +  - ]
     108         [ +  - ]:       4006 :     return result.str();
     109                 :            : }
     110                 :            : 
     111                 :     304728 : bool MathLib::isFloat(const std::string &s)
     112                 :            : {
     113                 :            :     // every number that contains a . is a float
     114         [ +  + ]:     304728 :     if (s.find("." , 0) != std::string::npos)
     115                 :       1216 :         return true;
     116                 :            :     // scientific notation
     117                 :     303512 :     return(s.find("E-", 0) != std::string::npos
     118 [ +  + ][ -  + ]:     304728 :            || s.find("e-", 0) != std::string::npos);
     119                 :            : }
     120                 :            : 
     121                 :       2115 : bool MathLib::isNegative(const std::string &s)
     122                 :            : {
     123                 :            :     // remember position
     124                 :       2115 :     std::string::size_type n = 0;
     125                 :            :     // eat up whitespace
     126         [ -  + ]:       2115 :     while (std::isspace(s[n])) ++n;
     127                 :            :     // every negative number has a negative sign
     128                 :       2115 :     return(s[n] == '-');
     129                 :            : }
     130                 :            : 
     131                 :    6546385 : bool MathLib::isOct(const std::string& str)
     132                 :            : {
     133 [ +  + ][ +  + ]:    6546385 :     bool sign = str[0]=='-' || str[0]=='+';
     134 [ +  + ][ +  + ]:    6546385 :     return(str[sign?1:0] == '0' && (str.size() == 1 || isOctalDigit(str[sign?2:1])) && !isFloat(str));
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
     135                 :            : }
     136                 :            : 
     137                 :    6569551 : bool MathLib::isHex(const std::string& str)
     138                 :            : {
     139 [ +  + ][ +  + ]:    6569551 :     bool sign = str[0]=='-' || str[0]=='+';
     140 [ +  + ][ +  + ]:    6569551 :     return(str.compare(sign?1:0, 2, "0x") == 0 || str.compare(sign?1:0, 2, "0X") == 0);
         [ +  + ][ +  + ]
     141                 :            : }
     142                 :            : 
     143                 :    6063290 : bool MathLib::isBin(const std::string& str)
     144                 :            : {
     145 [ +  + ][ +  + ]:    6063290 :     bool sign = str[0]=='-' || str[0]=='+';
     146 [ +  + ][ +  + ]:    6063290 :     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);
         [ +  + ][ +  + ]
                 [ +  - ]
     147                 :            : }
     148                 :            : 
     149                 :     262107 : bool MathLib::isInt(const std::string & s)
     150                 :            : {
     151                 :            :     // perform prechecks:
     152                 :            :     // ------------------
     153                 :            :     // first check, if a point is found, it is an floating point value
     154         [ +  + ]:     262107 :     if (s.find(".", 0) != std::string::npos) return false;
     155                 :            :     // check for scientific notation e.g. NumberE-Number this is obvious an floating point value
     156 [ +  + ][ +  + ]:     255584 :     else if (s.find("E-", 0) != std::string::npos || s.find("e-", 0) != std::string::npos) return false;
                 [ +  + ]
     157                 :            : 
     158                 :            : 
     159                 :            :     // prechecking has nothing found,...
     160                 :            :     // gather information
     161                 :            :     enum Representation {
     162                 :            :         eScientific = 0, // NumberE+Number or NumberENumber
     163                 :            :         eOctal,          // starts with 0
     164                 :            :         eHex,            // starts with 0x
     165                 :            :         eDefault         // Numbers with a (possible) trailing u or U or l or L for unsigned or long datatypes
     166                 :            :     };
     167                 :            :     // create an instance
     168                 :     255358 :     Representation Mode = eDefault;
     169                 :            : 
     170                 :            : 
     171                 :            :     // remember position
     172                 :     255358 :     unsigned long n = 0;
     173                 :            :     // eat up whitespace
     174         [ -  + ]:     255358 :     while (std::isspace(s[n])) ++n;
     175                 :            : 
     176                 :            :     // determine type
     177         [ +  + ]:     255358 :     if (s.find("E", 0) != std::string::npos) {
     178                 :        271 :         Mode = eScientific;
     179         [ +  + ]:     255087 :     } else if (isHex(s)) {
     180                 :        225 :         Mode = eHex;
     181         [ +  + ]:     254862 :     } else if (isOct(s)) {
     182                 :      74694 :         Mode = eOctal;
     183                 :            :     }
     184                 :            : 
     185                 :            :     // check sign
     186 [ +  + ][ +  + ]:     255358 :     if (s[n] == '-' || s[n] == '+') ++n;
                 [ +  + ]
     187                 :            : 
     188                 :            :     // check scientific notation
     189         [ +  + ]:     255358 :     if (Mode == eScientific) {
     190                 :            :         // check digits
     191         [ +  + ]:        542 :         while (std::isdigit(s[n])) ++n;
     192                 :            : 
     193                 :            :         // check scientific notation
     194         [ +  - ]:        271 :         if (std::tolower(s[n]) == 'e') {
     195                 :        271 :             ++n;
     196                 :            :             // check positive exponent
     197         [ +  + ]:        271 :             if (s[n] == '+') ++n;
     198                 :            :             // floating pointer number e.g. 124E-2
     199         [ -  + ]:        271 :             if (s[n] == '-') return false;
     200                 :            :             // check digits of the exponent
     201         [ +  + ]:        902 :             while (std::isdigit(s[n])) ++n;
     202                 :            :         }
     203                 :            :     }
     204                 :            :     // check hex notation
     205         [ +  + ]:     255087 :     else if (Mode == eHex) {
     206                 :        225 :         ++n; // 0
     207                 :        225 :         ++n; // x
     208         [ +  + ]:        585 :         while (std::isxdigit(s[n]))
     209                 :        360 :             ++n;
     210                 :            : 
     211 [ +  - ][ -  + ]:        225 :         while (std::tolower(s[n]) == 'u' || std::tolower(s[n]) == 'l') ++n; // unsigned or long (long)
                 [ -  + ]
     212                 :            :     }
     213                 :            :     // check octal notation
     214         [ +  + ]:     254862 :     else if (Mode == eOctal) {
     215                 :      74694 :         ++n; // 0
     216         [ +  + ]:      74874 :         while (isOctalDigit(s[n]))
     217                 :        180 :             ++n;
     218                 :            : 
     219 [ +  - ][ -  + ]:      74694 :         while (std::tolower(s[n]) == 'u' || std::tolower(s[n]) == 'l') ++n; // unsigned or long (long)
                 [ -  + ]
     220         [ +  - ]:     180168 :     } else if (Mode == eDefault) {
     221                 :            :         // starts with digit
     222                 :     180168 :         bool bStartsWithDigit=false;
     223         [ +  + ]:     454035 :         while (std::isdigit(s[n])) {
     224                 :     273867 :             bStartsWithDigit=true;
     225                 :     273867 :             ++n;
     226                 :            :         };
     227                 :            : 
     228 [ +  + ][ +  + ]:     181712 :         while (std::tolower(s[n]) == 'u' || std::tolower(s[n]) == 'l') ++n; // unsigned or long (long)
                 [ +  + ]
     229                 :            : 
     230         [ +  + ]:     180168 :         if (!bStartsWithDigit)
     231                 :        542 :             return false;
     232                 :            :     }
     233                 :            :     // eat up whitespace
     234         [ -  + ]:     254816 :     while (std::isspace(s[n]))
     235                 :          0 :         ++n;
     236                 :            : 
     237                 :            :     // if everything goes good, we are at the end of the string and no digits/character
     238                 :            :     // is here --> return true, but if something was found eg. 12E+12AA return false
     239                 :     262107 :     return(n >= s.length());
     240                 :            : }
     241                 :            : 
     242                 :       3876 : std::string MathLib::add(const std::string & first, const std::string & second)
     243                 :            : {
     244 [ +  + ][ +  + ]:       3876 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     245                 :       3696 :         return longToString(toLongNumber(first) + toLongNumber(second));
     246                 :            :     }
     247                 :            : 
     248                 :        180 :     double d1 = toDoubleNumber(first);
     249                 :        180 :     double d2 = toDoubleNumber(second);
     250                 :            : 
     251                 :        180 :     int count = 0;
     252 [ +  + ][ +  - ]:        360 :     while (d1 > 100000.0 * d2 && doubleToString(d1+d2)==first && ++count<5)
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
     253                 :        180 :         d2 *= 10.0;
     254 [ +  + ][ +  - ]:        180 :     while (d2 > 100000.0 * d1 && doubleToString(d1+d2)==second && ++count<5)
         [ +  - ][ -  + ]
         [ #  # ][ +  + ]
         [ -  + ][ #  # ]
     255                 :          0 :         d1 *= 10.0;
     256                 :            : 
     257                 :       3876 :     return doubleToString(d1 + d2);
     258                 :            : }
     259                 :            : 
     260                 :       1530 : std::string MathLib::subtract(const std::string &first, const std::string &second)
     261                 :            : {
     262 [ +  + ][ +  + ]:       1530 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     263                 :       1260 :         return longToString(toLongNumber(first) - toLongNumber(second));
     264                 :            :     }
     265                 :            : 
     266         [ +  + ]:        270 :     if (first == second)
     267         [ +  - ]:         45 :         return "0.0" ;
     268                 :            : 
     269                 :        225 :     double d1 = toDoubleNumber(first);
     270                 :        225 :     double d2 = toDoubleNumber(second);
     271                 :            : 
     272                 :        225 :     int count = 0;
     273 [ +  + ][ +  - ]:        405 :     while (d1 > 100000.0 * d2 && doubleToString(d1-d2)==first && ++count<5)
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
     274                 :        180 :         d2 *= 10.0;
     275 [ +  + ][ +  - ]:        225 :     while (d2 > 100000.0 * d1 && doubleToString(d1-d2)==second && ++count<5)
         [ +  - ][ -  + ]
         [ #  # ][ +  + ]
         [ -  + ][ #  # ]
     276                 :          0 :         d1 *= 10.0;
     277                 :            : 
     278                 :       1530 :     return doubleToString(d1 - d2);
     279                 :            : }
     280                 :            : 
     281                 :        991 : std::string MathLib::divide(const std::string &first, const std::string &second)
     282                 :            : {
     283 [ +  + ][ +  + ]:        991 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     284                 :        765 :         bigint a = toLongNumber(first);
     285                 :        765 :         bigint b = toLongNumber(second);
     286         [ +  + ]:        765 :         if (a == std::numeric_limits<bigint>::min())
     287 [ +  - ][ +  - ]:         45 :             throw InternalError(0, "Internal Error: Division overflow");
     288         [ +  + ]:        720 :         if (b == 0)
     289 [ +  - ][ +  - ]:         45 :             throw InternalError(0, "Internal Error: Division by zero");
     290                 :        675 :         return longToString(toLongNumber(first) / b);
     291                 :            :     }
     292                 :        901 :     return doubleToString(toDoubleNumber(first) / toDoubleNumber(second));
     293                 :            : }
     294                 :            : 
     295                 :       2162 : std::string MathLib::multiply(const std::string &first, const std::string &second)
     296                 :            : {
     297 [ +  + ][ +  - ]:       2162 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     298                 :       1892 :         return longToString(toLongNumber(first) * toLongNumber(second));
     299                 :            :     }
     300                 :       2162 :     return doubleToString(toDoubleNumber(first) * toDoubleNumber(second));
     301                 :            : }
     302                 :            : 
     303                 :        450 : std::string MathLib::mod(const std::string &first, const std::string &second)
     304                 :            : {
     305 [ +  + ][ +  + ]:        450 :     if (MathLib::isInt(first) && MathLib::isInt(second)) {
                 [ +  + ]
     306                 :        225 :         bigint b = toLongNumber(second);
     307         [ +  + ]:        225 :         if (b == 0)
     308 [ +  - ][ +  - ]:         45 :             throw InternalError(0, "Internal Error: Division by zero");
     309                 :        180 :         return longToString(toLongNumber(first) % b);
     310                 :            :     }
     311                 :        405 :     return doubleToString(std::fmod(toDoubleNumber(first),toDoubleNumber(second)));
     312                 :            : }
     313                 :            : 
     314                 :       6714 : std::string MathLib::calculate(const std::string &first, const std::string &second, char action)
     315                 :            : {
     316   [ +  +  +  +  :       6714 :     switch (action) {
             +  +  +  -  
                      + ]
     317                 :            :     case '+':
     318                 :       3381 :         return MathLib::add(first, second);
     319                 :            : 
     320                 :            :     case '-':
     321                 :        810 :         return MathLib::subtract(first, second);
     322                 :            : 
     323                 :            :     case '*':
     324                 :       1442 :         return MathLib::multiply(first, second);
     325                 :            : 
     326                 :            :     case '/':
     327                 :        406 :         return MathLib::divide(first, second);
     328                 :            : 
     329                 :            :     case '%':
     330                 :        450 :         return MathLib::mod(first, second);
     331                 :            : 
     332                 :            :     case '&':
     333                 :         90 :         return MathLib::longToString(MathLib::toLongNumber(first) & MathLib::toLongNumber(second));
     334                 :            : 
     335                 :            :     case '|':
     336                 :         90 :         return MathLib::longToString(MathLib::toLongNumber(first) | MathLib::toLongNumber(second));
     337                 :            : 
     338                 :            :     case '^':
     339                 :          0 :         return MathLib::longToString(MathLib::toLongNumber(first) ^ MathLib::toLongNumber(second));
     340                 :            : 
     341                 :            :     default:
     342 [ +  - ][ +  - ]:       6669 :         throw InternalError(0, std::string("Unexpected action '") + action + "' in MathLib::calculate(). Please report this to Cppcheck developers.");
         [ +  - ][ +  - ]
     343                 :            :     }
     344                 :            : }
     345                 :            : 
     346                 :          0 : std::string MathLib::sin(const std::string &tok)
     347                 :            : {
     348                 :          0 :     return doubleToString(std::sin(toDoubleNumber(tok)));
     349                 :            : }
     350                 :            : 
     351                 :            : 
     352                 :          0 : std::string MathLib::cos(const std::string &tok)
     353                 :            : {
     354                 :          0 :     return doubleToString(std::cos(toDoubleNumber(tok)));
     355                 :            : }
     356                 :            : 
     357                 :          0 : std::string MathLib::tan(const std::string &tok)
     358                 :            : {
     359                 :          0 :     return doubleToString(std::tan(toDoubleNumber(tok)));
     360                 :            : }
     361                 :            : 
     362                 :            : 
     363                 :          0 : std::string MathLib::abs(const std::string &tok)
     364                 :            : {
     365                 :          0 :     return doubleToString(std::abs(toDoubleNumber(tok)));
     366                 :            : }
     367                 :            : 
     368                 :       1080 : bool MathLib::isEqual(const std::string &first, const std::string &second)
     369                 :            : {
     370                 :            :     // this conversion is needed for formatting
     371                 :            :     // e.g. if first=0.1 and second=1.0E-1, the direct comparison of the strings whould fail
     372 [ +  - ][ +  - ]:       1080 :     return doubleToString(toDoubleNumber(first)) == doubleToString(toDoubleNumber(second));
         [ +  - ][ +  - ]
     373                 :            : }
     374                 :            : 
     375                 :        855 : bool MathLib::isNotEqual(const std::string &first, const std::string &second)
     376                 :            : {
     377                 :        855 :     return !isEqual(first, second);
     378                 :            : }
     379                 :            : 
     380                 :        315 : bool MathLib::isGreater(const std::string &first, const std::string &second)
     381                 :            : {
     382                 :        315 :     return toDoubleNumber(first) > toDoubleNumber(second);
     383                 :            : }
     384                 :            : 
     385                 :        765 : bool MathLib::isGreaterEqual(const std::string &first, const std::string &second)
     386                 :            : {
     387                 :        765 :     return toDoubleNumber(first) >= toDoubleNumber(second);
     388                 :            : }
     389                 :            : 
     390                 :        495 : bool MathLib::isLess(const std::string &first, const std::string &second)
     391                 :            : {
     392                 :        495 :     return toDoubleNumber(first) < toDoubleNumber(second);
     393                 :            : }
     394                 :            : 
     395                 :       1755 : bool MathLib::isLessEqual(const std::string &first, const std::string &second)
     396                 :            : {
     397                 :       1755 :     return toDoubleNumber(first) <= toDoubleNumber(second);
     398                 :            : }
     399                 :            : 
     400                 :      16791 : bool MathLib::isNullValue(const std::string &str)
     401                 :            : {
     402                 :      49111 :     return (str == "-0"        || str == "0"      || str == "+0"
     403                 :      46182 :             || str == "-0.0"   || str == "0.0"    || str == "+0.0"
     404                 :      30203 :             || str == "-0."    || str == "+0."
     405                 :      60046 :             || str == "-0E-00" || str == "-0E+00" || str == "+0E+00" || str == "+0E-00"
     406                 :      59776 :             || str == "-0e-00" || str == "-0e+00" || str == "+0e+00" || str == "+0e-00"
     407   [ +  +  +  +  :     245318 :             || str == "-0E-0");
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  -  +  
          +  +  -  +  +  
          +  -  +  -  +  
                -  +  - ]
                 [ -  + ]
     408                 :            : }
     409                 :            : 
     410                 :      78315 : bool MathLib::isOctalDigit(char c)
     411                 :            : {
     412 [ +  + ][ +  + ]:      78315 :     return(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7');
         [ +  + ][ +  + ]
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
     413                 :            : }

Generated by: LCOV version 1.9