1 /*
2 Qalculate (library)
3
4 Copyright (C) 2003-2007, 2008, 2016, 2018 Hanna Knutsson (hanna.knutsson@protonmail.com)
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 */
11
12 #include "support.h"
13
14 #include "BuiltinFunctions.h"
15 #include "util.h"
16 #include "MathStructure.h"
17 #include "Number.h"
18 #include "Calculator.h"
19 #include "Variable.h"
20 #include "Unit.h"
21
22 #include <sstream>
23 #include <time.h>
24 #include <limits>
25 #include <algorithm>
26
27 #include "MathStructure-support.h"
28
29 using std::string;
30 using std::cout;
31 using std::vector;
32 using std::endl;
33
test_eval(MathStructure & mtest,const EvaluationOptions & eo)34 bool test_eval(MathStructure &mtest, const EvaluationOptions &eo) {
35 EvaluationOptions eo2 = eo;
36 eo2.assume_denominators_nonzero = false;
37 eo2.approximation = APPROXIMATION_APPROXIMATE;
38 CALCULATOR->beginTemporaryEnableIntervalArithmetic();
39 if(!CALCULATOR->usesIntervalArithmetic()) {CALCULATOR->endTemporaryEnableIntervalArithmetic(); return false;}
40 CALCULATOR->beginTemporaryStopMessages();
41 mtest.calculateFunctions(eo2);
42 mtest.calculatesub(eo2, eo2, true);
43 CALCULATOR->endTemporaryEnableIntervalArithmetic();
44 if(CALCULATOR->endTemporaryStopMessages()) return false;
45 return true;
46 }
47
calculate_arg(MathStructure & mstruct,const EvaluationOptions & eo)48 bool calculate_arg(MathStructure &mstruct, const EvaluationOptions &eo) {
49
50 MathStructure msave;
51
52 if(!mstruct.isNumber()) {
53 if(mstruct.isPower() && mstruct[0] == CALCULATOR->getVariableById(VARIABLE_ID_E) && mstruct[1].isNumber() && mstruct[1].number().hasImaginaryPart() && !mstruct[1].number().hasRealPart()) {
54 CALCULATOR->beginTemporaryEnableIntervalArithmetic();
55 if(CALCULATOR->usesIntervalArithmetic()) {
56 CALCULATOR->beginTemporaryStopMessages();
57 Number nr(*mstruct[1].number().internalImaginary());
58 Number nrpi; nrpi.pi();
59 nr.add(nrpi);
60 nr.divide(nrpi);
61 nr.divide(2);
62 Number nr_u(nr.upperEndPoint());
63 nr = nr.lowerEndPoint();
64 nr_u.floor();
65 nr.floor();
66 if(!CALCULATOR->endTemporaryStopMessages() && nr == nr_u) {
67 CALCULATOR->endTemporaryEnableIntervalArithmetic();
68 nr.setApproximate(false);
69 nr *= 2;
70 nr.negate();
71 mstruct = mstruct[1].number().imaginaryPart();
72 if(!nr.isZero()) {
73 mstruct += nr;
74 mstruct.last() *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
75 }
76 return true;
77 }
78 }
79 CALCULATOR->endTemporaryEnableIntervalArithmetic();
80 }
81 if(eo.approximation == APPROXIMATION_EXACT) {
82 msave = mstruct;
83 if(!test_eval(mstruct, eo)) {
84 mstruct = msave;
85 return false;
86 }
87 }
88 }
89 if(mstruct.isNumber()) {
90 if(!mstruct.number().hasImaginaryPart()) {
91 return false;
92 } else if(!mstruct.number().hasRealPart() && mstruct.number().imaginaryPartIsNonZero()) {
93 bool b_neg = mstruct.number().imaginaryPartIsNegative();
94 mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); mstruct.multiply(nr_half);
95 if(b_neg) mstruct.negate();
96 } else if(!msave.isZero()) {
97 mstruct = msave;
98 return false;
99 } else if(!mstruct.number().realPartIsNonZero()) {
100 return false;
101 } else {
102 MathStructure new_nr(mstruct.number().imaginaryPart());
103 if(!new_nr.number().divide(mstruct.number().realPart())) return false;
104 if(mstruct.number().realPartIsNegative()) {
105 if(mstruct.number().imaginaryPartIsNegative()) {
106 mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
107 switch(eo.parse_options.angle_unit) {
108 case ANGLE_UNIT_DEGREES: {mstruct.divide_nocopy(new MathStructure(180, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
109 case ANGLE_UNIT_GRADIANS: {mstruct.divide_nocopy(new MathStructure(200, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
110 case ANGLE_UNIT_RADIANS: {break;}
111 default: {if(CALCULATOR->getRadUnit()) {mstruct /= CALCULATOR->getRadUnit();} break;}
112 }
113 mstruct.subtract(CALCULATOR->getVariableById(VARIABLE_ID_PI));
114 } else if(mstruct.number().imaginaryPartIsNonNegative()) {
115 mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
116 switch(eo.parse_options.angle_unit) {
117 case ANGLE_UNIT_DEGREES: {mstruct.divide_nocopy(new MathStructure(180, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
118 case ANGLE_UNIT_GRADIANS: {mstruct.divide_nocopy(new MathStructure(200, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
119 case ANGLE_UNIT_RADIANS: {break;}
120 default: {if(CALCULATOR->getRadUnit()) {mstruct /= CALCULATOR->getRadUnit();} break;}
121 }
122 mstruct.add(CALCULATOR->getVariableById(VARIABLE_ID_PI));
123 } else {
124 return false;
125 }
126 } else {
127 mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
128 switch(eo.parse_options.angle_unit) {
129 case ANGLE_UNIT_DEGREES: {mstruct.divide_nocopy(new MathStructure(180, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
130 case ANGLE_UNIT_GRADIANS: {mstruct.divide_nocopy(new MathStructure(200, 1, 0)); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
131 case ANGLE_UNIT_RADIANS: {break;}
132 default: {if(CALCULATOR->getRadUnit()) {mstruct /= CALCULATOR->getRadUnit();} break;}
133 }
134 }
135 }
136 return true;
137 }
138 if(!msave.isZero()) {
139 mstruct = msave;
140 }
141 return false;
142
143 }
144
SqrtFunction()145 SqrtFunction::SqrtFunction() : MathFunction("sqrt", 1) {
146 Argument *arg = new Argument("", false, false);
147 arg->setHandleVector(true);
148 setArgumentDefinition(1, arg);
149 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)150 int SqrtFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
151 if(vargs[0].isVector()) return 0;
152 mstruct = vargs[0];
153 if(!vargs[0].representsScalar()) {
154 mstruct.eval(eo);
155 if(mstruct.isVector()) return -1;
156 }
157 mstruct.raise(nr_half);
158 return 1;
159 }
representsPositive(const MathStructure & vargs,bool allow_units) const160 bool SqrtFunction::representsPositive(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsPositive(allow_units);}
representsNegative(const MathStructure &,bool) const161 bool SqrtFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool allow_units) const162 bool SqrtFunction::representsNonNegative(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNonNegative(allow_units);}
representsNonPositive(const MathStructure &,bool) const163 bool SqrtFunction::representsNonPositive(const MathStructure&, bool) const {return false;}
representsInteger(const MathStructure &,bool) const164 bool SqrtFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool allow_units) const165 bool SqrtFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsRational(const MathStructure &,bool) const166 bool SqrtFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool allow_units) const167 bool SqrtFunction::representsReal(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNonNegative(allow_units);}
representsNonComplex(const MathStructure & vargs,bool allow_units) const168 bool SqrtFunction::representsNonComplex(const MathStructure &vargs, bool allow_units) const {return representsReal(vargs, allow_units);}
representsComplex(const MathStructure & vargs,bool allow_units) const169 bool SqrtFunction::representsComplex(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNegative(allow_units);}
representsNonZero(const MathStructure & vargs,bool allow_units) const170 bool SqrtFunction::representsNonZero(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNonZero(allow_units);}
representsEven(const MathStructure &,bool) const171 bool SqrtFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const172 bool SqrtFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const173 bool SqrtFunction::representsUndefined(const MathStructure&) const {return false;}
CbrtFunction()174 CbrtFunction::CbrtFunction() : MathFunction("cbrt", 1) {
175 Argument *arg = new Argument("", false, false);
176 arg->setHandleVector(true);
177 setArgumentDefinition(1, arg);
178 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)179 int CbrtFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
180 if(vargs[0].isVector()) return 0;
181 if(vargs[0].representsNegative(true)) {
182 mstruct = vargs[0];
183 mstruct.negate();
184 mstruct.raise(Number(1, 3, 0));
185 mstruct.negate();
186 } else if(vargs[0].representsNonNegative(true)) {
187 mstruct = vargs[0];
188 mstruct.raise(Number(1, 3, 0));
189 } else {
190 MathStructure mroot(3, 1, 0);
191 mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ROOT), &vargs[0], &mroot, NULL);
192 }
193 return 1;
194 }
RootFunction()195 RootFunction::RootFunction() : MathFunction("root", 2) {
196 NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
197 arg->setComplexAllowed(false);
198 arg->setHandleVector(true);
199 setArgumentDefinition(1, arg);
200 NumberArgument *arg2 = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, true);
201 arg2->setComplexAllowed(false);
202 arg2->setRationalNumber(true);
203 arg2->setHandleVector(true);
204 setArgumentDefinition(2, arg2);
205 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)206 int RootFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
207 if(vargs[0].isVector()) return 0;
208 if(vargs[1].number().isOne()) {
209 mstruct = vargs[0];
210 return 1;
211 }
212 if(!vargs[1].number().isInteger() || !vargs[1].number().isPositive()) {
213 mstruct = vargs[0];
214 if(!vargs[0].representsScalar()) {
215 mstruct.eval(eo);
216 }
217 if(mstruct.isVector()) return -1;
218 Number nr_root(vargs[1].number().numerator());
219 nr_root.setPrecisionAndApproximateFrom(vargs[1].number());
220 Number nr_pow(vargs[1].number().denominator());
221 nr_pow.setPrecisionAndApproximateFrom(vargs[1].number());
222 if(nr_root.isNegative()) {
223 nr_root.negate();
224 nr_pow.negate();
225 }
226 if(nr_root.isOne()) {
227 mstruct ^= nr_pow;
228 } else if(nr_root.isZero()) {
229 mstruct ^= nr_zero;
230 } else {
231 mstruct ^= nr_pow;
232 mstruct.transform(this);
233 mstruct.addChild(nr_root);
234 }
235 return 1;
236 }
237 if(vargs[0].representsNonNegative(true)) {
238 mstruct = vargs[0];
239 Number nr_exp(vargs[1].number());
240 nr_exp.recip();
241 mstruct.raise(nr_exp);
242 return 1;
243 } else if(vargs[1].number().isOdd() && vargs[0].representsNegative(true)) {
244 mstruct = vargs[0];
245 mstruct.negate();
246 Number nr_exp(vargs[1].number());
247 nr_exp.recip();
248 mstruct.raise(nr_exp);
249 mstruct.negate();
250 return 1;
251 }
252 bool eval_mstruct = !vargs[0].isNumber();
253 Number nr;
254 if(eval_mstruct) {
255 mstruct = vargs[0];
256 if(eo.approximation == APPROXIMATION_TRY_EXACT && mstruct.representsScalar()) {
257 EvaluationOptions eo2 = eo;
258 eo2.approximation = APPROXIMATION_EXACT;
259 mstruct.eval(eo2);
260 } else {
261 mstruct.eval(eo);
262 }
263 if(mstruct.isVector()) {
264 if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
265 return -1;
266 }
267 if(mstruct.representsNonNegative(true)) {
268 Number nr_exp(vargs[1].number());
269 nr_exp.recip();
270 mstruct.raise(nr_exp);
271 return 1;
272 } else if(vargs[1].number().isOdd() && mstruct.representsNegative(true)) {
273 mstruct.negate();
274 Number nr_exp(vargs[1].number());
275 nr_exp.recip();
276 mstruct.raise(nr_exp);
277 mstruct.negate();
278 return 1;
279 }
280 if(!mstruct.isNumber()) {
281 if(mstruct.isPower() && mstruct[1].isNumber() && mstruct[1].number().isInteger()) {
282 if(mstruct[1] == vargs[1]) {
283 if(mstruct[1].number().isEven()) {
284 if(!mstruct[0].representsReal(true)) return -1;
285 mstruct.delChild(2);
286 mstruct.setType(STRUCT_FUNCTION);
287 mstruct.setFunctionId(FUNCTION_ID_ABS);
288 } else {
289 mstruct.setToChild(1);
290 }
291 return 1;
292 } else if(mstruct[1].number().isIntegerDivisible(vargs[1].number())) {
293 if(mstruct[1].number().isEven()) {
294 if(!mstruct[0].representsReal(true)) return -1;
295 mstruct[0].transform(STRUCT_FUNCTION);
296 mstruct[0].setFunctionId(FUNCTION_ID_ABS);
297 }
298 mstruct[1].divide(vargs[1].number());
299 return 1;
300 } else if(!mstruct[1].number().isMinusOne() && vargs[1].number().isIntegerDivisible(mstruct[1].number())) {
301 if(mstruct[1].number().isEven()) {
302 if(!mstruct[0].representsReal(true)) return -1;
303 mstruct[0].transform(STRUCT_FUNCTION);
304 mstruct[0].setFunctionId(FUNCTION_ID_ABS);
305 }
306 Number new_root(vargs[1].number());
307 new_root.divide(mstruct[1].number());
308 bool bdiv = new_root.isNegative();
309 if(bdiv) new_root.negate();
310 mstruct[1] = new_root;
311 mstruct.setType(STRUCT_FUNCTION);
312 mstruct.setFunction(this);
313 if(bdiv) mstruct.raise(nr_minus_one);
314 return 1;
315 } else if(mstruct[1].number().isMinusOne()) {
316 mstruct[0].transform(STRUCT_FUNCTION, vargs[1]);
317 mstruct[0].setFunction(this);
318 return 1;
319 } else if(mstruct[1].number().isNegative()) {
320 mstruct[1].number().negate();
321 mstruct.transform(STRUCT_FUNCTION, vargs[1]);
322 mstruct.setFunction(this);
323 mstruct.raise(nr_minus_one);
324 return 1;
325 }
326 } else if(mstruct.isPower() && mstruct[1].isNumber() && mstruct[1].number().isRational() && mstruct[1].number().denominatorIsTwo()) {
327 Number new_root(vargs[1].number());
328 new_root.multiply(Number(2, 1, 0));
329 if(mstruct[1].number().numeratorIsOne()) {
330 mstruct[1].number().set(new_root, true);
331 mstruct.setType(STRUCT_FUNCTION);
332 mstruct.setFunction(this);
333 } else {
334 mstruct[1].number().set(mstruct[1].number().numerator(), true);
335 mstruct.transform(STRUCT_FUNCTION);
336 mstruct.addChild(new_root);
337 mstruct.setFunction(this);
338 }
339 return 1;
340 } else if(mstruct.isFunction() && mstruct.function()->id() == FUNCTION_ID_SQRT && mstruct.size() == 1) {
341 Number new_root(vargs[1].number());
342 new_root.multiply(Number(2, 1, 0));
343 mstruct.addChild(new_root);
344 mstruct.setFunction(this);
345 return 1;
346 } else if(mstruct.isFunction() && mstruct.function()->id() == FUNCTION_ID_ROOT && mstruct.size() == 2 && mstruct[1].isNumber() && mstruct[1].number().isInteger() && mstruct[1].number().isPositive()) {
347 Number new_root(vargs[1].number());
348 new_root.multiply(mstruct[1].number());
349 mstruct[1] = new_root;
350 return 1;
351 } else if(mstruct.isMultiplication()) {
352 bool b = true;
353 for(size_t i = 0; i < mstruct.size(); i++) {
354 if(!mstruct[i].representsReal(true)) {
355 b = false;
356 break;
357 }
358 }
359 if(b) {
360 if(vargs[1].number().isOdd()) {
361 bool b_neg = false;
362 for(size_t i = 0; i < mstruct.size(); i++) {
363 if(mstruct[i].isNumber() && mstruct[i].number().isNegative() && !mstruct[i].isMinusOne()) {
364 mstruct[i].negate();
365 b_neg = !b_neg;
366 }
367 mstruct[i].transform(STRUCT_FUNCTION, vargs[1]);
368 mstruct[i].setFunction(this);
369 }
370 if(b_neg) mstruct.insertChild_nocopy(new MathStructure(-1, 1, 0), 1);
371 return 1;
372 } else {
373 for(size_t i = 0; i < mstruct.size(); i++) {
374 if(mstruct[i].isNumber() && mstruct[i].number().isNegative() && !mstruct[i].isMinusOne()) {
375 MathStructure *mmul = new MathStructure(this, &mstruct[i], &vargs[1], NULL);
376 (*mmul)[0].negate();
377 mstruct[i] = nr_minus_one;
378 mstruct.transform(STRUCT_FUNCTION, vargs[1]);
379 mstruct.setFunction(this);
380 mstruct.multiply_nocopy(mmul);
381 return true;
382 } else if(mstruct[i].representsPositive()) {
383 mstruct[i].transform(STRUCT_FUNCTION, vargs[1]);
384 mstruct[i].setFunction(this);
385 mstruct[i].ref();
386 MathStructure *mmul = &mstruct[i];
387 mstruct.delChild(i + 1, true);
388 mstruct.transform(STRUCT_FUNCTION, vargs[1]);
389 mstruct.setFunction(this);
390 mstruct.multiply_nocopy(mmul);
391 return true;
392 }
393 }
394 }
395 }
396 }
397 return -1;
398 }
399 nr = mstruct.number();
400 } else {
401 nr = vargs[0].number();
402 }
403 if(!nr.root(vargs[1].number()) || (eo.approximation < APPROXIMATION_APPROXIMATE && nr.isApproximate() && !vargs[0].isApproximate() && !mstruct.isApproximate() && !vargs[1].isApproximate()) || (!eo.allow_complex && nr.isComplex() && !vargs[0].number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !vargs[0].number().includesInfinity())) {
404 if(!eval_mstruct) {
405 if(vargs[0].number().isNegative() && vargs[1].number().isOdd()) {
406 mstruct.set(this, &vargs[0], &vargs[1], NULL);
407 mstruct[0].number().negate();
408 mstruct.negate();
409 return 1;
410 }
411 return 0;
412 } else if(mstruct.number().isNegative() && vargs[1].number().isOdd()) {
413 mstruct.number().negate();
414 mstruct.transform(STRUCT_FUNCTION, vargs[1]);
415 mstruct.setFunction(this);
416 mstruct.negate();
417 return 1;
418 }
419 } else {
420 mstruct.set(nr);
421 return 1;
422 }
423 return -1;
424 }
representsPositive(const MathStructure & vargs,bool allow_units) const425 bool RootFunction::representsPositive(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsPositive(allow_units);}
representsNegative(const MathStructure & vargs,bool allow_units) const426 bool RootFunction::representsNegative(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsOdd() && vargs[1].representsPositive() && vargs[0].representsNegative(allow_units);}
representsNonNegative(const MathStructure & vargs,bool allow_units) const427 bool RootFunction::representsNonNegative(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsNonNegative(allow_units);}
representsNonPositive(const MathStructure & vargs,bool allow_units) const428 bool RootFunction::representsNonPositive(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsOdd() && vargs[1].representsPositive() && vargs[0].representsNonPositive(allow_units);}
representsInteger(const MathStructure &,bool) const429 bool RootFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool allow_units) const430 bool RootFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsNumber(allow_units);}
representsRational(const MathStructure &,bool) const431 bool RootFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool allow_units) const432 bool RootFunction::representsReal(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsReal(allow_units) && (vargs[0].representsNonNegative(allow_units) || vargs[1].representsOdd());}
representsNonComplex(const MathStructure & vargs,bool allow_units) const433 bool RootFunction::representsNonComplex(const MathStructure &vargs, bool allow_units) const {return representsReal(vargs, allow_units);}
representsComplex(const MathStructure & vargs,bool allow_units) const434 bool RootFunction::representsComplex(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && (vargs[0].representsComplex(allow_units) || (vargs[1].representsEven() && vargs[0].representsNegative(allow_units)));}
representsNonZero(const MathStructure & vargs,bool allow_units) const435 bool RootFunction::representsNonZero(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 2 && vargs[1].representsInteger() && vargs[1].representsPositive() && vargs[0].representsNonZero(allow_units);}
representsEven(const MathStructure &,bool) const436 bool RootFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const437 bool RootFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const438 bool RootFunction::representsUndefined(const MathStructure&) const {return false;}
439
SquareFunction()440 SquareFunction::SquareFunction() : MathFunction("sq", 1) {
441 Argument *arg = new Argument("", false, false);
442 arg->setHandleVector(true);
443 setArgumentDefinition(1, arg);
444 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)445 int SquareFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
446 mstruct = vargs[0];
447 mstruct ^= 2;
448 return 1;
449 }
450
ExpFunction()451 ExpFunction::ExpFunction() : MathFunction("exp", 1) {
452 Argument *arg = new Argument("", false, false);
453 arg->setHandleVector(true);
454 setArgumentDefinition(1, arg);
455 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)456 int ExpFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
457 mstruct = CALCULATOR->getVariableById(VARIABLE_ID_E);
458 mstruct ^= vargs[0];
459 return 1;
460 }
461
LogFunction()462 LogFunction::LogFunction() : MathFunction("ln", 1) {
463 Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO, false);
464 arg->setHandleVector(true);
465 setArgumentDefinition(1, arg);
466 }
representsPositive(const MathStructure & vargs,bool) const467 bool LogFunction::representsPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsPositive() && ((vargs[0].isNumber() && vargs[0].number().isGreaterThan(nr_one)) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && ((KnownVariable*) vargs[0].variable())->get().number().isGreaterThan(nr_one)));}
representsNegative(const MathStructure & vargs,bool) const468 bool LogFunction::representsNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative() && ((vargs[0].isNumber() && vargs[0].number().isLessThan(nr_one)) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && ((KnownVariable*) vargs[0].variable())->get().number().isLessThan(nr_one)));}
representsNonNegative(const MathStructure & vargs,bool) const469 bool LogFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsPositive() && ((vargs[0].isNumber() && vargs[0].number().isGreaterThanOrEqualTo(nr_one)) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && ((KnownVariable*) vargs[0].variable())->get().number().isGreaterThanOrEqualTo(nr_one)));}
representsNonPositive(const MathStructure & vargs,bool) const470 bool LogFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative() && ((vargs[0].isNumber() && vargs[0].number().isLessThanOrEqualTo(nr_one)) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && ((KnownVariable*) vargs[0].variable())->get().number().isLessThanOrEqualTo(nr_one)));}
representsInteger(const MathStructure &,bool) const471 bool LogFunction::representsInteger(const MathStructure&, bool) const {return false;}
representsNumber(const MathStructure & vargs,bool allow_units) const472 bool LogFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units) && vargs[0].representsNonZero(allow_units);}
representsRational(const MathStructure &,bool) const473 bool LogFunction::representsRational(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure & vargs,bool) const474 bool LogFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsPositive();}
representsNonComplex(const MathStructure & vargs,bool) const475 bool LogFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative();}
representsComplex(const MathStructure & vargs,bool) const476 bool LogFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNegative();}
representsNonZero(const MathStructure & vargs,bool) const477 bool LogFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && (vargs[0].representsNonPositive() || (vargs[0].isNumber() && COMPARISON_IS_NOT_EQUAL(vargs[0].number().compare(nr_one))) || (vargs[0].isVariable() && vargs[0].variable()->isKnown() && ((KnownVariable*) vargs[0].variable())->get().isNumber() && COMPARISON_IS_NOT_EQUAL(((KnownVariable*) vargs[0].variable())->get().number().compare(nr_one))));}
representsEven(const MathStructure &,bool) const478 bool LogFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const479 bool LogFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const480 bool LogFunction::representsUndefined(const MathStructure&) const {return false;}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)481 int LogFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
482 if(vargs[0].isVector()) return 0;
483
484 mstruct = vargs[0];
485
486 if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_E) {
487 mstruct.set(m_one);
488 return true;
489 } else if(mstruct.isPower()) {
490 if(mstruct[0].isVariable() && mstruct[0].variable()->id() == VARIABLE_ID_E) {
491 if(mstruct[1].representsReal()) {
492 mstruct.setToChild(2, true);
493 return true;
494 }
495 } else if(eo.approximation != APPROXIMATION_APPROXIMATE && ((mstruct[0].representsPositive(true) && mstruct[1].representsReal()) || (mstruct[1].isNumber() && mstruct[1].number().isFraction()))) {
496 MathStructure mstruct2;
497 mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
498 mstruct2 *= mstruct[1];
499 mstruct = mstruct2;
500 return true;
501 }
502 }
503
504 if(eo.approximation == APPROXIMATION_TRY_EXACT) {
505 EvaluationOptions eo2 = eo;
506 eo2.approximation = APPROXIMATION_EXACT;
507 CALCULATOR->beginTemporaryStopMessages();
508 mstruct.eval(eo2);
509 if(mstruct.isVector()) {CALCULATOR->endTemporaryStopMessages(true); return -1;}
510 } else {
511 mstruct.eval(eo);
512 if(mstruct.isVector()) return -1;
513 }
514
515 bool b = false;
516 if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_E) {
517 mstruct.set(m_one);
518 b = true;
519 } else if(mstruct.isPower()) {
520 if(mstruct[0].isVariable() && mstruct[0].variable()->id() == VARIABLE_ID_E) {
521 if(mstruct[1].representsReal()) {
522 mstruct.setToChild(2, true);
523 b = true;
524 }
525 } else if((mstruct[0].representsPositive(true) && mstruct[1].representsReal()) || (mstruct[1].isNumber() && mstruct[1].number().isFraction())) {
526 MathStructure mstruct2;
527 mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
528 mstruct2 *= mstruct[1];
529 mstruct = mstruct2;
530 b = true;
531 }
532 } else if(mstruct.isMultiplication()) {
533 b = true;
534 for(size_t i = 0; i < mstruct.size(); i++) {
535 if(!mstruct[i].representsPositive()) {
536 b = false;
537 break;
538 }
539 }
540 if(b) {
541 MathStructure mstruct2;
542 mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
543 for(size_t i = 1; i < mstruct.size(); i++) {
544 mstruct2.add(MathStructure(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[i], NULL), i > 1);
545 }
546 mstruct = mstruct2;
547 }
548 }
549 if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(b);
550 if(b) return 1;
551 if(eo.approximation == APPROXIMATION_TRY_EXACT && !mstruct.isNumber()) {
552 EvaluationOptions eo2 = eo;
553 eo2.approximation = APPROXIMATION_APPROXIMATE;
554 mstruct = vargs[0];
555 mstruct.eval(eo2);
556 }
557
558 if(mstruct.isNumber()) {
559 if(eo.allow_complex && mstruct.number().isMinusOne()) {
560 mstruct = nr_one_i;
561 mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
562 return 1;
563 } else if(mstruct.number().isI()) {
564 mstruct.set(1, 2, 0);
565 mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
566 mstruct *= nr_one_i;
567 return 1;
568 } else if(mstruct.number().isMinusI()) {
569 mstruct.set(-1, 2, 0);
570 mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
571 mstruct *= nr_one_i;
572 return 1;
573 } else if(eo.allow_complex && eo.allow_infinite && mstruct.number().isMinusInfinity()) {
574 mstruct = CALCULATOR->getVariableById(VARIABLE_ID_PI);
575 mstruct *= nr_one_i;
576 Number nr; nr.setPlusInfinity();
577 mstruct += nr;
578 return 1;
579 }
580 Number nr(mstruct.number());
581 if(nr.ln() && !(eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) && !(!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) && !(!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
582 mstruct.set(nr, true);
583 return 1;
584 }
585 if(mstruct.number().isRational() && mstruct.number().isPositive()) {
586 if(mstruct.number().isInteger()) {
587 if(mstruct.number().isLessThanOrEqualTo(PRIMES[NR_OF_PRIMES - 1])) {
588 vector<Number> factors;
589 mstruct.number().factorize(factors);
590 if(factors.size() > 1) {
591 mstruct.clear(true);
592 mstruct.setType(STRUCT_ADDITION);
593 for(size_t i = 0; i < factors.size(); i++) {
594 if(i > 0 && factors[i] == factors[i - 1]) {
595 if(mstruct.last().isMultiplication()) mstruct.last().last().number()++;
596 else mstruct.last() *= nr_two;
597 } else {
598 mstruct.addChild(MathStructure(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), NULL));
599 mstruct.last().addChild(factors[i]);
600 }
601 }
602 if(mstruct.size() == 1) mstruct.setToChild(1, true);
603 return 1;
604 }
605 }
606 } else {
607 MathStructure mstruct2(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), NULL);
608 mstruct2.addChild(mstruct.number().denominator());
609 mstruct.number().set(mstruct.number().numerator());
610 mstruct.transformById(FUNCTION_ID_LOG);
611 mstruct -= mstruct2;
612 return 1;
613 }
614 } else if(mstruct.number().hasImaginaryPart()) {
615 if(mstruct.number().hasRealPart()) {
616 MathStructure *marg = new MathStructure(mstruct);
617 if(calculate_arg(*marg, eo)) {
618 mstruct.transformById(FUNCTION_ID_ABS);
619 mstruct.transformById(FUNCTION_ID_LOG);
620 marg->multiply(nr_one_i);
621 mstruct.add_nocopy(marg);
622 return 1;
623 }
624 marg->unref();
625 } else {
626 bool b_neg = mstruct.number().imaginaryPartIsNegative();
627 if(mstruct.number().abs()) {
628 mstruct.transform(this);
629 mstruct += b_neg ? nr_minus_half : nr_half;
630 mstruct.last() *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
631 mstruct.last().multiply(nr_one_i, true);
632 }
633 return 1;
634 }
635 }
636 } else if(mstruct.isPower()) {
637 if((mstruct[0].representsPositive(true) && mstruct[1].representsReal()) || (mstruct[1].isNumber() && mstruct[1].number().isFraction())) {
638 MathStructure mstruct2;
639 mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
640 mstruct2 *= mstruct[1];
641 mstruct = mstruct2;
642 return 1;
643 }
644 if(mstruct[1].isNumber() && mstruct[1].number().isTwo() && mstruct[0].representsPositive()) {
645 mstruct.setToChild(1, true);
646 mstruct.transform(this);
647 mstruct *= nr_two;
648 return 1;
649 }
650 if(eo.approximation == APPROXIMATION_EXACT && !mstruct[1].isNumber()) {
651 CALCULATOR->beginTemporaryStopMessages();
652 MathStructure mtest(mstruct[1]);
653 EvaluationOptions eo2 = eo;
654 eo2.approximation = APPROXIMATION_APPROXIMATE;
655 mtest.eval(eo2);
656 if(!CALCULATOR->endTemporaryStopMessages() && mtest.isNumber() && mtest.number().isFraction()) {
657 MathStructure mstruct2;
658 mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &mstruct[0], NULL);
659 mstruct2 *= mstruct[1];
660 mstruct = mstruct2;
661 return 1;
662 }
663 }
664 }
665 if(eo.allow_complex && mstruct.representsNegative()) {
666 mstruct.negate();
667 mstruct.transformById(FUNCTION_ID_LOG);
668 mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI);
669 mstruct.last() *= nr_one_i;
670 return 1;
671 }
672 if(!mstruct.representsReal()) {
673 MathStructure *marg = new MathStructure(mstruct);
674 if(calculate_arg(*marg, eo)) {
675 mstruct.transformById(FUNCTION_ID_ABS);
676 mstruct.transformById(FUNCTION_ID_LOG);
677 marg->multiply(nr_one_i);
678 mstruct.add_nocopy(marg);
679 return 1;
680 }
681 marg->unref();
682 }
683
684 return -1;
685
686 }
LognFunction()687 LognFunction::LognFunction() : MathFunction("log", 1, 2) {
688 Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO, false);
689 arg->setHandleVector(true);
690 setArgumentDefinition(1, arg);
691 arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO, false);
692 arg->setHandleVector(true);
693 setArgumentDefinition(2, arg);
694 setDefaultValue(2, "e");
695 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)696 int LognFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
697 if(vargs[0].isVector() || vargs[1].isVector()) return 0;
698 if(vargs[1].isVariable() && vargs[1].variable()->id() == VARIABLE_ID_E) {
699 mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &vargs[0], NULL);
700 return 1;
701 }
702 mstruct = vargs[0];
703 mstruct.eval(eo);
704 if(mstruct.isVector()) return -1;
705 MathStructure mstructv2 = vargs[1];
706 mstructv2.eval(eo);
707 if(mstructv2.isVector()) return -2;
708 if(mstruct.isPower()) {
709 if((mstruct[0].representsPositive(true) && mstruct[1].representsReal()) || (mstruct[1].isNumber() && mstruct[1].number().isFraction())) {
710 MathStructure mstruct2;
711 mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOGN), &mstruct[0], &mstructv2, NULL);
712 mstruct2 *= mstruct[1];
713 mstruct = mstruct2;
714 return 1;
715 }
716 } else if(mstruct.isMultiplication()) {
717 bool b = true;
718 for(size_t i = 0; i < mstruct.size(); i++) {
719 if(!mstruct[i].representsPositive()) {
720 b = false;
721 break;
722 }
723 }
724 if(b) {
725 MathStructure mstruct2;
726 mstruct2.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOGN), &mstruct[0], &mstructv2, NULL);
727 for(size_t i = 1; i < mstruct.size(); i++) {
728 mstruct2.add(MathStructure(CALCULATOR->getFunctionById(FUNCTION_ID_LOGN), &mstruct[i], &mstructv2, NULL), i > 1);
729 }
730 mstruct = mstruct2;
731 return 1;
732 }
733 } else if(mstruct.isNumber() && mstructv2.isNumber()) {
734 Number nr(mstruct.number());
735 if(nr.log(mstructv2.number()) && !(eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) && !(!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) && !(!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
736 mstruct.set(nr, true);
737 return 1;
738 }
739 }
740 mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &vargs[0], NULL);
741 mstruct.divide_nocopy(new MathStructure(CALCULATOR->getFunctionById(FUNCTION_ID_LOG), &vargs[1], NULL));
742 return 1;
743 }
CisFunction()744 CisFunction::CisFunction() : MathFunction("cis", 1) {
745 Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
746 arg->setHandleVector(true);
747 setArgumentDefinition(1, arg);
748 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)749 int CisFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
750
751 if(vargs[0].isVector()) return 0;
752 if(contains_angle_unit(vargs[0], eo.parse_options)) {
753 if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getRadUnit()) {
754 mstruct = vargs[0][0];
755 } else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getRadUnit()) {
756 mstruct = vargs[0][1];
757 } else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getDegUnit()) {
758 mstruct = vargs[0][0];
759 mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
760 mstruct.multiply(Number(1, 180), true);
761 } else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getDegUnit()) {
762 mstruct = vargs[0][1];
763 mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
764 mstruct.multiply(Number(1, 180), true);
765 } else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getGraUnit()) {
766 mstruct = vargs[0][0];
767 mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
768 mstruct.multiply(Number(1, 200), true);
769 } else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getGraUnit()) {
770 mstruct = vargs[0][1];
771 mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
772 mstruct.multiply(Number(1, 200), true);
773 } else {
774 mstruct = vargs[0];
775 mstruct.convert(CALCULATOR->getRadUnit());
776 mstruct /= CALCULATOR->getRadUnit();
777 }
778 } else {
779 mstruct = vargs[0];
780 }
781
782 if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_PI) {
783 mstruct.set(-1, 1, 0, true);
784 return 1;
785 } else if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isInteger() && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI) {
786 if(mstruct[0].number().isEven()) {
787 mstruct.set(1, 1, 0, true);
788 return 1;
789 } else if(mstruct[0].number().isOdd()) {
790 mstruct.set(-1, 1, 0, true);
791 return 1;
792 }
793 }
794
795 mstruct *= nr_one_i;
796 mstruct ^= CALCULATOR->getVariableById(VARIABLE_ID_E);
797 mstruct.swapChildren(1, 2);
798
799 return 1;
800
801 }
LambertWFunction()802 LambertWFunction::LambertWFunction() : MathFunction("lambertw", 1, 2) {
803 NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
804 arg->setComplexAllowed(false);
805 arg->setHandleVector(true);
806 setArgumentDefinition(1, arg);
807 setArgumentDefinition(2, new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
808 setDefaultValue(2, "0");
809 }
representsNumber(const MathStructure & vargs,bool) const810 bool LambertWFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[0].representsNumber() && (vargs[1].isZero() || vargs[0].representsNonZero()));}
representsReal(const MathStructure & vargs,bool) const811 bool LambertWFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[1].isZero() && vargs[0].representsNonNegative());}
representsNonComplex(const MathStructure & vargs,bool) const812 bool LambertWFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[0].isZero() || (vargs[1].isZero() && vargs[0].representsNonNegative()));}
representsComplex(const MathStructure & vargs,bool) const813 bool LambertWFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[0].representsComplex() || (vargs[0].representsNonZero() && (vargs[1].isInteger() && (!vargs[1].isMinusOne() || vargs[0].representsPositive()) && !vargs[1].isZero())));}
representsNonZero(const MathStructure & vargs,bool) const814 bool LambertWFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 2 && (vargs[1].representsNonZero() || vargs[0].representsNonZero());}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)815 int LambertWFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
816
817 if(vargs[0].isVector()) return 0;
818 mstruct = vargs[0];
819
820 if(eo.approximation == APPROXIMATION_TRY_EXACT) {
821 EvaluationOptions eo2 = eo;
822 eo2.approximation = APPROXIMATION_EXACT;
823 CALCULATOR->beginTemporaryStopMessages();
824 mstruct.eval(eo2);
825 if(mstruct.isVector()) {CALCULATOR->endTemporaryStopMessages(true); return -1;}
826 } else {
827 mstruct.eval(eo);
828 if(mstruct.isVector()) return -1;
829 }
830
831 bool b = false;
832 if(!vargs[1].isZero()) {
833 if(mstruct.isZero()) {
834 mstruct.set(nr_minus_inf, true);
835 b = true;
836 } else if(vargs[1].isMinusOne()) {
837 if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isNumber() && mstruct[1].isPower() && mstruct[1][0].isVariable() && mstruct[1][0].variable()->id() == VARIABLE_ID_E && mstruct[0].number() <= nr_minus_one && mstruct[1][1] == mstruct[0]) {
838 mstruct.setToChild(1, true);
839 b = true;
840 }
841 }
842
843 } else {
844 if(mstruct.isZero()) {
845 b = true;
846 } else if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_E) {
847 mstruct.set(1, 1, 0, true);
848 b = true;
849 } else if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isMinusOne() && mstruct[1].isPower() && mstruct[1][0].isVariable() && mstruct[1][0].variable()->id() == VARIABLE_ID_E && mstruct[1][1].isMinusOne()) {
850 mstruct.set(-1, 1, 0, true);
851 b = true;
852 }
853 }
854 if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(b);
855 if(b) return 1;
856 if(eo.approximation == APPROXIMATION_EXACT) return -1;
857 if(eo.approximation == APPROXIMATION_TRY_EXACT && !mstruct.isNumber()) {
858 EvaluationOptions eo2 = eo;
859 eo2.approximation = APPROXIMATION_APPROXIMATE;
860 mstruct = vargs[0];
861 mstruct.eval(eo2);
862 }
863 if(mstruct.isNumber()) {
864 Number nr(mstruct.number());
865 if(nr.lambertW(vargs[1].number()) && !(eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) && !(!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) && !(!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
866 mstruct.set(nr, true);
867 return 1;
868 }
869 }
870 return -1;
871 }
872
873