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 : : }
|