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 
34 #define FR_FUNCTION_2(FUNC)	Number nr(vargs[0].number()); if(!nr.FUNC(vargs[1].number()) || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !vargs[0].isApproximate() && !vargs[1].isApproximate()) || (!eo.allow_complex && nr.isComplex() && !vargs[0].number().isComplex() && !vargs[1].number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !vargs[0].number().includesInfinity() && !vargs[1].number().includesInfinity())) {return 0;} else {mstruct.set(nr); return 1;}
35 
is_real_angle_value(const MathStructure & mstruct)36 bool is_real_angle_value(const MathStructure &mstruct) {
37 	if(mstruct.isUnit()) {
38 		return mstruct.unit()->baseUnit() == CALCULATOR->getRadUnit()->baseUnit();
39 	} else if(mstruct.isMultiplication()) {
40 		bool b = false;
41 		for(size_t i = 0; i < mstruct.size(); i++) {
42 			if(!b && mstruct[i].isUnit()) {
43 				if(mstruct[i].unit()->baseUnit() == CALCULATOR->getRadUnit()->baseUnit()) {
44 					b = true;
45 				} else {
46 					return false;
47 				}
48 			} else if(!mstruct[i].representsReal()) {
49 				return false;
50 			}
51 		}
52 		return b;
53 	} else if(mstruct.isAddition()) {
54 		for(size_t i = 0; i < mstruct.size(); i++) {
55 			if(!is_real_angle_value(mstruct[i])) return false;
56 		}
57 		return true;
58 	}
59 	return false;
60 }
is_infinite_angle_value(const MathStructure & mstruct)61 bool is_infinite_angle_value(const MathStructure &mstruct) {
62 	if(mstruct.isMultiplication() && mstruct.size() == 2) {
63 		bool b = false;
64 		for(size_t i = 0; i < mstruct.size(); i++) {
65 			if(!b && mstruct[i].isUnit()) {
66 				if(mstruct[i].unit()->baseUnit() == CALCULATOR->getRadUnit()->baseUnit()) {
67 					b = true;
68 				} else {
69 					return false;
70 				}
71 			} else if(!mstruct[i].isNumber() || !mstruct[i].number().isInfinite()) {
72 				return false;
73 			}
74 		}
75 		return b;
76 	}
77 	return false;
78 }
is_number_angle_value(const MathStructure & mstruct,bool allow_infinity=false)79 bool is_number_angle_value(const MathStructure &mstruct, bool allow_infinity = false) {
80 	if(mstruct.isUnit()) {
81 		return mstruct.unit()->baseUnit() == CALCULATOR->getRadUnit()->baseUnit();
82 	} else if(mstruct.isMultiplication()) {
83 		bool b = false;
84 		for(size_t i = 0; i < mstruct.size(); i++) {
85 			if(!b && mstruct[i].isUnit()) {
86 				if(mstruct[i].unit()->baseUnit() == CALCULATOR->getRadUnit()->baseUnit()) {
87 					b = true;
88 				} else {
89 					return false;
90 				}
91 			} else if(!mstruct[i].representsNumber()) {
92 				if(!allow_infinity || ((!mstruct[i].isNumber() || !mstruct[i].number().isInfinite()) && (!mstruct[i].isPower() || !mstruct[i][0].representsNumber() || !mstruct[i][1].representsNumber())) || mstruct[i].representsUndefined(true)) {
93 					return false;
94 				}
95 			}
96 		}
97 		return b;
98 	} else if(mstruct.isAddition()) {
99 		for(size_t i = 0; i < mstruct.size(); i++) {
100 			if(!is_number_angle_value(mstruct[i])) return false;
101 		}
102 		return true;
103 	}
104 	return false;
105 }
106 
has_predominately_negative_sign(const MathStructure & mstruct)107 bool has_predominately_negative_sign(const MathStructure &mstruct) {
108 	if(mstruct.hasNegativeSign() && !mstruct.containsType(STRUCT_ADDITION, true)) return true;
109 	if(mstruct.containsInfinity(false, false, false) > 0) return false;
110 	if(mstruct.isAddition() && mstruct.size() > 0) {
111 		size_t p_count = 0;
112 		for(size_t i = 0; i < mstruct.size(); i++) {
113 			if(mstruct[i].hasNegativeSign()) {
114 				p_count++;
115 				if(p_count > mstruct.size() / 2) return true;
116 			}
117 		}
118 		if(mstruct.size() % 2 == 0 && p_count == mstruct.size() / 2) return mstruct[0].hasNegativeSign();
119 	}
120 	return false;
121 }
122 
negate_struct(MathStructure & mstruct)123 void negate_struct(MathStructure &mstruct) {
124 	if(mstruct.isAddition()) {
125 		for(size_t i = 0; i < mstruct.size(); i++) {
126 			mstruct[i].negate();
127 		}
128 	} else {
129 		mstruct.negate();
130 	}
131 }
132 
trig_remove_i(MathStructure & mstruct)133 bool trig_remove_i(MathStructure &mstruct) {
134 	if(mstruct.isNumber() && mstruct.number().hasImaginaryPart() && !mstruct.number().hasRealPart()) {
135 		mstruct.number() /= nr_one_i;
136 		return true;
137 	} else if(mstruct.isMultiplication() && mstruct.size() > 1 && mstruct[0].isNumber() && mstruct[0].number().hasImaginaryPart() && !mstruct[0].number().hasRealPart()) {
138 		mstruct[0].number() /= nr_one_i;
139 		return true;
140 	} else if(mstruct.isAddition() && mstruct.size() > 0) {
141 		for(size_t i = 0; i < mstruct.size(); i++) {
142 			if(!(mstruct[i].isNumber() && mstruct[i].number().hasImaginaryPart() && !mstruct[i].number().hasRealPart()) && !(mstruct[i].isMultiplication() && mstruct[i].size() > 1 && mstruct[i][0].isNumber() && mstruct[i][0].number().hasImaginaryPart() && !mstruct[i][0].number().hasRealPart())) {
143 				return false;
144 			}
145 		}
146 		for(size_t i = 0; i < mstruct.size(); i++) {
147 			if(mstruct[i].isNumber()) mstruct[i].number() /= nr_one_i;
148 			else mstruct[i][0].number() /= nr_one_i;
149 		}
150 		return true;
151 	}
152 	return false;
153 }
154 
SinFunction()155 SinFunction::SinFunction() : MathFunction("sin", 1) {
156 	Argument *arg = new AngleArgument();
157 	arg->setHandleVector(true);
158 	setArgumentDefinition(1, arg);
159 }
representsNumber(const MathStructure & vargs,bool allow_units) const160 bool SinFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && ((allow_units && (vargs[0].representsNumber(true) || vargs[0].representsNonComplex(true))) || (!allow_units && is_number_angle_value(vargs[0], true)));}
representsReal(const MathStructure & vargs,bool) const161 bool SinFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && (is_real_angle_value(vargs[0]) || is_infinite_angle_value(vargs[0]));}
representsNonComplex(const MathStructure & vargs,bool) const162 bool SinFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex(true);}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)163 int SinFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
164 
165 	if(vargs[0].isVector()) return 0;
166 	if(CALCULATOR->getRadUnit()) {
167 		if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getRadUnit()) {
168 			mstruct = vargs[0][0];
169 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getRadUnit()) {
170 			mstruct = vargs[0][1];
171 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getDegUnit()) {
172 			mstruct = vargs[0][0];
173 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
174 			mstruct.multiply(Number(1, 180), true);
175 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getDegUnit()) {
176 			mstruct = vargs[0][1];
177 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
178 			mstruct.multiply(Number(1, 180), true);
179 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getGraUnit()) {
180 			mstruct = vargs[0][0];
181 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
182 			mstruct.multiply(Number(1, 200), true);
183 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getGraUnit()) {
184 			mstruct = vargs[0][1];
185 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
186 			mstruct.multiply(Number(1, 200), true);
187 		} else {
188 			mstruct = vargs[0];
189 			mstruct.convert(CALCULATOR->getRadUnit());
190 			mstruct /= CALCULATOR->getRadUnit();
191 		}
192 	} else {
193 		mstruct = vargs[0];
194 	}
195 
196 	MathFunction *f = NULL;
197 	if(eo.approximation == APPROXIMATION_APPROXIMATE && (eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES || eo.parse_options.angle_unit == ANGLE_UNIT_GRADIANS)) {
198 		if(mstruct.isMultiplication() && mstruct.size() == 3 && mstruct[0].isFunction() && mstruct[0].size() == 1 && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI && mstruct[2].isNumber() && mstruct[2].number().equals(Number(1, eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES ? 180 : 200))) {
199 			f = mstruct[0].function();
200 		}
201 	}
202 
203 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
204 		EvaluationOptions eo2 = eo;
205 		eo2.approximation = APPROXIMATION_EXACT;
206 		CALCULATOR->beginTemporaryStopMessages();
207 		mstruct.eval(eo2);
208 	} else if(!f) {
209 		mstruct.eval(eo);
210 	}
211 
212 	if(mstruct.isVector()) {
213 		if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
214 		if(CALCULATOR->getRadUnit()) {
215 			for(size_t i = 0; i < mstruct.size(); i++) {
216 				mstruct[i] *= CALCULATOR->getRadUnit();
217 			}
218 		}
219 		return -1;
220 	}
221 
222 	bool b = false, b_recalc = true;
223 
224 	if(eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES || eo.parse_options.angle_unit == ANGLE_UNIT_GRADIANS) {
225 		if(!f && mstruct.isMultiplication() && mstruct.size() == 3 && mstruct[2].isFunction() && mstruct[2].size() == 1 && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI && mstruct[0].isNumber() && mstruct[0].number().equals(Number(1, eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES ? 180 : 200))) {
226 			f = mstruct[2].function();
227 		}
228 	} else if(mstruct.isFunction() && mstruct.size() == 1) {
229 		f = mstruct.function();
230 	}
231 
232 	if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_PI) {
233 		mstruct.clear();
234 		b = true;
235 	} else if(f) {
236 		if(f->id() == FUNCTION_ID_ASIN) {
237 			if(!mstruct.isFunction()) mstruct.setToChild(mstruct[0].isFunction() ? 1 : 3, true);
238 			mstruct.setToChild(1, true);
239 			b = true;
240 		} else if(f->id() == FUNCTION_ID_ACOS) {
241 			if(!mstruct.isFunction()) mstruct.setToChild(mstruct[0].isFunction() ? 1 : 3, true);
242 			mstruct.setToChild(1);
243 			mstruct ^= nr_two;
244 			mstruct.negate();
245 			mstruct += nr_one;
246 			mstruct ^= nr_half;
247 			b = true;
248 		} else if(f->id() == FUNCTION_ID_ATAN && (mstruct.isFunction() ? !mstruct[0].containsInterval(eo.approximation == APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true) : (mstruct[2].isFunction() ? !mstruct[2][0].containsInterval(eo.approximation == APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true) : !mstruct[0][0].containsInterval(eo.approximation == APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true)))) {
249 			if(!mstruct.isFunction()) mstruct.setToChild(mstruct[0].isFunction() ? 1 : 3, true);
250 			mstruct.setToChild(1);
251 			MathStructure *mmul = new MathStructure(mstruct);
252 			mstruct ^= nr_two;
253 			mstruct += nr_one;
254 			mstruct ^= nr_minus_half;
255 			mstruct.multiply_nocopy(mmul);
256 			b = true;
257 		}
258 	} else if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isNumber() && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI) {
259 		if(mstruct[0].number().isInteger()) {
260 			mstruct.clear();
261 			b = true;
262 		} else if(!mstruct[0].number().hasImaginaryPart() && !mstruct[0].number().includesInfinity() && !mstruct[0].number().isInterval()) {
263 			Number nr(mstruct[0].number());
264 			nr.frac();
265 			Number nr_int(mstruct[0].number());
266 			nr_int.floor();
267 			bool b_even = nr_int.isEven();
268 			nr.setNegative(false);
269 			if(nr.equals(Number(1, 2, 0))) {
270 				if(b_even) mstruct.set(1, 1, 0);
271 				else mstruct.set(-1, 1, 0);
272 				b = true;
273 			} else if(nr.equals(Number(1, 4, 0)) || nr.equals(Number(3, 4, 0))) {
274 				mstruct.set(2, 1, 0);
275 				mstruct.raise_nocopy(new MathStructure(1, 2, 0));
276 				mstruct.divide_nocopy(new MathStructure(2, 1, 0));
277 				if(!b_even) mstruct.negate();
278 				b = true;
279 			} else if(nr.equals(Number(1, 3, 0)) || nr.equals(Number(2, 3, 0))) {
280 				mstruct.set(3, 1, 0);
281 				mstruct.raise_nocopy(new MathStructure(1, 2, 0));
282 				mstruct.divide_nocopy(new MathStructure(2, 1, 0));
283 				if(!b_even) mstruct.negate();
284 				b = true;
285 			} else if(nr.equals(Number(1, 6, 0)) || nr.equals(Number(5, 6, 0))) {
286 				if(b_even) mstruct.set(1, 2, 0);
287 				else mstruct.set(-1, 2, 0);
288 				b = true;
289 			} else if(eo.approximation == APPROXIMATION_EXACT && (mstruct[0].number().isNegative() || !mstruct[0].number().isFraction() || mstruct[0].number().isGreaterThan(nr_half))) {
290 				nr_int = mstruct[0].number();
291 				nr_int.floor();
292 				Number nr_frac = mstruct[0].number();
293 				nr_frac -= nr_int;
294 				if(nr_frac.isGreaterThan(nr_half)) {
295 					nr_frac -= nr_half;
296 					mstruct[0].number() = nr_half;
297 					mstruct[0].number() -= nr_frac;
298 				} else {
299 					mstruct[0].number() = nr_frac;
300 				}
301 				if(nr_int.isOdd()) {
302 					if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();
303 					mstruct.transform(this);
304 					mstruct.negate();
305 					b = true;
306 				}
307 			}
308 		}
309 	} else if(mstruct.isMultiplication() && mstruct.size() >= 2) {
310 		bool b_pi = false;
311 		for(size_t i = 0; i < mstruct.size(); i++) {
312 			if(mstruct[i].isVariable() && mstruct[i].variable()->id() == VARIABLE_ID_PI) {
313 				b_pi = !b_pi;
314 				if(!b_pi) break;
315 			} else if(!mstruct[i].representsInteger()) {
316 				b_pi = false;
317 				break;
318 			}
319 		}
320 		if(b_pi) {
321 			mstruct.clear();
322 			b = true;
323 		}
324 	} else if(mstruct.isAddition()) {
325 		size_t i = 0;
326 		bool b_negate = false;
327 		for(; i < mstruct.size(); i++) {
328 			if((mstruct[i].isVariable() && mstruct[i].variable()->id() == VARIABLE_ID_PI) || (mstruct[i].isMultiplication() && mstruct[i].size() == 2 && mstruct[i][1].isVariable() && mstruct[i][1].variable()->id() == VARIABLE_ID_PI && mstruct[i][0].isNumber())) {
329 				if(mstruct[i].isVariable() || mstruct[i][0].number().isInteger()) {
330 					b_negate = mstruct[i].isVariable() || mstruct[i][0].number().isOdd();
331 					mstruct.delChild(i + 1);
332 					b_recalc = false;
333 					break;
334 				} else if(mstruct[i][0].number().isReal() && (mstruct[i][0].number().isNegative() || !mstruct[i][0].number().isFraction())) {
335 					Number nr_int = mstruct[i][0].number();
336 					nr_int.floor();
337 					mstruct[i][0].number() -= nr_int;
338 					b_negate = nr_int.isOdd();
339 					b_recalc = false;
340 					break;
341 				}
342 			}
343 		}
344 		b = b_negate;
345 		if(b_negate) {
346 			if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();
347 			mstruct.transform(this);
348 			mstruct.negate();
349 		}
350 	}
351 	if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(b);
352 	if(b) return 1;
353 	if(eo.approximation == APPROXIMATION_TRY_EXACT && !mstruct.isNumber()) {
354 		EvaluationOptions eo2 = eo;
355 		eo2.approximation = APPROXIMATION_APPROXIMATE;
356 		if(b_recalc) {
357 			mstruct = vargs[0];
358 			if(CALCULATOR->getRadUnit()) {
359 				mstruct.convert(CALCULATOR->getRadUnit());
360 				mstruct /= CALCULATOR->getRadUnit();
361 			}
362 		}
363 		mstruct.eval(eo2);
364 	}
365 
366 	if(mstruct.isNumber()) {
367 		Number nr(mstruct.number());
368 		if(nr.sin() && !(eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) && !(!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) && !(!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
369 			mstruct.set(nr, true);
370 			return 1;
371 		}
372 	}
373 
374 	if(trig_remove_i(mstruct)) {
375 		mstruct.transformById(FUNCTION_ID_SINH);
376 		mstruct *= nr_one_i;
377 		return 1;
378 	}
379 
380 	if(has_predominately_negative_sign(mstruct)) {
381 		negate_struct(mstruct);
382 		if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();
383 		mstruct.transform(this);
384 		mstruct.negate();
385 		return 1;
386 	}
387 
388 
389 	if(CALCULATOR->getRadUnit()) {
390 		if(mstruct.isVector()) {
391 			for(size_t i = 0; i < mstruct.size(); i++) {
392 				mstruct[i] *= CALCULATOR->getRadUnit();
393 			}
394 		} else {
395 			mstruct *= CALCULATOR->getRadUnit();
396 		}
397 	}
398 	return -1;
399 }
400 
CosFunction()401 CosFunction::CosFunction() : MathFunction("cos", 1) {
402 	Argument *arg = new AngleArgument();
403 	arg->setHandleVector(true);
404 	setArgumentDefinition(1, arg);
405 }
representsNumber(const MathStructure & vargs,bool allow_units) const406 bool CosFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && ((allow_units && (vargs[0].representsNumber(true) || vargs[0].representsNonComplex(true))) || (!allow_units && is_number_angle_value(vargs[0], true)));}
representsReal(const MathStructure & vargs,bool) const407 bool CosFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && (is_real_angle_value(vargs[0]) || is_infinite_angle_value(vargs[0]));}
representsNonComplex(const MathStructure & vargs,bool) const408 bool CosFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex(true);}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)409 int CosFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
410 
411 	if(vargs[0].isVector()) return 0;
412 	if(CALCULATOR->getRadUnit()) {
413 		if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getRadUnit()) {
414 			mstruct = vargs[0][0];
415 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getRadUnit()) {
416 			mstruct = vargs[0][1];
417 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getDegUnit()) {
418 			mstruct = vargs[0][0];
419 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
420 			mstruct.multiply(Number(1, 180), true);
421 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getDegUnit()) {
422 			mstruct = vargs[0][1];
423 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
424 			mstruct.multiply(Number(1, 180), true);
425 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getGraUnit()) {
426 			mstruct = vargs[0][0];
427 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
428 			mstruct.multiply(Number(1, 200), true);
429 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getGraUnit()) {
430 			mstruct = vargs[0][1];
431 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
432 			mstruct.multiply(Number(1, 200), true);
433 		} else {
434 			mstruct = vargs[0];
435 			mstruct.convert(CALCULATOR->getRadUnit());
436 			mstruct /= CALCULATOR->getRadUnit();
437 		}
438 	} else {
439 		mstruct = vargs[0];
440 	}
441 
442 	MathFunction *f = NULL;
443 	if(eo.approximation == APPROXIMATION_APPROXIMATE && (eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES || eo.parse_options.angle_unit == ANGLE_UNIT_GRADIANS)) {
444 		if(mstruct.isMultiplication() && mstruct.size() == 3 && mstruct[0].isFunction() && mstruct[0].size() == 1 && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI && mstruct[2].isNumber() && mstruct[2].number().equals(Number(1, eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES ? 180 : 200))) {
445 			f = mstruct[0].function();
446 		}
447 	}
448 
449 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
450 		EvaluationOptions eo2 = eo;
451 		eo2.approximation = APPROXIMATION_EXACT;
452 		CALCULATOR->beginTemporaryStopMessages();
453 		mstruct.eval(eo2);
454 	} else if(!f) {
455 		mstruct.eval(eo);
456 	}
457 
458 	if(mstruct.isVector()) {
459 		if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
460 		if(CALCULATOR->getRadUnit()) {
461 			for(size_t i = 0; i < mstruct.size(); i++) {
462 				mstruct[i] *= CALCULATOR->getRadUnit();
463 			}
464 		}
465 		return -1;
466 	}
467 
468 	bool b = false, b_recalc = true;
469 
470 	if(eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES || eo.parse_options.angle_unit == ANGLE_UNIT_GRADIANS) {
471 		if(!f && mstruct.isMultiplication() && mstruct.size() == 3 && mstruct[2].isFunction() && mstruct[2].size() == 1 && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI && mstruct[0].isNumber() && mstruct[0].number().equals(Number(1, eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES ? 180 : 200))) {
472 			f = mstruct[2].function();
473 		}
474 	} else if(mstruct.isFunction() && mstruct.size() == 1) {
475 		f = mstruct.function();
476 	}
477 
478 	if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_PI) {
479 		mstruct = -1;
480 		b = true;
481 	} else if(f) {
482 		if(f->id() == FUNCTION_ID_ACOS) {
483 			if(!mstruct.isFunction()) mstruct.setToChild(mstruct[0].isFunction() ? 1 : 3, true);
484 			mstruct.setToChild(1, true);
485 			b = true;
486 		} else if(f->id() == FUNCTION_ID_ASIN) {
487 			if(!mstruct.isFunction()) mstruct.setToChild(mstruct[0].isFunction() ? 1 : 3, true);
488 			mstruct.setToChild(1);
489 			mstruct ^= nr_two;
490 			mstruct.negate();
491 			mstruct += nr_one;
492 			mstruct ^= nr_half;
493 			b = true;
494 		} else if(f->id() == FUNCTION_ID_ATAN) {
495 			if(!mstruct.isFunction()) mstruct.setToChild(mstruct[0].isFunction() ? 1 : 3, true);
496 			mstruct.setToChild(1);
497 			mstruct ^= nr_two;
498 			mstruct += nr_one;
499 			mstruct ^= nr_minus_half;
500 			b = true;
501 		}
502 	} else if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isNumber() && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI) {
503 		if(mstruct[0].number().isInteger()) {
504 			if(mstruct[0].number().isEven()) {
505 				mstruct = 1;
506 			} else {
507 				mstruct = -1;
508 			}
509 			b = true;
510 		} else if(!mstruct[0].number().hasImaginaryPart() && !mstruct[0].number().includesInfinity() && !mstruct[0].number().isInterval()) {
511 			Number nr(mstruct[0].number());
512 			nr.frac();
513 			Number nr_int(mstruct[0].number());
514 			nr_int.trunc();
515 			bool b_even = nr_int.isEven();
516 			nr.setNegative(false);
517 			if(nr.equals(Number(1, 2, 0))) {
518 				mstruct.clear();
519 				b = true;
520 			} else if(nr.equals(Number(1, 4, 0))) {
521 				mstruct.set(2, 1, 0);
522 				mstruct.raise_nocopy(new MathStructure(1, 2, 0));
523 				mstruct.divide_nocopy(new MathStructure(2, 1, 0));
524 				if(!b_even) mstruct.negate();
525 				b = true;
526 			} else if(nr.equals(Number(3, 4, 0))) {
527 				mstruct.set(2, 1, 0);
528 				mstruct.raise_nocopy(new MathStructure(1, 2, 0));
529 				mstruct.divide_nocopy(new MathStructure(2, 1, 0));
530 				if(b_even) mstruct.negate();
531 				b = true;
532 			} else if(nr.equals(Number(1, 3, 0))) {
533 				if(b_even) mstruct.set(1, 2, 0);
534 				else mstruct.set(-1, 2, 0);
535 				b = true;
536 			} else if(nr.equals(Number(2, 3, 0))) {
537 				if(b_even) mstruct.set(-1, 2, 0);
538 				else mstruct.set(1, 2, 0);
539 				b = true;
540 			} else if(nr.equals(Number(1, 6, 0))) {
541 				mstruct.set(3, 1, 0);
542 				mstruct.raise_nocopy(new MathStructure(1, 2, 0));
543 				mstruct.divide_nocopy(new MathStructure(2, 1, 0));
544 				if(!b_even) mstruct.negate();
545 				b = true;
546 			} else if(nr.equals(Number(5, 6, 0))) {
547 				mstruct.set(3, 1, 0);
548 				mstruct.raise_nocopy(new MathStructure(1, 2, 0));
549 				mstruct.divide_nocopy(new MathStructure(2, 1, 0));
550 				if(b_even) mstruct.negate();
551 				b = true;
552 			} else if(eo.approximation == APPROXIMATION_EXACT && (mstruct[0].number().isNegative() || !mstruct[0].number().isFraction() || mstruct[0].number().isGreaterThan(nr_half))) {
553 				nr_int = mstruct[0].number();
554 				nr_int.floor();
555 				Number nr_frac = mstruct[0].number();
556 				nr_frac -= nr_int;
557 				if(nr_frac.isGreaterThan(nr_half)) {
558 					nr_frac -= nr_half;
559 					mstruct[0].number() = nr_half;
560 					mstruct[0].number() -= nr_frac;
561 					nr_int++;
562 				} else {
563 					mstruct[0].number() = nr_frac;
564 				}
565 				if(nr_int.isOdd()) {
566 					if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();
567 					mstruct.transform(this);
568 					mstruct.negate();
569 					b = true;
570 				}
571 			}
572 		}
573 	} else if(mstruct.isAddition()) {
574 		size_t i = 0;
575 		bool b_negate = false;
576 		for(; i < mstruct.size(); i++) {
577 			if((mstruct[i].isVariable() && mstruct[i].variable()->id() == VARIABLE_ID_PI) || (mstruct[i].isMultiplication() && mstruct[i].size() == 2 && mstruct[i][1].isVariable() && mstruct[i][1].variable()->id() == VARIABLE_ID_PI && mstruct[i][0].isNumber())) {
578 				if(mstruct[i].isVariable() || mstruct[i][0].number().isInteger()) {
579 					b_negate = mstruct[i].isVariable() || mstruct[i][0].number().isOdd();
580 					mstruct.delChild(i + 1);
581 					b_recalc = false;
582 					break;
583 				} else if(mstruct[i][0].number().isReal() && (mstruct[i][0].number().isNegative() || !mstruct[i][0].number().isFraction())) {
584 					Number nr_int = mstruct[i][0].number();
585 					nr_int.floor();
586 					mstruct[i][0].number() -= nr_int;
587 					b_negate = nr_int.isOdd();
588 					b_recalc = false;
589 					break;
590 				}
591 			}
592 		}
593 		b = b_negate;
594 		if(b_negate) {
595 			if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();
596 			mstruct.transform(this);
597 			mstruct.negate();
598 		}
599 	}
600 	if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(b);
601 	if(b) return 1;
602 	if(eo.approximation == APPROXIMATION_TRY_EXACT && !mstruct.isNumber()) {
603 		EvaluationOptions eo2 = eo;
604 		eo2.approximation = APPROXIMATION_APPROXIMATE;
605 		if(b_recalc) {
606 			mstruct = vargs[0];
607 			if(CALCULATOR->getRadUnit()) {
608 				mstruct.convert(CALCULATOR->getRadUnit());
609 				mstruct /= CALCULATOR->getRadUnit();
610 			}
611 		}
612 		mstruct.eval(eo2);
613 	}
614 	if(mstruct.isNumber()) {
615 		Number nr(mstruct.number());
616 		if(nr.cos() && !(eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) && !(!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) && !(!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
617 			mstruct.set(nr, true);
618 			return 1;
619 		}
620 	}
621 	if(trig_remove_i(mstruct)) {
622 		mstruct.transformById(FUNCTION_ID_COSH);
623 		return 1;
624 	}
625 	if(has_predominately_negative_sign(mstruct)) {
626 		negate_struct(mstruct);
627 	}
628 	if(CALCULATOR->getRadUnit()) {
629 		if(mstruct.isVector()) {
630 			for(size_t i = 0; i < mstruct.size(); i++) {
631 				mstruct[i] *= CALCULATOR->getRadUnit();
632 			}
633 		} else {
634 			mstruct *= CALCULATOR->getRadUnit();
635 		}
636 	}
637 	return -1;
638 }
639 
TanFunction()640 TanFunction::TanFunction() : MathFunction("tan", 1) {
641 	Argument *arg = new AngleArgument();
642 	arg->setHandleVector(true);
643 	setArgumentDefinition(1, arg);
644 }
representsNumber(const MathStructure &,bool) const645 bool TanFunction::representsNumber(const MathStructure&, bool) const {return false;}
representsReal(const MathStructure &,bool) const646 bool TanFunction::representsReal(const MathStructure&, bool) const {return false;}
representsNonComplex(const MathStructure & vargs,bool) const647 bool TanFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex(true);}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)648 int TanFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
649 
650 	if(vargs[0].isVector()) return 0;
651 	if(CALCULATOR->getRadUnit()) {
652 		if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getRadUnit()) {
653 			mstruct = vargs[0][0];
654 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getRadUnit()) {
655 			mstruct = vargs[0][1];
656 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getDegUnit()) {
657 			mstruct = vargs[0][0];
658 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
659 			mstruct.multiply(Number(1, 180), true);
660 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getDegUnit()) {
661 			mstruct = vargs[0][1];
662 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
663 			mstruct.multiply(Number(1, 180), true);
664 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][1] == CALCULATOR->getGraUnit()) {
665 			mstruct = vargs[0][0];
666 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
667 			mstruct.multiply(Number(1, 200), true);
668 		} else if(vargs[0].isMultiplication() && vargs[0].size() == 2 && vargs[0][0] == CALCULATOR->getGraUnit()) {
669 			mstruct = vargs[0][1];
670 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
671 			mstruct.multiply(Number(1, 200), true);
672 		} else {
673 			mstruct = vargs[0];
674 			mstruct.convert(CALCULATOR->getRadUnit());
675 			mstruct /= CALCULATOR->getRadUnit();
676 		}
677 	} else {
678 		mstruct = vargs[0];
679 	}
680 
681 	MathFunction *f = NULL;
682 	if(eo.approximation == APPROXIMATION_APPROXIMATE && (eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES || eo.parse_options.angle_unit == ANGLE_UNIT_GRADIANS)) {
683 		if(mstruct.isMultiplication() && mstruct.size() == 3 && mstruct[0].isFunction() && mstruct[0].size() == 1 && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI && mstruct[2].isNumber() && mstruct[2].number().equals(Number(1, eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES ? 180 : 200))) {
684 			f = mstruct[0].function();
685 		}
686 	}
687 
688 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
689 		EvaluationOptions eo2 = eo;
690 		eo2.approximation = APPROXIMATION_EXACT;
691 		CALCULATOR->beginTemporaryStopMessages();
692 		mstruct.eval(eo2);
693 	} else if(!f) {
694 		mstruct.eval(eo);
695 	}
696 
697 	if(mstruct.isVector()) {
698 		if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
699 		if(CALCULATOR->getRadUnit()) {
700 			for(size_t i = 0; i < mstruct.size(); i++) {
701 				mstruct[i] *= CALCULATOR->getRadUnit();
702 			}
703 		}
704 		return -1;
705 	}
706 
707 	bool b = false, b_recalc = true;
708 
709 	if(eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES || eo.parse_options.angle_unit == ANGLE_UNIT_GRADIANS) {
710 		if(!f && mstruct.isMultiplication() && mstruct.size() == 3 && mstruct[2].isFunction() && mstruct[2].size() == 1 && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI && mstruct[0].isNumber() && mstruct[0].number().equals(Number(1, eo.parse_options.angle_unit == ANGLE_UNIT_DEGREES ? 180 : 200))) {
711 			f = mstruct[2].function();
712 		}
713 	} else if(mstruct.isFunction() && mstruct.size() == 1) {
714 		f = mstruct.function();
715 	}
716 
717 	if(mstruct.isVariable() && mstruct.variable()->id() == VARIABLE_ID_PI) {
718 		mstruct.clear();
719 		b = true;
720 	} else if(f) {
721 		if(f->id() == FUNCTION_ID_ATAN) {
722 			if(!mstruct.isFunction()) mstruct.setToChild(mstruct[0].isFunction() ? 1 : 3, true);
723 			mstruct.setToChild(1, true);
724 			b = true;
725 		} else if(f->id() == FUNCTION_ID_ASIN && (mstruct.isFunction() ? !mstruct[0].containsInterval(eo.approximation == APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true) : (mstruct[2].isFunction() ? !mstruct[2][0].containsInterval(eo.approximation == APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true) : !mstruct[0][0].containsInterval(eo.approximation == APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true)))) {
726 			if(!mstruct.isFunction()) mstruct.setToChild(mstruct[0].isFunction() ? 1 : 3, true);
727 			mstruct.setToChild(1);
728 			MathStructure *mmul = new MathStructure(mstruct);
729 			mstruct ^= nr_two;
730 			mstruct.negate();
731 			mstruct += nr_one;
732 			mstruct ^= nr_minus_half;
733 			mstruct.multiply_nocopy(mmul);
734 			b = true;
735 		} else if(f->id() == FUNCTION_ID_ACOS && (mstruct.isFunction() ? !mstruct[0].containsInterval(eo.approximation == APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true) : (mstruct[2].isFunction() ? !mstruct[2][0].containsInterval(eo.approximation == APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true) : !mstruct[0][0].containsInterval(eo.approximation == APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation != APPROXIMATION_EXACT, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true)))) {
736 			if(!mstruct.isFunction()) mstruct.setToChild(mstruct[0].isFunction() ? 1 : 3, true);
737 			mstruct.setToChild(1);
738 			MathStructure *mmul = new MathStructure(mstruct);
739 			mstruct ^= nr_two;
740 			mstruct.negate();
741 			mstruct += nr_one;
742 			mstruct ^= nr_half;
743 			mstruct.divide_nocopy(mmul);
744 			b = true;
745 		}
746 	} else if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isNumber() && mstruct[1].isVariable() && mstruct[1].variable()->id() == VARIABLE_ID_PI) {
747 		if(mstruct[0].number().isInteger()) {
748 			mstruct.clear();
749 			b = true;
750 		} else if(!mstruct[0].number().hasImaginaryPart() && !mstruct[0].number().includesInfinity() && !mstruct[0].number().isInterval()) {
751 			Number nr(mstruct[0].number());
752 			nr.frac();
753 			bool b_neg = nr.isNegative();
754 			nr.setNegative(false);
755 			if(nr.equals(nr_half)) {
756 				if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
757 				if(!mstruct[0].number().numeratorIsOne() && !mstruct[0].number().numeratorEquals(3)) {
758 					Number nr_int(mstruct[0].number());
759 					nr_int.floor();
760 					bool b_even = nr_int.isEven();
761 					if(b_even) mstruct[0].set(nr_half, true);
762 					else mstruct[0].set(Number(3, 2), true);
763 					mstruct.childUpdated(1);
764 				}
765 				if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();
766 				return -1;
767 			} else if(nr.equals(Number(1, 4, 0))) {
768 				if(b_neg) mstruct.set(-1, 1, 0);
769 				else mstruct.set(1, 1, 0);
770 				b = true;
771 			} else if(nr.equals(Number(3, 4, 0))) {
772 				if(!b_neg) mstruct.set(-1, 1, 0);
773 				else mstruct.set(1, 1, 0);
774 				b = true;
775 			} else if(nr.equals(Number(1, 3, 0))) {
776 				mstruct.set(3, 1, 0);
777 				mstruct.raise_nocopy(new MathStructure(1, 2, 0));
778 				if(b_neg) mstruct.negate();
779 				b = true;
780 			} else if(nr.equals(Number(2, 3, 0))) {
781 				mstruct.set(3, 1, 0);
782 				mstruct.raise_nocopy(new MathStructure(1, 2, 0));
783 				if(!b_neg) mstruct.negate();
784 				b = true;
785 			} else if(nr.equals(Number(1, 6, 0))) {
786 				mstruct.set(3, 1, 0);
787 				mstruct.raise_nocopy(new MathStructure(-1, 2, 0));
788 				if(b_neg) mstruct.negate();
789 				b = true;
790 			} else if(nr.equals(Number(5, 6, 0))) {
791 				mstruct.set(3, 1, 0);
792 				mstruct.raise_nocopy(new MathStructure(-1, 2, 0));
793 				if(!b_neg) mstruct.negate();
794 				b = true;
795 			} else if(eo.approximation == APPROXIMATION_EXACT && (mstruct[0].number().isNegative() || !mstruct[0].number().isFraction() || mstruct[0].number().isGreaterThan(nr_half))) {
796 				Number nr_int(mstruct[0].number());
797 				nr_int.floor();
798 				Number nr_frac = mstruct[0].number();
799 				nr_frac -= nr_int;
800 				if(nr_frac.isGreaterThan(nr_half)) {
801 					nr_frac -= nr_half;
802 					mstruct[0].number() = nr_half;
803 					mstruct[0].number() -= nr_frac;
804 					if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();
805 					mstruct.transform(this);
806 					mstruct.negate();
807 					b = true;
808 				} else {
809 					mstruct[0].number() = nr_frac;
810 				}
811 			}
812 		}
813 	} else if(mstruct.isMultiplication() && mstruct.size() >= 2) {
814 		bool b_pi = false;
815 		for(size_t i = 0; i < mstruct.size(); i++) {
816 			if(mstruct[i].isVariable() && mstruct[i].variable()->id() == VARIABLE_ID_PI) {
817 				b_pi = !b_pi;
818 				if(!b_pi) break;
819 			} else if(!mstruct[i].representsInteger()) {
820 				b_pi = false;
821 				break;
822 			}
823 		}
824 		if(b_pi) {
825 			mstruct.clear();
826 			b = true;
827 		}
828 	} else if(mstruct.isAddition()) {
829 		size_t i = 0;
830 		for(; i < mstruct.size(); i++) {
831 			if((mstruct[i].isVariable() && mstruct[i].variable()->id() == VARIABLE_ID_PI) || (mstruct[i].isMultiplication() && mstruct[i].size() == 2 && mstruct[i][1].isVariable() && mstruct[i][1].variable()->id() == VARIABLE_ID_PI && mstruct[i][0].isNumber())) {
832 				if(mstruct[i].isVariable() || mstruct[i][0].number().isInteger()) {
833 					mstruct.delChild(i + 1);
834 					b_recalc = false;
835 					break;
836 				} else if(mstruct[i][0].number().isReal() && (mstruct[i][0].number().isNegative() || !mstruct[i][0].number().isFraction())) {
837 					Number nr_int = mstruct[i][0].number();
838 					nr_int.floor();
839 					mstruct[i][0].number() -= nr_int;
840 					b_recalc = false;
841 					break;
842 				}
843 			}
844 		}
845 	}
846 	if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(b);
847 	if(b) return 1;
848 	if(eo.approximation == APPROXIMATION_TRY_EXACT && !mstruct.isNumber()) {
849 		EvaluationOptions eo2 = eo;
850 		eo2.approximation = APPROXIMATION_APPROXIMATE;
851 		if(b_recalc) {
852 			mstruct = vargs[0];
853 			if(CALCULATOR->getRadUnit()) {
854 				mstruct.convert(CALCULATOR->getRadUnit());
855 				mstruct /= CALCULATOR->getRadUnit();
856 			}
857 			mstruct.eval(eo2);
858 		}
859 	}
860 
861 	if(mstruct.isNumber()) {
862 		Number nr(mstruct.number());
863 		if(nr.tan() && !(eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) && !(!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) && !(!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
864 			mstruct.set(nr, true);
865 			return 1;
866 		}
867 	}
868 
869 	if(trig_remove_i(mstruct)) {
870 		mstruct.transformById(FUNCTION_ID_TANH);
871 		mstruct *= nr_one_i;
872 		return 1;
873 	}
874 
875 	if(has_predominately_negative_sign(mstruct)) {
876 		negate_struct(mstruct);
877 		if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();
878 		mstruct.transform(this);
879 		mstruct.negate();
880 		return 1;
881 	}
882 
883 	if(CALCULATOR->getRadUnit()) {
884 		if(mstruct.isVector()) {
885 			for(size_t i = 0; i < mstruct.size(); i++) {
886 				mstruct[i] *= CALCULATOR->getRadUnit();
887 			}
888 		} else {
889 			mstruct *= CALCULATOR->getRadUnit();
890 		}
891 	}
892 
893 	return -1;
894 }
895 
AsinFunction()896 AsinFunction::AsinFunction() : MathFunction("asin", 1) {
897 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
898 }
representsNumber(const MathStructure & vargs,bool allow_units) const899 bool AsinFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)900 int AsinFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
901 	if(vargs[0].isVector()) return 0;
902 	mstruct = vargs[0];
903 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
904 		EvaluationOptions eo2 = eo;
905 		eo2.approximation = APPROXIMATION_EXACT;
906 		CALCULATOR->beginTemporaryStopMessages();
907 		mstruct.eval(eo2);
908 	} else {
909 		mstruct.eval(eo);
910 	}
911 	if(mstruct.isVector()) {
912 		if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
913 		return -1;
914 	}
915 	if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0] == nr_half && mstruct[1].isPower() && mstruct[1][1] == nr_half) {
916 		if(mstruct[1][0] == nr_two) {
917 			switch(eo.parse_options.angle_unit) {
918 				case ANGLE_UNIT_DEGREES: {mstruct.set(45, 1, 0); break;}
919 				case ANGLE_UNIT_GRADIANS: {mstruct.set(50, 1, 0); break;}
920 				case ANGLE_UNIT_RADIANS: {mstruct.set(1, 4, 0); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
921 				default: {mstruct.set(1, 4, 0);	mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();}}
922 			}
923 			if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
924 			return 1;
925 		} else if(mstruct[1][0] == nr_three) {
926 			switch(eo.parse_options.angle_unit) {
927 				case ANGLE_UNIT_DEGREES: {mstruct.set(60, 1, 0); break;}
928 				case ANGLE_UNIT_GRADIANS: {mstruct.set(200, 3, 0); break;}
929 				case ANGLE_UNIT_RADIANS: {mstruct.set(1, 3, 0); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
930 				default: {mstruct.set(1, 3, 0);	mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();}}
931 			}
932 			if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
933 			return 1;
934 		}
935 	} else if(mstruct.isPower() && mstruct[1] == nr_minus_half && mstruct[0] == nr_two) {
936 		switch(eo.parse_options.angle_unit) {
937 			case ANGLE_UNIT_DEGREES: {mstruct.set(45, 1, 0); break;}
938 			case ANGLE_UNIT_GRADIANS: {mstruct.set(50, 1, 0); break;}
939 			case ANGLE_UNIT_RADIANS: {mstruct.set(1, 4, 0); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
940 			default: {mstruct.set(1, 4, 0);	mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();}}
941 		}
942 		if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
943 		return 1;
944 	}
945 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
946 		if(!mstruct.isNumber()) {
947 			CALCULATOR->endTemporaryStopMessages(false);
948 			EvaluationOptions eo2 = eo;
949 			eo2.approximation = APPROXIMATION_APPROXIMATE;
950 			mstruct = vargs[0];
951 			mstruct.eval(eo2);
952 		} else {
953 			CALCULATOR->endTemporaryStopMessages(true);
954 		}
955 	}
956 	if(!mstruct.isNumber()) {
957 		if(trig_remove_i(mstruct)) {
958 			mstruct.transformById(FUNCTION_ID_ASINH);
959 			mstruct *= nr_one_i;
960 			switch(eo.parse_options.angle_unit) {
961 				case ANGLE_UNIT_DEGREES: {mstruct.multiply_nocopy(new MathStructure(180, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
962 				case ANGLE_UNIT_GRADIANS: {mstruct.multiply_nocopy(new MathStructure(200, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
963 				case ANGLE_UNIT_RADIANS: {break;}
964 				default: {if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();} break;}
965 			}
966 			return 1;
967 		}
968 		if(has_predominately_negative_sign(mstruct)) {negate_struct(mstruct); mstruct.transform(this); mstruct.negate(); return 1;}
969 		return -1;
970 	}
971 	if(mstruct.number().isZero()) {
972 		mstruct.clear();
973 	} else if(mstruct.number().isOne()) {
974 		switch(eo.parse_options.angle_unit) {
975 			case ANGLE_UNIT_DEGREES: {
976 				mstruct.set(90, 1, 0);
977 				break;
978 			}
979 			case ANGLE_UNIT_GRADIANS: {
980 				mstruct.set(100, 1, 0);
981 				break;
982 			}
983 			case ANGLE_UNIT_RADIANS: {
984 				mstruct.set(1, 2, 0);
985 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
986 				break;
987 			}
988 			default: {
989 				mstruct.set(1, 2, 0);
990 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
991 				if(CALCULATOR->getRadUnit()) {
992 					mstruct *= CALCULATOR->getRadUnit();
993 				}
994 			}
995 		}
996 	} else if(mstruct.number().isMinusOne()) {
997 		switch(eo.parse_options.angle_unit) {
998 			case ANGLE_UNIT_DEGREES: {
999 				mstruct.set(-90, 1, 0);
1000 				break;
1001 			}
1002 			case ANGLE_UNIT_GRADIANS: {
1003 				mstruct.set(-100, 1, 0);
1004 				break;
1005 			}
1006 			case ANGLE_UNIT_RADIANS: {
1007 				mstruct.set(-1, 2, 0);
1008 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1009 				break;
1010 			}
1011 			default: {
1012 				mstruct.set(-1, 2, 0);
1013 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1014 				if(CALCULATOR->getRadUnit()) {
1015 					mstruct *= CALCULATOR->getRadUnit();
1016 				}
1017 			}
1018 		}
1019 	} else if(mstruct.number().equals(nr_half)) {
1020 		switch(eo.parse_options.angle_unit) {
1021 			case ANGLE_UNIT_DEGREES: {
1022 				mstruct.set(30, 1, 0);
1023 				break;
1024 			}
1025 			case ANGLE_UNIT_GRADIANS: {
1026 				mstruct.set(100, 3, 0);
1027 				break;
1028 			}
1029 			case ANGLE_UNIT_RADIANS: {
1030 				mstruct.set(1, 6, 0);
1031 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1032 				break;
1033 			}
1034 			default: {
1035 				mstruct.set(1, 6, 0);
1036 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1037 				if(CALCULATOR->getRadUnit()) {
1038 					mstruct *= CALCULATOR->getRadUnit();
1039 				}
1040 			}
1041 		}
1042 	} else {
1043 		Number nr = mstruct.number();
1044 		if(!nr.asin() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) || (!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
1045 			if(trig_remove_i(mstruct)) {
1046 				mstruct.transformById(FUNCTION_ID_ASINH);
1047 				mstruct *= nr_one_i;
1048 				switch(eo.parse_options.angle_unit) {
1049 					case ANGLE_UNIT_DEGREES: {mstruct.multiply_nocopy(new MathStructure(180, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1050 					case ANGLE_UNIT_GRADIANS: {mstruct.multiply_nocopy(new MathStructure(200, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1051 					case ANGLE_UNIT_RADIANS: {break;}
1052 					default: {if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();} break;}
1053 				}
1054 				return 1;
1055 			}
1056 			if(has_predominately_negative_sign(mstruct)) {mstruct.number().negate(); mstruct.transform(this); mstruct.negate(); return 1;}
1057 			return -1;
1058 		}
1059 		mstruct = nr;
1060 		switch(eo.parse_options.angle_unit) {
1061 			case ANGLE_UNIT_DEGREES: {mstruct.multiply_nocopy(new MathStructure(180, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1062 			case ANGLE_UNIT_GRADIANS: {mstruct.multiply_nocopy(new MathStructure(200, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1063 			case ANGLE_UNIT_RADIANS: {break;}
1064 			default: {if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();} break;}
1065 		}
1066 	}
1067 	return 1;
1068 
1069 }
1070 
AcosFunction()1071 AcosFunction::AcosFunction() : MathFunction("acos", 1) {
1072 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
1073 }
representsNumber(const MathStructure & vargs,bool allow_units) const1074 bool AcosFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1075 int AcosFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1076 	if(vargs[0].isVector()) return 0;
1077 	mstruct = vargs[0];
1078 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
1079 		EvaluationOptions eo2 = eo;
1080 		eo2.approximation = APPROXIMATION_EXACT;
1081 		CALCULATOR->beginTemporaryStopMessages();
1082 		mstruct.eval(eo2);
1083 	} else {
1084 		mstruct.eval(eo);
1085 	}
1086 	if(mstruct.isVector()) {
1087 		if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
1088 		return -1;
1089 	}
1090 	if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0] == nr_half && mstruct[1].isPower() && mstruct[1][1] == nr_half) {
1091 		if(mstruct[1][0] == nr_two) {
1092 			switch(eo.parse_options.angle_unit) {
1093 				case ANGLE_UNIT_DEGREES: {mstruct.set(45, 1, 0); break;}
1094 				case ANGLE_UNIT_GRADIANS: {mstruct.set(50, 1, 0); break;}
1095 				case ANGLE_UNIT_RADIANS: {mstruct.set(1, 4, 0); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1096 				default: {mstruct.set(1, 4, 0);	mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();}}
1097 			}
1098 			if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
1099 			return 1;
1100 		} else if(mstruct[1][0] == nr_three) {
1101 			switch(eo.parse_options.angle_unit) {
1102 				case ANGLE_UNIT_DEGREES: {mstruct.set(30, 1, 0); break;}
1103 				case ANGLE_UNIT_GRADIANS: {mstruct.set(100, 3, 0); break;}
1104 				case ANGLE_UNIT_RADIANS: {mstruct.set(1, 6, 0); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1105 				default: {mstruct.set(1, 6, 0);	mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();}}
1106 			}
1107 			if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
1108 			return 1;
1109 		}
1110 	} else if(mstruct.isPower() && mstruct[1] == nr_minus_half && mstruct[0] == nr_two) {
1111 		switch(eo.parse_options.angle_unit) {
1112 			case ANGLE_UNIT_DEGREES: {mstruct.set(45, 1, 0); break;}
1113 			case ANGLE_UNIT_GRADIANS: {mstruct.set(50, 1, 0); break;}
1114 			case ANGLE_UNIT_RADIANS: {mstruct.set(1, 4, 0); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1115 			default: {mstruct.set(1, 4, 0);	mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();}}
1116 		}
1117 		if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
1118 		return 1;
1119 	}
1120 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
1121 		if(!mstruct.isNumber()) {
1122 			CALCULATOR->endTemporaryStopMessages(false);
1123 			EvaluationOptions eo2 = eo;
1124 			eo2.approximation = APPROXIMATION_APPROXIMATE;
1125 			mstruct = vargs[0];
1126 			mstruct.eval(eo2);
1127 		} else {
1128 			CALCULATOR->endTemporaryStopMessages(true);
1129 		}
1130 	}
1131 	if(!mstruct.isNumber()) {
1132 		if(has_predominately_negative_sign(mstruct)) {
1133 			negate_struct(mstruct); mstruct.transformById(FUNCTION_ID_ASIN);
1134 			switch(eo.parse_options.angle_unit) {
1135 				case ANGLE_UNIT_DEGREES: {mstruct += Number(90, 1, 0); break;}
1136 				case ANGLE_UNIT_GRADIANS: {mstruct += Number(100, 1, 0); break;}
1137 				case ANGLE_UNIT_RADIANS: {mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI); mstruct.last() *= nr_half; break;}
1138 				default: {mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI); mstruct.last() *= nr_half; if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();} break;}
1139 			}
1140 			return 1;
1141 		}
1142 		return -1;
1143 	}
1144 	if(mstruct.number().isZero()) {
1145 		switch(eo.parse_options.angle_unit) {
1146 			case ANGLE_UNIT_DEGREES: {
1147 				mstruct.set(90, 1, 0);
1148 				break;
1149 			}
1150 			case ANGLE_UNIT_GRADIANS: {
1151 				mstruct.set(100, 1, 0);
1152 				break;
1153 			}
1154 			case ANGLE_UNIT_RADIANS: {
1155 				mstruct.set(1, 2, 0);
1156 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1157 				break;
1158 			}
1159 			default: {
1160 				mstruct.set(1, 2, 0);
1161 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1162 				if(CALCULATOR->getRadUnit()) {
1163 					mstruct *= CALCULATOR->getRadUnit();
1164 				}
1165 			}
1166 		}
1167 	} else if(mstruct.number().isOne()) {
1168 		mstruct.clear();
1169 	} else if(mstruct.number().isMinusOne()) {
1170 		switch(eo.parse_options.angle_unit) {
1171 			case ANGLE_UNIT_DEGREES: {
1172 				mstruct.set(180, 1, 0);
1173 				break;
1174 			}
1175 			case ANGLE_UNIT_GRADIANS: {
1176 				mstruct.set(200, 1, 0);
1177 				break;
1178 			}
1179 			case ANGLE_UNIT_RADIANS: {
1180 				mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI));
1181 				break;
1182 			}
1183 			default: {
1184 				mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI));
1185 				if(CALCULATOR->getRadUnit()) {
1186 					mstruct *= CALCULATOR->getRadUnit();
1187 				}
1188 			}
1189 		}
1190 	} else if(mstruct.number().equals(nr_half)) {
1191 		switch(eo.parse_options.angle_unit) {
1192 			case ANGLE_UNIT_DEGREES: {
1193 				mstruct.set(60, 1, 0);
1194 				break;
1195 			}
1196 			case ANGLE_UNIT_GRADIANS: {
1197 				mstruct.set(200, 3, 0);
1198 				break;
1199 			}
1200 			case ANGLE_UNIT_RADIANS: {
1201 				mstruct.set(1, 3, 0);
1202 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1203 				break;
1204 			}
1205 			default: {
1206 				mstruct.set(1, 3, 0);
1207 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1208 				if(CALCULATOR->getRadUnit()) {
1209 					mstruct *= CALCULATOR->getRadUnit();
1210 				}
1211 			}
1212 		}
1213 	} else {
1214 		Number nr = mstruct.number();
1215 		if(!nr.acos() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) || (!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
1216 			if(has_predominately_negative_sign(mstruct)) {
1217 				mstruct.number().negate();
1218 				mstruct.transformById(FUNCTION_ID_ASIN);
1219 				switch(eo.parse_options.angle_unit) {
1220 					case ANGLE_UNIT_DEGREES: {mstruct += Number(90, 1, 0); break;}
1221 					case ANGLE_UNIT_GRADIANS: {mstruct += Number(100, 1, 0); break;}
1222 					case ANGLE_UNIT_RADIANS: {mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI); mstruct.last() *= nr_half; break;}
1223 					default: {mstruct += CALCULATOR->getVariableById(VARIABLE_ID_PI); mstruct.last() *= nr_half; if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();} break;}
1224 				}
1225 				return 1;
1226 			}
1227 			return -1;
1228 		}
1229 		mstruct = nr;
1230 		switch(eo.parse_options.angle_unit) {
1231 			case ANGLE_UNIT_DEGREES: {mstruct.multiply_nocopy(new MathStructure(180, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1232 			case ANGLE_UNIT_GRADIANS: {mstruct.multiply_nocopy(new MathStructure(200, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1233 			case ANGLE_UNIT_RADIANS: {break;}
1234 			default: {if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();} break;}
1235 		}
1236 	}
1237 	return 1;
1238 
1239 }
1240 
AtanFunction()1241 AtanFunction::AtanFunction() : MathFunction("atan", 1) {
1242 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
1243 }
representsNumber(const MathStructure & vargs,bool allow_units) const1244 bool AtanFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && (vargs[0].representsReal(allow_units) || (vargs[0].isNumber() && !vargs[0].number().isI() && !vargs[0].number().isMinusI()));}
representsReal(const MathStructure & vargs,bool) const1245 bool AtanFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const1246 bool AtanFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1247 int AtanFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1248 	if(vargs[0].isVector()) return 0;
1249 	mstruct = vargs[0];
1250 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
1251 		EvaluationOptions eo2 = eo;
1252 		eo2.approximation = APPROXIMATION_EXACT;
1253 		CALCULATOR->beginTemporaryStopMessages();
1254 		mstruct.eval(eo2);
1255 	} else {
1256 		mstruct.eval(eo);
1257 	}
1258 	if(mstruct.isVector()) {
1259 		if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
1260 		return -1;
1261 	}
1262 	if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isNumber() && mstruct[1].isPower() && mstruct[1][1] == nr_half && mstruct[1][0] == nr_three && mstruct[0].number() == Number(1, 3)) {
1263 		if(mstruct[1][0] == nr_three) {
1264 			switch(eo.parse_options.angle_unit) {
1265 				case ANGLE_UNIT_DEGREES: {mstruct.set(30, 1, 0); break;}
1266 				case ANGLE_UNIT_GRADIANS: {mstruct.set(100, 3, 0); break;}
1267 				case ANGLE_UNIT_RADIANS: {mstruct.set(1, 6, 0); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1268 				default: {mstruct.set(1, 6, 0);	mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();}}
1269 			}
1270 			if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
1271 			return 1;
1272 		}
1273 	} else if(mstruct.isPower() && mstruct[1] == nr_half && mstruct[0] == nr_three) {
1274 		switch(eo.parse_options.angle_unit) {
1275 			case ANGLE_UNIT_DEGREES: {mstruct.set(60, 1, 0); break;}
1276 			case ANGLE_UNIT_GRADIANS: {mstruct.set(200, 3, 0); break;}
1277 			case ANGLE_UNIT_RADIANS: {mstruct.set(1, 3, 0); mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1278 			default: {mstruct.set(1, 3, 0);	mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();}}
1279 		}
1280 		if(eo.approximation == APPROXIMATION_TRY_EXACT) CALCULATOR->endTemporaryStopMessages(true);
1281 		return 1;
1282 	}
1283 	if(eo.approximation == APPROXIMATION_TRY_EXACT) {
1284 		if(!mstruct.isNumber()) {
1285 			CALCULATOR->endTemporaryStopMessages(false);
1286 			EvaluationOptions eo2 = eo;
1287 			eo2.approximation = APPROXIMATION_APPROXIMATE;
1288 			mstruct = vargs[0];
1289 			mstruct.eval(eo2);
1290 		} else {
1291 			CALCULATOR->endTemporaryStopMessages(true);
1292 		}
1293 	}
1294 	if(!mstruct.isNumber()) {
1295 		if(trig_remove_i(mstruct)) {
1296 			mstruct.transformById(FUNCTION_ID_ATANH);
1297 			mstruct *= nr_one_i;
1298 			switch(eo.parse_options.angle_unit) {
1299 				case ANGLE_UNIT_DEGREES: {mstruct.multiply_nocopy(new MathStructure(180, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1300 				case ANGLE_UNIT_GRADIANS: {mstruct.multiply_nocopy(new MathStructure(200, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1301 				case ANGLE_UNIT_RADIANS: {break;}
1302 				default: {if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();} break;}
1303 			}
1304 			return 1;
1305 		}
1306 		if(has_predominately_negative_sign(mstruct)) {negate_struct(mstruct); mstruct.transform(this); mstruct.negate(); return 1;}
1307 		return -1;
1308 	}
1309 	if(mstruct.number().isZero()) {
1310 		mstruct.clear();
1311 	} else if(eo.allow_infinite && mstruct.number().isI()) {
1312 		Number nr; nr.setImaginaryPart(nr_plus_inf);
1313 		mstruct = nr;
1314 	} else if(eo.allow_infinite && mstruct.number().isMinusI()) {
1315 		Number nr; nr.setImaginaryPart(nr_minus_inf);
1316 		mstruct = nr;
1317 	} else if(mstruct.number().isPlusInfinity()) {
1318 		switch(eo.parse_options.angle_unit) {
1319 			case ANGLE_UNIT_DEGREES: {
1320 				mstruct.set(90, 1, 0);
1321 				break;
1322 			}
1323 			case ANGLE_UNIT_GRADIANS: {
1324 				mstruct.set(100, 1, 0);
1325 				break;
1326 			}
1327 			case ANGLE_UNIT_RADIANS: {
1328 				mstruct.set(1, 2, 0);
1329 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1330 				break;
1331 			}
1332 			default: {
1333 				mstruct.set(1, 2, 0);
1334 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1335 				if(CALCULATOR->getRadUnit()) {
1336 					mstruct *= CALCULATOR->getRadUnit();
1337 				}
1338 			}
1339 		}
1340 	} else if(mstruct.number().isMinusInfinity()) {
1341 		switch(eo.parse_options.angle_unit) {
1342 			case ANGLE_UNIT_DEGREES: {
1343 				mstruct.set(-90, 1, 0);
1344 				break;
1345 			}
1346 			case ANGLE_UNIT_GRADIANS: {
1347 				mstruct.set(-100, 1, 0);
1348 				break;
1349 			}
1350 			case ANGLE_UNIT_RADIANS: {
1351 				mstruct.set(-1, 2, 0);
1352 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1353 				break;
1354 			}
1355 			default: {
1356 				mstruct.set(-1, 2, 0);
1357 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1358 				if(CALCULATOR->getRadUnit()) {
1359 					mstruct *= CALCULATOR->getRadUnit();
1360 				}
1361 			}
1362 		}
1363 	} else if(mstruct.number().isOne()) {
1364 		switch(eo.parse_options.angle_unit) {
1365 			case ANGLE_UNIT_DEGREES: {
1366 				mstruct.set(45, 1, 0);
1367 				break;
1368 			}
1369 			case ANGLE_UNIT_GRADIANS: {
1370 				mstruct.set(50, 1, 0);
1371 				break;
1372 			}
1373 			case ANGLE_UNIT_RADIANS: {
1374 				mstruct.set(1, 4, 0);
1375 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1376 				break;
1377 			}
1378 			default: {
1379 				mstruct.set(1, 4, 0);
1380 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1381 				if(CALCULATOR->getRadUnit()) {
1382 					mstruct *= CALCULATOR->getRadUnit();
1383 				}
1384 			}
1385 		}
1386 	} else if(mstruct.number().isMinusOne()) {
1387 		switch(eo.parse_options.angle_unit) {
1388 			case ANGLE_UNIT_DEGREES: {
1389 				mstruct.set(-45, 1, 0);
1390 				break;
1391 			}
1392 			case ANGLE_UNIT_GRADIANS: {
1393 				mstruct.set(-50, 1, 0);
1394 				break;
1395 			}
1396 			case ANGLE_UNIT_RADIANS: {
1397 				mstruct.set(-1, 4, 0);
1398 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1399 				break;
1400 			}
1401 			default: {
1402 				mstruct.set(-1, 4, 0);
1403 				mstruct.multiply_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI)));
1404 				if(CALCULATOR->getRadUnit()) {
1405 					mstruct *= CALCULATOR->getRadUnit();
1406 				}
1407 			}
1408 		}
1409 	} else {
1410 		Number nr = mstruct.number();
1411 		if(!nr.atan() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) || (!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
1412 			if(trig_remove_i(mstruct)) {
1413 				mstruct.transformById(FUNCTION_ID_ATANH);
1414 				mstruct *= nr_one_i;
1415 				switch(eo.parse_options.angle_unit) {
1416 					case ANGLE_UNIT_DEGREES: {mstruct.multiply_nocopy(new MathStructure(180, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1417 					case ANGLE_UNIT_GRADIANS: {mstruct.multiply_nocopy(new MathStructure(200, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1418 					case ANGLE_UNIT_RADIANS: {break;}
1419 					default: {if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();} break;}
1420 				}
1421 				return 1;
1422 			}
1423 			if(has_predominately_negative_sign(mstruct)) {mstruct.number().negate(); mstruct.transform(this); mstruct.negate(); return 1;}
1424 			return -1;
1425 		}
1426 		mstruct = nr;
1427 		switch(eo.parse_options.angle_unit) {
1428 			case ANGLE_UNIT_DEGREES: {mstruct.multiply_nocopy(new MathStructure(180, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1429 			case ANGLE_UNIT_GRADIANS: {mstruct.multiply_nocopy(new MathStructure(200, 1, 0)); mstruct.divide_nocopy(new MathStructure(CALCULATOR->getVariableById(VARIABLE_ID_PI))); break;}
1430 			case ANGLE_UNIT_RADIANS: {break;}
1431 			default: {if(CALCULATOR->getRadUnit()) {mstruct *= CALCULATOR->getRadUnit();} break;}
1432 		}
1433 	}
1434 	return 1;
1435 
1436 }
1437 
SinhFunction()1438 SinhFunction::SinhFunction() : MathFunction("sinh", 1) {
1439 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
1440 }
representsNumber(const MathStructure & vargs,bool allow_units) const1441 bool SinhFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsReal(const MathStructure & vargs,bool) const1442 bool SinhFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const1443 bool SinhFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1444 int SinhFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1445 	if(vargs[0].isVector()) return 0;
1446 	mstruct = vargs[0];
1447 	mstruct.eval(eo);
1448 	if(mstruct.isVector()) return -1;
1449 	if(mstruct.isFunction() && mstruct.size() == 1) {
1450 		if(mstruct.function()->id() == FUNCTION_ID_ASINH) {
1451 			mstruct.setToChild(1, true);
1452 			return 1;
1453 		} else if(mstruct.function()->id() == FUNCTION_ID_ACOSH && !mstruct[0].containsInterval(eo.approximation == APPROXIMATION_EXACT, false, false, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true)) {
1454 			mstruct.setToChild(1);
1455 			MathStructure *mmul = new MathStructure(mstruct);
1456 			mstruct += nr_minus_one;
1457 			mstruct ^= nr_half;
1458 			*mmul += nr_one;
1459 			*mmul ^= nr_half;
1460 			mstruct.multiply_nocopy(mmul);
1461 			return 1;
1462 		} else if(mstruct.function()->id() == FUNCTION_ID_ATANH && !mstruct[0].containsInterval(eo.approximation == APPROXIMATION_EXACT, false, false, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true)) {
1463 			mstruct.setToChild(1);
1464 			MathStructure *mmul = new MathStructure(mstruct);
1465 			mstruct ^= nr_two;
1466 			mstruct.negate();
1467 			mstruct += nr_one;
1468 			mstruct ^= nr_minus_half;
1469 			mstruct.multiply_nocopy(mmul);
1470 			return 1;
1471 		}
1472 	}
1473 	if(!mstruct.isNumber()) {
1474 		if(trig_remove_i(mstruct)) {mstruct *= CALCULATOR->getRadUnit(); mstruct.transformById(FUNCTION_ID_SIN); mstruct *= nr_one_i; return 1;}
1475 		if(has_predominately_negative_sign(mstruct)) {negate_struct(mstruct); mstruct.transform(this); mstruct.negate(); return 1;}
1476 		return -1;
1477 	}
1478 	Number nr = mstruct.number();
1479 	if(!nr.sinh() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) || (!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
1480 		if(trig_remove_i(mstruct)) {mstruct *= CALCULATOR->getRadUnit(); mstruct.transformById(FUNCTION_ID_SIN); mstruct *= nr_one_i; return 1;}
1481 		if(has_predominately_negative_sign(mstruct)) {mstruct.number().negate(); mstruct.transform(this); mstruct.negate(); return 1;}
1482 		return -1;
1483 	}
1484 	mstruct = nr;
1485 	return 1;
1486 }
CoshFunction()1487 CoshFunction::CoshFunction() : MathFunction("cosh", 1) {
1488 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
1489 }
representsNumber(const MathStructure & vargs,bool allow_units) const1490 bool CoshFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsReal(const MathStructure & vargs,bool) const1491 bool CoshFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const1492 bool CoshFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1493 int CoshFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1494 	if(vargs[0].isVector()) return 0;
1495 	mstruct = vargs[0];
1496 	mstruct.eval(eo);
1497 	if(mstruct.isVector()) return -1;
1498 	if(mstruct.isFunction() && mstruct.size() == 1) {
1499 		if(mstruct.function()->id() == FUNCTION_ID_ACOSH) {
1500 			mstruct.setToChild(1, true);
1501 			return 1;
1502 		} else if(mstruct.function()->id() == FUNCTION_ID_ASINH) {
1503 			mstruct.setToChild(1);
1504 			mstruct ^= nr_two;
1505 			mstruct += nr_one;
1506 			mstruct ^= nr_half;
1507 			return 1;
1508 		} else if(mstruct.function()->id() == FUNCTION_ID_ATANH) {
1509 			mstruct.setToChild(1);
1510 			mstruct ^= nr_two;
1511 			mstruct.negate();
1512 			mstruct += nr_one;
1513 			mstruct ^= nr_minus_half;
1514 			return 1;
1515 		}
1516 	}
1517 	if(!mstruct.isNumber()) {
1518 		if(trig_remove_i(mstruct)) {mstruct *= CALCULATOR->getRadUnit(); mstruct.transformById(FUNCTION_ID_COS); return 1;}
1519 		if(has_predominately_negative_sign(mstruct)) {negate_struct(mstruct); return -1;}
1520 		return -1;
1521 	}
1522 	Number nr = mstruct.number();
1523 	if(!nr.cosh() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) || (!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
1524 		if(trig_remove_i(mstruct)) {mstruct *= CALCULATOR->getRadUnit(); mstruct.transformById(FUNCTION_ID_COS); return 1;}
1525 		if(has_predominately_negative_sign(mstruct)) mstruct.number().negate();
1526 		return -1;
1527 	}
1528 	mstruct = nr;
1529 	return 1;
1530 }
TanhFunction()1531 TanhFunction::TanhFunction() : MathFunction("tanh", 1) {
1532 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
1533 }
representsNumber(const MathStructure & vargs,bool allow_units) const1534 bool TanhFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsReal(const MathStructure & vargs,bool) const1535 bool TanhFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const1536 bool TanhFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1537 int TanhFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&eo) {
1538 	if(vargs[0].isVector()) return 0;
1539 	mstruct = vargs[0];
1540 	mstruct.eval(eo);
1541 	if(mstruct.isVector()) return -1;
1542 	if(mstruct.isFunction() && mstruct.size() == 1) {
1543 		if(mstruct.function()->id() == FUNCTION_ID_ATANH) {
1544 			mstruct.setToChild(1, true);
1545 			return 1;
1546 		} else if(mstruct.function()->id() == FUNCTION_ID_ASINH && !mstruct[0].containsInterval(eo.approximation == APPROXIMATION_EXACT, false, false, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true)) {
1547 			mstruct.setToChild(1);
1548 			MathStructure *mmul = new MathStructure(mstruct);
1549 			mstruct ^= nr_two;
1550 			mstruct += nr_one;
1551 			mstruct ^= nr_minus_half;
1552 			mstruct.multiply_nocopy(mmul);
1553 			return 1;
1554 		} else if(mstruct.function()->id() == FUNCTION_ID_ACOSH && !mstruct[0].containsInterval(eo.approximation == APPROXIMATION_EXACT, false, false, eo.approximation == APPROXIMATION_EXACT ? 1 : 0, true)) {
1555 			mstruct.setToChild(1);
1556 			MathStructure *mmul = new MathStructure(mstruct);
1557 			MathStructure *mmul2 = new MathStructure(mstruct);
1558 			*mmul2 ^= nr_minus_one;
1559 			mstruct += nr_minus_one;
1560 			mstruct ^= nr_half;
1561 			*mmul += nr_one;
1562 			*mmul ^= nr_half;
1563 			mstruct.multiply_nocopy(mmul);
1564 			mstruct.multiply_nocopy(mmul2);
1565 			return 1;
1566 		}
1567 	}
1568 	if(!mstruct.isNumber()) {
1569 		if(trig_remove_i(mstruct)) {mstruct *= CALCULATOR->getRadUnit(); mstruct.transformById(FUNCTION_ID_TAN); mstruct *= nr_one_i; return 1;}
1570 		if(has_predominately_negative_sign(mstruct)) {negate_struct(mstruct); mstruct.transform(this); mstruct.negate(); return 1;}
1571 		return -1;
1572 	}
1573 	Number nr = mstruct.number();
1574 	if(!nr.tanh() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) || (!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
1575 		if(has_predominately_negative_sign(mstruct)) {mstruct.number().negate(); mstruct.transform(this); mstruct.negate(); return 1;}
1576 		if(trig_remove_i(mstruct)) {mstruct *= CALCULATOR->getRadUnit(); mstruct.transformById(FUNCTION_ID_TAN); mstruct *= nr_one_i; return 1;}
1577 		return -1;
1578 	}
1579 	mstruct = nr;
1580 	return 1;
1581 }
AsinhFunction()1582 AsinhFunction::AsinhFunction() : MathFunction("asinh", 1) {
1583 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
1584 }
representsNumber(const MathStructure & vargs,bool allow_units) const1585 bool AsinhFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsReal(const MathStructure & vargs,bool) const1586 bool AsinhFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const1587 bool AsinhFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1588 int AsinhFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1589 	if(vargs[0].isVector()) return 0;
1590 	mstruct = vargs[0];
1591 	mstruct.eval(eo);
1592 	if(mstruct.isVector()) return -1;
1593 	if(!mstruct.isNumber()) {
1594 		if(has_predominately_negative_sign(mstruct)) {negate_struct(mstruct); mstruct.transform(this); mstruct.negate(); return 1;}
1595 		return -1;
1596 	}
1597 	Number nr = mstruct.number();
1598 	if(!nr.asinh() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) || (!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
1599 		if(has_predominately_negative_sign(mstruct)) {mstruct.number().negate(); mstruct.transform(this); mstruct.negate(); return 1;}
1600 		return -1;
1601 	}
1602 	mstruct = nr;
1603 	return 1;
1604 }
AcoshFunction()1605 AcoshFunction::AcoshFunction() : MathFunction("acosh", 1) {
1606 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false));
1607 }
representsNumber(const MathStructure & vargs,bool allow_units) const1608 bool AcoshFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1609 int AcoshFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1610 	if(eo.allow_complex && vargs[0].isZero()) {
1611 		mstruct.set(1, 2, 0);
1612 		mstruct.number() *= nr_one_i;
1613 		mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
1614 		return 1;
1615 	} else if(vargs[0].isOne()) {
1616 		mstruct.clear();
1617 		return 1;
1618 	} else if(eo.approximation != APPROXIMATION_APPROXIMATE && eo.allow_complex && vargs[0].number() <= -1) {
1619 		mstruct = nr_one_i;
1620 		mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
1621 		mstruct.add_nocopy(new MathStructure(this, &vargs[0], NULL));
1622 		mstruct.last()[0].negate();
1623 		return 1;
1624 	}
1625 	Number nr(vargs[0].number());
1626 	if(!nr.acosh() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) || (!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
1627 		return 0;
1628 	}
1629 	mstruct = nr;
1630 	return 1;
1631 }
AtanhFunction()1632 AtanhFunction::AtanhFunction() : MathFunction("atanh", 1) {
1633 	setArgumentDefinition(1, new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false));
1634 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1635 int AtanhFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1636 	if(vargs[0].isVector()) return 0;
1637 	mstruct = vargs[0];
1638 	mstruct.eval(eo);
1639 	if(mstruct.isVector()) return -1;
1640 	if(!mstruct.isNumber()) {
1641 		if(has_predominately_negative_sign(mstruct)) {negate_struct(mstruct); mstruct.transform(this); mstruct.negate(); return 1;}
1642 		return -1;
1643 	}
1644 	if(eo.allow_complex && mstruct.number().includesInfinity()) {
1645 		if(mstruct.number().isPlusInfinity() || (!mstruct.number().hasRealPart() && mstruct.number().hasImaginaryPart() && mstruct.number().internalImaginary()->isMinusInfinity())) {
1646 			mstruct = nr_minus_half;
1647 			mstruct *= nr_one_i;
1648 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
1649 			return true;
1650 		} else if(mstruct.number().isMinusInfinity() || (!mstruct.number().hasRealPart() && mstruct.number().hasImaginaryPart() && mstruct.number().internalImaginary()->isPlusInfinity())) {
1651 			mstruct = nr_half;
1652 			mstruct *= nr_one_i;
1653 			mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
1654 			return true;
1655 		}
1656 	} else if(eo.approximation != APPROXIMATION_APPROXIMATE && eo.allow_complex && mstruct.number() > 1) {
1657 		mstruct.set(-1, 2, 0);
1658 		mstruct.number() *= nr_one_i;
1659 		mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
1660 		mstruct.add_nocopy(new MathStructure(this, &vargs[0], NULL));
1661 		mstruct.last()[0].inverse();
1662 		return 1;
1663 	} else if(eo.approximation != APPROXIMATION_APPROXIMATE && eo.allow_complex && mstruct.number() < -1) {
1664 		mstruct.set(1, 2, 0);
1665 		mstruct.number() *= nr_one_i;
1666 		mstruct *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
1667 		mstruct.add_nocopy(new MathStructure(this, &vargs[0], NULL));
1668 		mstruct.last()[0].inverse();
1669 		mstruct.last()[0].negate();
1670 		mstruct.last().negate();
1671 		return 1;
1672 	}
1673 	Number nr = mstruct.number();
1674 	if(!nr.atanh() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate()) || (!eo.allow_complex && nr.isComplex() && !mstruct.number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !mstruct.number().includesInfinity())) {
1675 		if(has_predominately_negative_sign(mstruct)) {mstruct.number().negate(); mstruct.transform(this); mstruct.negate(); return 1;}
1676 		return -1;
1677 	}
1678 	mstruct = nr;
1679 	return 1;
1680 }
SincFunction()1681 SincFunction::SincFunction() : MathFunction("sinc", 1) {
1682 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false);
1683 	arg->setHandleVector(true);
1684 	setArgumentDefinition(1, arg);
1685 }
representsNumber(const MathStructure & vargs,bool) const1686 bool SincFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && (vargs[0].representsNumber() || is_number_angle_value(vargs[0]));}
representsReal(const MathStructure & vargs,bool) const1687 bool SincFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && (vargs[0].representsReal() || is_real_angle_value(vargs[0]));}
representsNonComplex(const MathStructure & vargs,bool) const1688 bool SincFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNonComplex();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1689 int SincFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1690 	if(vargs[0].isZero()) {
1691 		mstruct.set(1, 1, 0, true);
1692 		return 1;
1693 	} else if(vargs[0].representsNonZero(true)) {
1694 		mstruct = vargs[0];
1695 		bool b = replace_f_interval(mstruct, eo);
1696 		b = replace_intervals_f(mstruct) || b;
1697 		MathStructure *m_sin = new MathStructure(CALCULATOR->getFunctionById(FUNCTION_ID_SIN), &mstruct, NULL);
1698 		if(CALCULATOR->getRadUnit()) (*m_sin)[0].multiply(CALCULATOR->getRadUnit());
1699 		mstruct.inverse();
1700 		mstruct.multiply_nocopy(m_sin);
1701 		if(b) mstruct.eval(eo);
1702 		return 1;
1703 	}
1704 	return -1;
1705 }
1706 
Atan2Function()1707 Atan2Function::Atan2Function() : MathFunction("atan2", 2) {
1708 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, true);
1709 	arg->setComplexAllowed(false);
1710 	setArgumentDefinition(1, arg);
1711 	arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, true);
1712 	arg->setComplexAllowed(false);
1713 	setArgumentDefinition(2, arg);
1714 }
representsNumber(const MathStructure & vargs,bool) const1715 bool Atan2Function::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 2 && vargs[0].representsNumber() && vargs[1].representsNumber();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1716 int Atan2Function::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1717 	if(vargs[0].number().isZero()) {
1718 		if(!vargs[1].number().isNonZero()) return 0;
1719 		if(vargs[1].number().isNegative()) {
1720 			switch(eo.parse_options.angle_unit) {
1721 				case ANGLE_UNIT_DEGREES: {mstruct.set(180, 1, 0); break;}
1722 				case ANGLE_UNIT_GRADIANS: {mstruct.set(200, 1, 0); break;}
1723 				case ANGLE_UNIT_RADIANS: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); break;}
1724 				default: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();}
1725 			}
1726 		} else {
1727 			mstruct.clear();
1728 		}
1729 	} else if(vargs[1].number().isZero() && vargs[0].number().isNonZero()) {
1730 		switch(eo.parse_options.angle_unit) {
1731 			case ANGLE_UNIT_DEGREES: {mstruct.set(90, 1, 0); break;}
1732 			case ANGLE_UNIT_GRADIANS: {mstruct.set(100, 1, 0); break;}
1733 			case ANGLE_UNIT_RADIANS: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); mstruct.multiply(nr_half); break;}
1734 			default: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); mstruct.multiply(nr_half); if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();}
1735 		}
1736 		if(vargs[0].number().hasNegativeSign()) mstruct.negate();
1737 	} else if(!vargs[1].number().isNonZero()) {
1738 		FR_FUNCTION_2(atan2)
1739 	} else {
1740 		MathStructure new_nr(vargs[0]);
1741 		if(!new_nr.number().divide(vargs[1].number())) return -1;
1742 		if(vargs[1].number().isNegative() && vargs[0].number().isNonZero()) {
1743 			if(vargs[0].number().isNegative()) {
1744 				mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
1745 				switch(eo.parse_options.angle_unit) {
1746 					case ANGLE_UNIT_DEGREES: {mstruct.add(-180); break;}
1747 					case ANGLE_UNIT_GRADIANS: {mstruct.add(-200); break;}
1748 					case ANGLE_UNIT_RADIANS: {mstruct.subtract(CALCULATOR->getVariableById(VARIABLE_ID_PI)); break;}
1749 					default: {MathStructure msub(CALCULATOR->getVariableById(VARIABLE_ID_PI)); if(CALCULATOR->getRadUnit()) msub *= CALCULATOR->getRadUnit(); mstruct.subtract(msub);}
1750 				}
1751 			} else {
1752 				mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
1753 				switch(eo.parse_options.angle_unit) {
1754 					case ANGLE_UNIT_DEGREES: {mstruct.add(180); break;}
1755 					case ANGLE_UNIT_GRADIANS: {mstruct.add(200); break;}
1756 					case ANGLE_UNIT_RADIANS: {mstruct.add(CALCULATOR->getVariableById(VARIABLE_ID_PI)); break;}
1757 					default: {MathStructure madd(CALCULATOR->getVariableById(VARIABLE_ID_PI)); if(CALCULATOR->getRadUnit()) madd *= CALCULATOR->getRadUnit(); mstruct.add(madd);}
1758 				}
1759 			}
1760 		} else {
1761 			mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
1762 		}
1763 	}
1764 	return 1;
1765 }
RadiansToDefaultAngleUnitFunction()1766 RadiansToDefaultAngleUnitFunction::RadiansToDefaultAngleUnitFunction() : MathFunction("radtodef", 1) {
1767 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1768 int RadiansToDefaultAngleUnitFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1769 	mstruct = vargs[0];
1770 	switch(eo.parse_options.angle_unit) {
1771 		case ANGLE_UNIT_DEGREES: {
1772 			mstruct *= 180;
1773 			mstruct /= CALCULATOR->getVariableById(VARIABLE_ID_PI);
1774 			break;
1775 		}
1776 		case ANGLE_UNIT_GRADIANS: {
1777 			mstruct *= 200;
1778 			mstruct /= CALCULATOR->getVariableById(VARIABLE_ID_PI);
1779 			break;
1780 		}
1781 		case ANGLE_UNIT_RADIANS: {
1782 			break;
1783 		}
1784 		default: {
1785 			if(CALCULATOR->getRadUnit()) {
1786 				mstruct *= CALCULATOR->getRadUnit();
1787 			}
1788 		}
1789 	}
1790 	return 1;
1791 }
1792 
1793