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 #if HAVE_UNORDERED_MAP
30 #	include <unordered_map>
31 	using std::unordered_map;
32 #elif 	defined(__GNUC__)
33 
34 #	ifndef __has_include
35 #	define __has_include(x) 0
36 #	endif
37 
38 #	if (defined(__clang__) && __has_include(<tr1/unordered_map>)) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 3)
39 #		include <tr1/unordered_map>
40 		namespace Sgi = std;
41 #		define unordered_map std::tr1::unordered_map
42 #	else
43 #		if __GNUC__ < 3
44 #			include <hash_map.h>
45 			namespace Sgi { using ::hash_map; }; // inherit globals
46 #		else
47 #			include <ext/hash_map>
48 #			if __GNUC__ == 3 && __GNUC_MINOR__ == 0
49 				namespace Sgi = std;               // GCC 3.0
50 #			else
51 				namespace Sgi = ::__gnu_cxx;       // GCC 3.1 and later
52 #			endif
53 #		endif
54 #		define unordered_map Sgi::hash_map
55 #	endif
56 #else      // ...  there are other compilers, right?
57 	namespace Sgi = std;
58 #	define unordered_map Sgi::hash_map
59 #endif
60 
61 using std::string;
62 using std::cout;
63 using std::vector;
64 using std::endl;
65 
66 #define FR_FUNCTION(FUNC)	Number nr(vargs[0].number()); if(!nr.FUNC() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !vargs[0].isApproximate()) || (!eo.allow_complex && nr.isComplex() && !vargs[0].number().isComplex()) || (!eo.allow_infinite && nr.includesInfinity() && !vargs[0].number().includesInfinity())) {return 0;} else {mstruct.set(nr); return 1;}
67 #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;}
68 
69 #define NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(i)			NumberArgument *arg_non_complex##i = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false); arg_non_complex##i->setComplexAllowed(false); setArgumentDefinition(i, arg_non_complex##i);
70 #define NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR_NONZERO(i)		NumberArgument *arg_non_complex##i = new NumberArgument("", ARGUMENT_MIN_MAX_NONZERO, true, false); arg_non_complex##i->setComplexAllowed(false); setArgumentDefinition(i, arg_non_complex##i);
71 #define RATIONAL_NUMBER_ARGUMENT_NO_ERROR(i)			NumberArgument *arg_rational##i = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, false); arg_rational##i->setRationalNumber(true); setArgumentDefinition(i, arg_rational##i);
72 #define RATIONAL_POLYNOMIAL_ARGUMENT(i)				Argument *arg_poly##i = new Argument(); arg_poly##i->setRationalPolynomial(true); setArgumentDefinition(i, arg_poly##i);
73 #define RATIONAL_POLYNOMIAL_ARGUMENT_HV(i)			Argument *arg_poly##i = new Argument(); arg_poly##i->setRationalPolynomial(true); arg_poly##i->setHandleVector(true); setArgumentDefinition(i, arg_poly##i);
74 
OddFunction()75 OddFunction::OddFunction() : MathFunction("odd", 1) {
76 	Argument *arg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
77 	arg->setHandleVector(true);
78 	setArgumentDefinition(1, arg);
79 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)80 int OddFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
81 	if(vargs[0].isVector()) return 0;
82 	if(vargs[0].representsOdd()) {
83 		mstruct.set(1, 1, 0);
84 		return 1;
85 	} else if(vargs[0].representsEven()) {
86 		mstruct.clear();
87 		return 1;
88 	}
89 	mstruct = vargs[0];
90 	mstruct.eval(eo);
91 	if(mstruct.isVector()) return -1;
92 	if(mstruct.representsOdd()) {
93 		mstruct.set(1, 1, 0);
94 		return 1;
95 	} else if(mstruct.representsEven()) {
96 		mstruct.clear();
97 		return 1;
98 	}
99 	return -1;
100 }
EvenFunction()101 EvenFunction::EvenFunction() : MathFunction("even", 1) {
102 	Argument *arg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
103 	arg->setHandleVector(true);
104 	setArgumentDefinition(1, arg);
105 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)106 int EvenFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
107 	if(vargs[0].isVector()) return 0;
108 	if(vargs[0].representsEven()) {
109 		mstruct.set(1, 1, 0);
110 		return 1;
111 	} else if(vargs[0].representsOdd()) {
112 		mstruct.clear();
113 		return 1;
114 	}
115 	mstruct = vargs[0];
116 	mstruct.eval(eo);
117 	if(mstruct.isVector()) return -1;
118 	if(mstruct.representsEven()) {
119 		mstruct.set(1, 1, 0);
120 		return 1;
121 	} else if(mstruct.representsOdd()) {
122 		mstruct.clear();
123 		return 1;
124 	}
125 	return -1;
126 }
AbsFunction()127 AbsFunction::AbsFunction() : MathFunction("abs", 1) {
128 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
129 	arg->setHandleVector(true);
130 	setArgumentDefinition(1, arg);
131 }
representsPositive(const MathStructure & vargs,bool allow_units) const132 bool AbsFunction::representsPositive(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units) && vargs[0].representsNonZero(allow_units);}
representsNegative(const MathStructure &,bool) const133 bool AbsFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool allow_units) const134 bool AbsFunction::representsNonNegative(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsNonPositive(const MathStructure &,bool) const135 bool AbsFunction::representsNonPositive(const MathStructure&, bool) const {return false;}
representsInteger(const MathStructure & vargs,bool allow_units) const136 bool AbsFunction::representsInteger(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsInteger(allow_units);}
representsNumber(const MathStructure & vargs,bool allow_units) const137 bool AbsFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsRational(const MathStructure & vargs,bool allow_units) const138 bool AbsFunction::representsRational(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsRational(allow_units);}
representsReal(const MathStructure & vargs,bool allow_units) const139 bool AbsFunction::representsReal(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsNonComplex(const MathStructure & vargs,bool) const140 bool AbsFunction::representsNonComplex(const MathStructure &vargs, bool) const {return true;}
representsComplex(const MathStructure &,bool) const141 bool AbsFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure & vargs,bool allow_units) const142 bool AbsFunction::representsNonZero(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units) && vargs[0].representsNonZero(allow_units);}
representsEven(const MathStructure & vargs,bool allow_units) const143 bool AbsFunction::representsEven(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsEven(allow_units);}
representsOdd(const MathStructure & vargs,bool allow_units) const144 bool AbsFunction::representsOdd(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsOdd(allow_units);}
representsUndefined(const MathStructure & vargs) const145 bool AbsFunction::representsUndefined(const MathStructure &vargs) const {return vargs.size() == 1 && vargs[0].representsUndefined();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)146 int AbsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
147 	if(vargs[0].isVector()) return 0;
148 	mstruct = vargs[0];
149 	mstruct.eval(eo);
150 	if(mstruct.isVector()) return -1;
151 	if(mstruct.isNumber()) {
152 		if(eo.approximation != APPROXIMATION_APPROXIMATE && mstruct.number().hasImaginaryPart() && mstruct.number().hasRealPart()) {
153 			MathStructure m_i(mstruct.number().imaginaryPart());
154 			m_i ^= nr_two;
155 			mstruct.number().clearImaginary();
156 			mstruct.numberUpdated();
157 			mstruct ^= nr_two;
158 			mstruct += m_i;
159 			mstruct ^= nr_half;
160 			return 1;
161 		}
162 		Number nr(mstruct.number());
163 		if(!nr.abs() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate())) {
164 			return -1;
165 		}
166 		mstruct = nr;
167 		return 1;
168 	}
169 	if(mstruct.isPower() && mstruct[0].representsPositive()) {
170 		if(mstruct[1].isNumber() && !mstruct[1].number().hasRealPart()) {
171 			mstruct.set(1, 1, 0, true);
172 			return 1;
173 		} else if(mstruct[1].isMultiplication() && mstruct.size() > 0 && mstruct[1][0].isNumber() && !mstruct[1][0].number().hasRealPart()) {
174 			bool b = true;
175 			for(size_t i = 1; i < mstruct[1].size(); i++) {
176 				if(!mstruct[1][i].representsNonComplex()) {b = false; break;}
177 			}
178 			if(b) {
179 				mstruct.set(1, 1, 0, true);
180 				return 1;
181 			}
182 		}
183 	}
184 	if(mstruct.representsNegative(true)) {
185 		mstruct.negate();
186 		return 1;
187 	}
188 	if(mstruct.representsNonNegative(true)) {
189 		return 1;
190 	}
191 	if(mstruct.isMultiplication()) {
192 		for(size_t i = 0; i < mstruct.size(); i++) {
193 			mstruct[i].transform(STRUCT_FUNCTION);
194 			mstruct[i].setFunction(this);
195 		}
196 		mstruct.childrenUpdated();
197 		return 1;
198 	}
199 	if(mstruct.isFunction() && mstruct.function()->id() == FUNCTION_ID_SIGNUM && mstruct.size() == 2) {
200 		mstruct[0].transform(this);
201 		mstruct.childUpdated(1);
202 		return 1;
203 	}
204 	if(mstruct.isPower() && mstruct[1].representsReal()) {
205 		mstruct[0].transform(this);
206 		return 1;
207 	}
208 	if(eo.approximation == APPROXIMATION_EXACT || has_interval_unknowns(mstruct)) {
209 		ComparisonResult cr = mstruct.compare(m_zero);
210 		if(COMPARISON_IS_EQUAL_OR_LESS(cr)) {
211 			return 1;
212 		} else if(COMPARISON_IS_EQUAL_OR_GREATER(cr)) {
213 			mstruct.negate();
214 			return 1;
215 		}
216 	}
217 	return -1;
218 }
GcdFunction()219 GcdFunction::GcdFunction() : MathFunction("gcd", 2) {
220 	RATIONAL_POLYNOMIAL_ARGUMENT_HV(1)
221 	RATIONAL_POLYNOMIAL_ARGUMENT_HV(2)
222 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)223 int GcdFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
224 	if(MathStructure::gcd(vargs[0], vargs[1], mstruct, eo)) {
225 		return 1;
226 	}
227 	return 0;
228 }
LcmFunction()229 LcmFunction::LcmFunction() : MathFunction("lcm", 2) {
230 	RATIONAL_POLYNOMIAL_ARGUMENT_HV(1)
231 	RATIONAL_POLYNOMIAL_ARGUMENT_HV(2)
232 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)233 int LcmFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
234 	if(MathStructure::lcm(vargs[0], vargs[1], mstruct, eo)) {
235 		return 1;
236 	}
237 	return 0;
238 }
239 
SignumFunction()240 SignumFunction::SignumFunction() : MathFunction("sgn", 1, 2) {
241 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
242 	arg->setHandleVector(true);
243 	setArgumentDefinition(1, arg);
244 	setDefaultValue(2, "0");
245 }
representsPositive(const MathStructure &,bool allow_units) const246 bool SignumFunction::representsPositive(const MathStructure&, bool allow_units) const {return false;}
representsNegative(const MathStructure &,bool) const247 bool SignumFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool) const248 bool SignumFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() >= 1 && vargs[0].representsNonNegative(true);}
representsNonPositive(const MathStructure & vargs,bool) const249 bool SignumFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() >= 1 && vargs[0].representsNonPositive(true);}
representsInteger(const MathStructure & vargs,bool) const250 bool SignumFunction::representsInteger(const MathStructure &vargs, bool) const {return vargs.size() >= 1 && vargs[0].representsReal(true);}
representsNumber(const MathStructure & vargs,bool) const251 bool SignumFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() >= 1 && vargs[0].representsNumber(true);}
representsRational(const MathStructure & vargs,bool) const252 bool SignumFunction::representsRational(const MathStructure &vargs, bool) const {return vargs.size() >= 1 && vargs[0].representsReal(true);}
representsNonComplex(const MathStructure & vargs,bool) const253 bool SignumFunction::representsNonComplex(const MathStructure &vargs, bool) const {return vargs.size() >= 1 && vargs[0].representsNonComplex(true);}
representsReal(const MathStructure & vargs,bool) const254 bool SignumFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() >= 1 && vargs[0].representsReal(true);}
representsComplex(const MathStructure & vargs,bool) const255 bool SignumFunction::representsComplex(const MathStructure &vargs, bool) const {return vargs.size() >= 1 && vargs[0].representsComplex(true);}
representsNonZero(const MathStructure & vargs,bool) const256 bool SignumFunction::representsNonZero(const MathStructure &vargs, bool) const {return (vargs.size() == 2 && !vargs[1].isZero()) || (vargs.size() >= 1 && vargs[0].representsNonZero(true));}
representsEven(const MathStructure &,bool) const257 bool SignumFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure & vargs,bool b) const258 bool SignumFunction::representsOdd(const MathStructure &vargs, bool b) const {return representsNonZero(vargs, b);}
representsUndefined(const MathStructure & vargs) const259 bool SignumFunction::representsUndefined(const MathStructure &vargs) const {return vargs.size() >= 1 && vargs[0].representsUndefined();}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)260 int SignumFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
261 	if(vargs[0].isVector()) return 0;
262 	mstruct = vargs[0];
263 	mstruct.eval(eo);
264 	if(mstruct.isVector()) return -1;
265 	if(mstruct.isNumber() && (vargs.size() == 1 || vargs[1].isZero())) {
266 		Number nr(mstruct.number());
267 		if(!nr.signum() || (eo.approximation == APPROXIMATION_EXACT && nr.isApproximate() && !mstruct.isApproximate())) {
268 			if(mstruct.number().isNonZero()) {
269 				MathStructure *mabs = new MathStructure(mstruct);
270 				mabs->transformById(FUNCTION_ID_ABS);
271 				mstruct.divide_nocopy(mabs);
272 				return 1;
273 			}
274 			return -1;
275 		} else {
276 			mstruct = nr;
277 			return 1;
278 		}
279 	}
280 	if((vargs.size() > 1 && vargs[1].isOne() && mstruct.representsNonNegative(true)) || mstruct.representsPositive(true)) {
281 		mstruct.set(1, 1, 0);
282 		return 1;
283 	}
284 	if((vargs.size() > 1 && vargs[1].isMinusOne() && mstruct.representsNonPositive(true)) || mstruct.representsNegative(true)) {
285 		mstruct.set(-1, 1, 0);
286 		return 1;
287 	}
288 	if(mstruct.isMultiplication()) {
289 		for(size_t i = 0; i < mstruct.size(); i++) {
290 			if(vargs.size() > 1) mstruct[i].transform(STRUCT_FUNCTION, vargs[1]);
291 			else mstruct[i].transform(STRUCT_FUNCTION);
292 			mstruct[i].setFunction(this);
293 
294 		}
295 		mstruct.childrenUpdated();
296 		return 1;
297 	}
298 	if(vargs.size() > 1 && mstruct.isZero()) {
299 		mstruct.set(vargs[1], true);
300 		return 1;
301 	}
302 	if(eo.approximation == APPROXIMATION_EXACT || has_interval_unknowns(mstruct)) {
303 		ComparisonResult cr = mstruct.compare(m_zero);
304 		if(cr == COMPARISON_RESULT_LESS || (vargs.size() > 1 && vargs[1].isOne() && COMPARISON_IS_EQUAL_OR_LESS(cr))) {
305 			mstruct.set(1, 1, 0);
306 			return 1;
307 		} else if(cr == COMPARISON_RESULT_GREATER || (vargs.size() > 1 && vargs[1].isMinusOne() && COMPARISON_IS_EQUAL_OR_GREATER(cr))) {
308 			mstruct.set(-1, 1, 0);
309 			return 1;
310 		}
311 	}
312 	return -1;
313 }
314 
CeilFunction()315 CeilFunction::CeilFunction() : MathFunction("ceil", 1) {
316 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
317 	arg->setComplexAllowed(false);
318 	arg->setHandleVector(true);
319 	setArgumentDefinition(1, arg);
320 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)321 int CeilFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
322 	if(vargs[0].isVector()) return 0;
323 	if(vargs[0].isNumber()) {
324 		FR_FUNCTION(ceil)
325 	}
326 	mstruct = vargs[0];
327 	mstruct.eval(eo);
328 	if(mstruct.isVector()) return -1;
329 	if(mstruct.isNumber()) {
330 		Number nr(mstruct.number());
331 		if(nr.ceil() && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || vargs[0].isApproximate())) {
332 			mstruct.set(nr);
333 			return 1;
334 		}
335 	} else if(!mstruct.isNumber() && eo.approximation == APPROXIMATION_EXACT && !vargs[0].isApproximate()) {
336 		EvaluationOptions eo2 = eo;
337 		eo2.approximation = APPROXIMATION_APPROXIMATE;
338 		MathStructure mstruct2(mstruct);
339 		mstruct2.eval(eo2);
340 		if(mstruct2.isNumber()) {
341 			Number nr(mstruct2.number());
342 			if(nr.ceil() && !nr.isApproximate()) {
343 				mstruct.set(nr);
344 				return 1;
345 			}
346 		}
347 	}
348 	return -1;
349 }
representsPositive(const MathStructure & vargs,bool) const350 bool CeilFunction::representsPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsPositive();}
representsNegative(const MathStructure &,bool) const351 bool CeilFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool) const352 bool CeilFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative();}
representsNonPositive(const MathStructure & vargs,bool) const353 bool CeilFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonPositive();}
representsInteger(const MathStructure & vargs,bool) const354 bool CeilFunction::representsInteger(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNumber(const MathStructure & vargs,bool) const355 bool CeilFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const356 bool CeilFunction::representsNonComplex(const MathStructure &vargs, bool) const {return true;}
representsRational(const MathStructure & vargs,bool) const357 bool CeilFunction::representsRational(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsReal(const MathStructure & vargs,bool) const358 bool CeilFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsComplex(const MathStructure &,bool) const359 bool CeilFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure & vargs,bool) const360 bool CeilFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsPositive();}
representsEven(const MathStructure & vargs,bool) const361 bool CeilFunction::representsEven(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsEven();}
representsOdd(const MathStructure & vargs,bool) const362 bool CeilFunction::representsOdd(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsOdd();}
representsUndefined(const MathStructure &) const363 bool CeilFunction::representsUndefined(const MathStructure&) const {return false;}
364 
FloorFunction()365 FloorFunction::FloorFunction() : MathFunction("floor", 1) {
366 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
367 	arg->setComplexAllowed(false);
368 	arg->setHandleVector(true);
369 	setArgumentDefinition(1, arg);
370 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)371 int FloorFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
372 	if(vargs[0].isVector()) return 0;
373 	if(vargs[0].isNumber()) {
374 		FR_FUNCTION(floor)
375 	}
376 	mstruct = vargs[0];
377 	mstruct.eval(eo);
378 	if(mstruct.isVector()) return -1;
379 	if(mstruct.isNumber()) {
380 		Number nr(mstruct.number());
381 		if(nr.floor() && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || vargs[0].isApproximate())) {
382 			mstruct.set(nr);
383 			return 1;
384 		}
385 	} else if(!mstruct.isNumber() && eo.approximation == APPROXIMATION_EXACT && !vargs[0].isApproximate()) {
386 		EvaluationOptions eo2 = eo;
387 		eo2.approximation = APPROXIMATION_APPROXIMATE;
388 		MathStructure mstruct2(mstruct);
389 		mstruct2.eval(eo2);
390 		if(mstruct2.isNumber()) {
391 			Number nr(mstruct2.number());
392 			if(nr.floor() && !nr.isApproximate()) {
393 				mstruct.set(nr);
394 				return 1;
395 			}
396 		}
397 	}
398 	return -1;
399 }
representsPositive(const MathStructure &,bool) const400 bool FloorFunction::representsPositive(const MathStructure&, bool) const {return false;}
representsNegative(const MathStructure & vargs,bool) const401 bool FloorFunction::representsNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNegative();}
representsNonNegative(const MathStructure & vargs,bool) const402 bool FloorFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative();}
representsNonPositive(const MathStructure & vargs,bool) const403 bool FloorFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonPositive();}
representsInteger(const MathStructure & vargs,bool) const404 bool FloorFunction::representsInteger(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNumber(const MathStructure & vargs,bool) const405 bool FloorFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsRational(const MathStructure & vargs,bool) const406 bool FloorFunction::representsRational(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const407 bool FloorFunction::representsNonComplex(const MathStructure &vargs, bool) const {return true;}
representsReal(const MathStructure & vargs,bool) const408 bool FloorFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsComplex(const MathStructure &,bool) const409 bool FloorFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure & vargs,bool) const410 bool FloorFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNegative();}
representsEven(const MathStructure & vargs,bool) const411 bool FloorFunction::representsEven(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsEven();}
representsOdd(const MathStructure & vargs,bool) const412 bool FloorFunction::representsOdd(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsOdd();}
representsUndefined(const MathStructure &) const413 bool FloorFunction::representsUndefined(const MathStructure&) const {return false;}
414 
TruncFunction()415 TruncFunction::TruncFunction() : MathFunction("trunc", 1) {
416 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
417 	arg->setComplexAllowed(false);
418 	arg->setHandleVector(true);
419 	setArgumentDefinition(1, arg);
420 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)421 int TruncFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
422 	if(vargs[0].isVector()) return 0;
423 	if(vargs[0].isNumber()) {
424 		FR_FUNCTION(trunc)
425 	}
426 	mstruct = vargs[0];
427 	mstruct.eval(eo);
428 	if(mstruct.isVector()) return -1;
429 	if(mstruct.isNumber()) {
430 		Number nr(mstruct.number());
431 		if(nr.trunc() && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || vargs[0].isApproximate())) {
432 			mstruct.set(nr);
433 			return 1;
434 		}
435 	} else if(!mstruct.isNumber() && eo.approximation == APPROXIMATION_EXACT && !vargs[0].isApproximate()) {
436 		EvaluationOptions eo2 = eo;
437 		eo2.approximation = APPROXIMATION_APPROXIMATE;
438 		MathStructure mstruct2(mstruct);
439 		mstruct2.eval(eo2);
440 		if(mstruct2.isNumber()) {
441 			Number nr(mstruct2.number());
442 			if(nr.trunc() && !nr.isApproximate()) {
443 				mstruct.set(nr);
444 				return 1;
445 			}
446 		}
447 	}
448 	return -1;
449 }
representsPositive(const MathStructure &,bool) const450 bool TruncFunction::representsPositive(const MathStructure&, bool) const {return false;}
representsNegative(const MathStructure &,bool) const451 bool TruncFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool) const452 bool TruncFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative();}
representsNonPositive(const MathStructure & vargs,bool) const453 bool TruncFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonPositive();}
representsInteger(const MathStructure & vargs,bool) const454 bool TruncFunction::representsInteger(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNumber(const MathStructure & vargs,bool) const455 bool TruncFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsRational(const MathStructure & vargs,bool) const456 bool TruncFunction::representsRational(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsReal(const MathStructure & vargs,bool) const457 bool TruncFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const458 bool TruncFunction::representsNonComplex(const MathStructure &vargs, bool) const {return true;}
representsComplex(const MathStructure &,bool) const459 bool TruncFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure &,bool) const460 bool TruncFunction::representsNonZero(const MathStructure&, bool) const {return false;}
representsEven(const MathStructure & vargs,bool) const461 bool TruncFunction::representsEven(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsEven();}
representsOdd(const MathStructure & vargs,bool) const462 bool TruncFunction::representsOdd(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsOdd();}
representsUndefined(const MathStructure &) const463 bool TruncFunction::representsUndefined(const MathStructure&) const {return false;}
464 
RoundFunction()465 RoundFunction::RoundFunction() : MathFunction("round", 1, 3) {
466 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
467 	arg->setComplexAllowed(false);
468 	arg->setHandleVector(true);
469 	setArgumentDefinition(1, arg);
470 	setArgumentDefinition(2, new IntegerArgument());
471 	setDefaultValue(2, "0");
472 	setArgumentDefinition(3, new BooleanArgument());
473 	setDefaultValue(3, "0");
474 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)475 int RoundFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
476 	if(vargs[0].isVector()) return 0;
477 	if(vargs[0].isNumber()) {
478 		Number nr(vargs[0].number());
479 		if(vargs.size() >= 2 && !vargs[1].isZero()) nr.exp10(vargs[1].number());
480 		if(nr.round(vargs.size() >= 3 ? vargs[2].number().getBoolean() : true) && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || vargs[0].isApproximate())) {
481 			if(vargs.size() >= 2 && !vargs[1].isZero()) nr.exp10(-vargs[1].number());
482 			mstruct.set(nr);
483 			return 1;
484 		}
485 		return 0;
486 	}
487 	mstruct = vargs[0];
488 	mstruct.eval(eo);
489 	if(mstruct.isVector()) return -1;
490 	if(mstruct.isNumber()) {
491 		Number nr(mstruct.number());
492 		if(vargs.size() >= 2 && !vargs[1].isZero()) nr.exp10(vargs[1].number());
493 		if(nr.round(vargs.size() >= 3 ? vargs[2].number().getBoolean() : true) && (eo.approximation != APPROXIMATION_EXACT || !nr.isApproximate() || vargs[0].isApproximate())) {
494 			if(vargs.size() >= 2 && !vargs[1].isZero()) nr.exp10(-vargs[1].number());
495 			mstruct.set(nr);
496 			return 1;
497 		}
498 	} else if(!mstruct.isNumber() && eo.approximation == APPROXIMATION_EXACT && !vargs[0].isApproximate()) {
499 		EvaluationOptions eo2 = eo;
500 		eo2.approximation = APPROXIMATION_APPROXIMATE;
501 		MathStructure mstruct2(mstruct);
502 		mstruct2.eval(eo2);
503 		if(mstruct2.isNumber()) {
504 			Number nr(mstruct2.number());
505 			if(vargs.size() >= 2 && !vargs[1].isZero()) nr.exp10(vargs[1].number());
506 			if(nr.round(vargs.size() >= 3 ? vargs[2].number().getBoolean() : true) && !nr.isApproximate()) {
507 				if(vargs.size() >= 2 && !vargs[1].isZero()) nr.exp10(-vargs[1].number());
508 				mstruct.set(nr);
509 				return 1;
510 			}
511 		}
512 	}
513 	return -1;
514 }
representsPositive(const MathStructure &,bool) const515 bool RoundFunction::representsPositive(const MathStructure&, bool) const {return false;}
representsNegative(const MathStructure &,bool) const516 bool RoundFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool) const517 bool RoundFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonNegative();}
representsNonPositive(const MathStructure & vargs,bool) const518 bool RoundFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && vargs[0].representsNonPositive();}
representsInteger(const MathStructure & vargs,bool) const519 bool RoundFunction::representsInteger(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal() && (vargs.size() < 2 || vargs[1].representsNonPositive());}
representsNumber(const MathStructure & vargs,bool) const520 bool RoundFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsRational(const MathStructure & vargs,bool) const521 bool RoundFunction::representsRational(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsReal(const MathStructure & vargs,bool) const522 bool RoundFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonComplex(const MathStructure & vargs,bool) const523 bool RoundFunction::representsNonComplex(const MathStructure &vargs, bool) const {return true;}
representsComplex(const MathStructure &,bool) const524 bool RoundFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure &,bool) const525 bool RoundFunction::representsNonZero(const MathStructure&, bool) const {return false;}
representsEven(const MathStructure & vargs,bool) const526 bool RoundFunction::representsEven(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsEven() && (vargs.size() < 2 || vargs[1].representsNonPositive());}
representsOdd(const MathStructure & vargs,bool) const527 bool RoundFunction::representsOdd(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsOdd() && (vargs.size() < 2 || vargs[1].representsNonPositive());}
representsUndefined(const MathStructure &) const528 bool RoundFunction::representsUndefined(const MathStructure&) const {return false;}
529 
FracFunction()530 FracFunction::FracFunction() : MathFunction("frac", 1) {
531 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(1)
532 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)533 int FracFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
534 	FR_FUNCTION(frac)
535 }
IntFunction()536 IntFunction::IntFunction() : MathFunction("int", 1) {
537 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(1)
538 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)539 int IntFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
540 	FR_FUNCTION(trunc)
541 }
NumeratorFunction()542 NumeratorFunction::NumeratorFunction() : MathFunction("numerator", 1) {
543 	NumberArgument *arg_rational_1 = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
544 	arg_rational_1->setRationalNumber(true);
545 	arg_rational_1->setHandleVector(true);
546 	setArgumentDefinition(1, arg_rational_1);
547 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)548 int NumeratorFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
549 	if(vargs[0].isVector()) return 0;
550 	if(vargs[0].isNumber()) {
551 		if(vargs[0].number().isInteger()) {
552 			mstruct = vargs[0];
553 			return 1;
554 		} else if(vargs[0].number().isRational()) {
555 			mstruct.set(vargs[0].number().numerator());
556 			return 1;
557 		}
558 		return 0;
559 	} else if(vargs[0].representsInteger()) {
560 		mstruct = vargs[0];
561 		return 1;
562 	}
563 	mstruct = vargs[0];
564 	mstruct.eval(eo);
565 	if(mstruct.isVector()) return -1;
566 	if(mstruct.representsInteger()) {
567 		return 1;
568 	} else if(mstruct.isNumber() && mstruct.number().isRational()) {
569 		Number nr(mstruct.number().numerator());
570 		mstruct.set(nr);
571 		return 1;
572 	}
573 	return -1;
574 }
DenominatorFunction()575 DenominatorFunction::DenominatorFunction() : MathFunction("denominator", 1) {
576 	RATIONAL_NUMBER_ARGUMENT_NO_ERROR(1)
577 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)578 int DenominatorFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
579 	mstruct.set(vargs[0].number().denominator());
580 	return 1;
581 }
RemFunction()582 RemFunction::RemFunction() : MathFunction("rem", 2) {
583 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(1)
584 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR_NONZERO(2)
585 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)586 int RemFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
587 	FR_FUNCTION_2(rem)
588 }
ModFunction()589 ModFunction::ModFunction() : MathFunction("mod", 2) {
590 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR(1)
591 	NON_COMPLEX_NUMBER_ARGUMENT_NO_ERROR_NONZERO(2)
592 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)593 int ModFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
594 	FR_FUNCTION_2(mod)
595 }
596 
BernoulliFunction()597 BernoulliFunction::BernoulliFunction() : MathFunction("bernoulli", 1, 2) {
598 	setArgumentDefinition(1, new IntegerArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE));
599 	setDefaultValue(2, "0");
600 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)601 int BernoulliFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
602 	if(vargs.size() > 1 && !vargs[1].isZero()) {
603 		MathStructure m2(vargs[1]);
604 		replace_f_interval(m2, eo);
605 		replace_intervals_f(m2);
606 		mstruct.clear();
607 		Number bin, k, nmk(vargs[0].number()), nrB;
608 		while(k <= vargs[0].number()) {
609 			if(nmk.isEven() || nmk.isOne()) {
610 				nrB.set(nmk);
611 				if(!bin.binomial(vargs[0].number(), k) || !nrB.bernoulli() || !nrB.multiply(bin)) return 0;
612 				if(eo.approximation == APPROXIMATION_EXACT && nrB.isApproximate()) return 0;
613 				mstruct.add(nrB, true);
614 				mstruct.last().multiply(m2);
615 				mstruct.last().last().raise(k);
616 				mstruct.childUpdated(mstruct.size());
617 			}
618 			nmk--;
619 			k++;
620 		}
621 		if(mstruct.isAddition()) mstruct.delChild(1, true);
622 		return 1;
623 	}
624 	FR_FUNCTION(bernoulli)
625 }
626 
TotientFunction()627 TotientFunction::TotientFunction() : MathFunction("totient", 1, 1) {
628 	setArgumentDefinition(1, new IntegerArgument());
629 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)630 int TotientFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
631 	if(vargs[0].number().isZero()) {mstruct.clear(); return 1;}
632 	if(vargs[0].number() <= 2 && vargs[0].number() >= -2) {mstruct.set(1, 1, 0); return 1;}
633 	mpz_t n, result, tmp, p_square, p;
634 	mpz_inits(n, result, tmp, p_square, p, NULL);
635 	mpz_set(n, mpq_numref(vargs[0].number().internalRational()));
636 	mpz_abs(n, n);
637 	mpz_set(result, n);
638 	size_t i = 0;
639 	while(true) {
640 		if(CALCULATOR->aborted()) {mpz_clears(n, result, tmp, p, p_square, NULL); return 0;}
641 		if(i < NR_OF_PRIMES) {
642 			if(i < NR_OF_SQUARE_PRIMES) {
643 				if(mpz_cmp_si(n, SQUARE_PRIMES[i]) < 0) break;
644 			} else {
645 				mpz_ui_pow_ui(p_square, PRIMES[i], 2);
646 				if(mpz_cmp(n, p_square) < 0) break;
647 			}
648 			if(mpz_divisible_ui_p(n, PRIMES[i])) {
649 				mpz_divexact_ui(n, n, PRIMES[i]);
650 				while(mpz_divisible_ui_p(n, PRIMES[i])) mpz_divexact_ui(n, n, PRIMES[i]);
651 				mpz_divexact_ui(tmp, result, PRIMES[i]);
652 				mpz_sub(result, result, tmp);
653 			}
654 			i++;
655 		} else {
656 			if(i == NR_OF_PRIMES) {mpz_set_si(p, PRIMES[i - 1]); i++;}
657 			mpz_add_ui(p, p, 2);
658 			mpz_pow_ui(p_square, p, 2);
659 			if(mpz_cmp(n, p_square) < 0) break;
660 			if(mpz_divisible_p(n, p)) {
661 				mpz_divexact(n, n, p);
662 				while(mpz_divisible_p(n, p)) mpz_divexact(n, n, p);
663 				mpz_divexact(tmp, result, p);
664 				mpz_sub(result, result, tmp);
665 			}
666 		}
667 	}
668 	if(mpz_cmp_ui(n, 1) > 0) {
669 		mpz_divexact(tmp, result, n);
670 		mpz_sub(result, result, tmp);
671 	}
672 	mstruct.clear();
673 	mstruct.number().setInternal(result);
674 	mpz_clears(n, result, tmp, p, p_square, NULL);
675 	return 1;
676 }
677 
PolynomialUnitFunction()678 PolynomialUnitFunction::PolynomialUnitFunction() : MathFunction("punit", 1, 2) {
679 	RATIONAL_POLYNOMIAL_ARGUMENT(1)
680 	setArgumentDefinition(2, new SymbolicArgument());
681 	setDefaultValue(2, "undefined");
682 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)683 int PolynomialUnitFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
684 	mstruct.set(vargs[0].polynomialUnit(vargs[1]), 0);
685 	return 1;
686 }
PolynomialPrimpartFunction()687 PolynomialPrimpartFunction::PolynomialPrimpartFunction() : MathFunction("primpart", 1, 2) {
688 	RATIONAL_POLYNOMIAL_ARGUMENT(1)
689 	setArgumentDefinition(2, new SymbolicArgument());
690 	setDefaultValue(2, "undefined");
691 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)692 int PolynomialPrimpartFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
693 	vargs[0].polynomialPrimpart(vargs[1], mstruct, eo);
694 	return 1;
695 }
PolynomialContentFunction()696 PolynomialContentFunction::PolynomialContentFunction() : MathFunction("pcontent", 1, 2) {
697 	RATIONAL_POLYNOMIAL_ARGUMENT(1)
698 	setArgumentDefinition(2, new SymbolicArgument());
699 	setDefaultValue(2, "undefined");
700 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)701 int PolynomialContentFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
702 	vargs[0].polynomialContent(vargs[1], mstruct, eo);
703 	return 1;
704 }
CoeffFunction()705 CoeffFunction::CoeffFunction() : MathFunction("coeff", 2, 3) {
706 	RATIONAL_POLYNOMIAL_ARGUMENT(1)
707 	setArgumentDefinition(2, new IntegerArgument("", ARGUMENT_MIN_MAX_NONNEGATIVE));
708 	setArgumentDefinition(3, new SymbolicArgument());
709 	setDefaultValue(3, "undefined");
710 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)711 int CoeffFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
712 	vargs[0].coefficient(vargs[2], vargs[1].number(), mstruct);
713 	return 1;
714 }
LCoeffFunction()715 LCoeffFunction::LCoeffFunction() : MathFunction("lcoeff", 1, 2) {
716 	RATIONAL_POLYNOMIAL_ARGUMENT(1)
717 	setArgumentDefinition(2, new SymbolicArgument());
718 	setDefaultValue(2, "undefined");
719 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)720 int LCoeffFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
721 	vargs[0].lcoefficient(vargs[1], mstruct);
722 	return 1;
723 }
TCoeffFunction()724 TCoeffFunction::TCoeffFunction() : MathFunction("tcoeff", 1, 2) {
725 	RATIONAL_POLYNOMIAL_ARGUMENT(1)
726 	setArgumentDefinition(2, new SymbolicArgument());
727 	setDefaultValue(2, "undefined");
728 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)729 int TCoeffFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
730 	vargs[0].tcoefficient(vargs[1], mstruct);
731 	return 1;
732 }
DegreeFunction()733 DegreeFunction::DegreeFunction() : MathFunction("degree", 1, 2) {
734 	RATIONAL_POLYNOMIAL_ARGUMENT(1)
735 	setArgumentDefinition(2, new SymbolicArgument());
736 	setDefaultValue(2, "undefined");
737 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)738 int DegreeFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
739 	mstruct = vargs[0].degree(vargs[1]);
740 	return 1;
741 }
LDegreeFunction()742 LDegreeFunction::LDegreeFunction() : MathFunction("ldegree", 1, 2) {
743 	RATIONAL_POLYNOMIAL_ARGUMENT(1)
744 	setArgumentDefinition(2, new SymbolicArgument());
745 	setDefaultValue(2, "undefined");
746 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)747 int LDegreeFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
748 	mstruct = vargs[0].ldegree(vargs[1]);
749 	return 1;
750 }
751 
752 
BinFunction()753 BinFunction::BinFunction() : MathFunction("bin", 1, 2) {
754 	setArgumentDefinition(1, new TextArgument());
755 	setArgumentDefinition(2, new BooleanArgument());
756 	setDefaultValue(2, "0");
757 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)758 int BinFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
759 	ParseOptions po = eo.parse_options;
760 	po.base = BASE_BINARY;
761 	po.twos_complement = vargs[1].number().getBoolean();
762 	CALCULATOR->parse(&mstruct, vargs[0].symbol(), po);
763 	return 1;
764 }
OctFunction()765 OctFunction::OctFunction() : MathFunction("oct", 1) {
766 	setArgumentDefinition(1, new TextArgument());
767 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)768 int OctFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
769 	ParseOptions po = eo.parse_options;
770 	po.base = BASE_OCTAL;
771 	CALCULATOR->parse(&mstruct, vargs[0].symbol(), po);
772 	return 1;
773 }
DecFunction()774 DecFunction::DecFunction() : MathFunction("dec", 1) {
775 	setArgumentDefinition(1, new TextArgument());
776 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)777 int DecFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
778 	ParseOptions po = eo.parse_options;
779 	po.base = BASE_DECIMAL;
780 	CALCULATOR->parse(&mstruct, vargs[0].symbol(), po);
781 	return 1;
782 }
HexFunction()783 HexFunction::HexFunction() : MathFunction("hex", 1, 2) {
784 	setArgumentDefinition(1, new TextArgument());
785 	setArgumentDefinition(2, new BooleanArgument());
786 	setDefaultValue(2, "0");
787 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)788 int HexFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
789 	ParseOptions po = eo.parse_options;
790 	po.base = BASE_HEXADECIMAL;
791 	po.hexadecimal_twos_complement = vargs[1].number().getBoolean();
792 	CALCULATOR->parse(&mstruct, vargs[0].symbol(), po);
793 	return 1;
794 }
795 
BaseFunction()796 BaseFunction::BaseFunction() : MathFunction("base", 2, 3) {
797 	setArgumentDefinition(1, new TextArgument());
798 	Argument *arg = new Argument();
799 	arg->setHandleVector(true);
800 	setArgumentDefinition(2, arg);
801 	IntegerArgument *arg2 = new IntegerArgument();
802 	arg2->setMin(&nr_zero);
803 	arg2->setMax(&nr_three);
804 	setArgumentDefinition(3, arg2);
805 	setArgumentDefinition(3, new TextArgument());
806 	setDefaultValue(3, "0");
807 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)808 int BaseFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
809 	if(vargs[1].isVector()) return 0;
810 	Number nbase;
811 	int idigits = 0;
812 	string sdigits;
813 	if(vargs.size() > 2) sdigits = vargs[2].symbol();
814 	if(sdigits.empty() || sdigits == "0" || sdigits == "auto") idigits = 0;
815 	else if(sdigits == "1") idigits = 1;
816 	else if(sdigits == "2") idigits = 2;
817 	else if(sdigits == "3" || sdigits == "Unicode" || sdigits == "unicode" || sdigits == "escaped") idigits = 3;
818 	else if(sdigits == "4" || sdigits == _("phoneword")) idigits = 4;
819 	else {
820 		size_t i = sdigits.find("|");
821 		if(i != string::npos && sdigits.find("|", i + 1) != string::npos) {
822 			idigits = -4;
823 		} else {
824 			i = sdigits.find(";");
825 			if(i != string::npos && sdigits.find(";", i + 1) != string::npos) {
826 				idigits = -3;
827 			} else {
828 				i = sdigits.find(",");
829 				if(i != string::npos && sdigits.find(",", i + 1) != string::npos) idigits = -2;
830 				else idigits = -1;
831 			}
832 		}
833 		i = sdigits.find(" ");
834 		if(i != string::npos && sdigits.find(" ", i + 1) != string::npos) remove_blanks(sdigits);
835 		if(idigits == -2 || idigits == -3) {
836 			if((sdigits[0] == LEFT_VECTOR_WRAP_CH && sdigits[sdigits.size() - 1] == RIGHT_VECTOR_WRAP_CH) || (sdigits[0] == LEFT_PARENTHESIS_CH && sdigits[sdigits.size() - 1] == RIGHT_PARENTHESIS_CH)) {
837 				sdigits = sdigits.substr(1, sdigits.size() - 2);
838 			}
839 		}
840 	}
841 	if(vargs[1].isNumber() && idigits == 0) {
842 		nbase = vargs[1].number();
843 	} else {
844 		mstruct = vargs[1];
845 		mstruct.eval(eo);
846 		if(mstruct.isVector()) return -2;
847 		if(idigits == 0 && !mstruct.isNumber() && eo.approximation == APPROXIMATION_EXACT) {
848 			MathStructure mstruct2(mstruct);
849 			EvaluationOptions eo2 = eo;
850 			eo2.approximation = APPROXIMATION_TRY_EXACT;
851 			CALCULATOR->beginTemporaryStopMessages();
852 			mstruct2.eval(eo2);
853 			if(mstruct2.isVector() || mstruct2.isNumber()) {
854 				mstruct = mstruct2;
855 				CALCULATOR->endTemporaryStopMessages(true);
856 				if(mstruct.isVector()) return -2;
857 			} else {
858 				CALCULATOR->endTemporaryStopMessages();
859 			}
860 		}
861 		if(mstruct.isNumber() && idigits == 0) {
862 			nbase = mstruct.number();
863 		} else {
864 			string number = vargs[0].symbol();
865 			size_t i_dot = number.length();
866 			vector<Number> digits;
867 			bool b_minus = false;
868 			if(idigits < 0) {
869 				vector<unordered_map<string, long int>> vdigits;
870 				string schar;
871 				long int v = 0;
872 				size_t d_i = 0;
873 				for(size_t i = 0; i < sdigits.length();) {
874 					if((idigits == -2 && sdigits[i] == ',') || (idigits == -3 && sdigits[i] == ';') || (idigits == -4 && sdigits[i] == '|')) {
875 						d_i = 0; v++; i++;
876 					} else {
877 						size_t l = 1;
878 						while(i + l < sdigits.length() && sdigits[i + l] <= 0 && (unsigned char) sdigits[i + l] < 0xC0) l++;
879 						if(d_i == vdigits.size()) vdigits.resize(d_i + 1);
880 						vdigits[d_i][sdigits.substr(i, l)] = v;
881 						i += l;
882 						if(idigits < -1) d_i++;
883 						else v++;
884 					}
885 				}
886 				i_dot = number.length();
887 				for(size_t i = 0; i < number.length();) {
888 					size_t l = 1;
889 					while(i + l < number.length() && number[i + l] <= 0 && (unsigned char) number[i + l] < 0xC0) l++;
890 					for(d_i = 0; d_i < vdigits.size(); d_i++) {
891 						unordered_map<string, long int>::iterator it = vdigits[d_i].find(number.substr(i, l));
892 						if(it != vdigits[d_i].end()) {
893 							digits.push_back(it->second);
894 							break;
895 						}
896 					}
897 					if(d_i == vdigits.size()) {
898 						if(l == 1 && (number[i] == CALCULATOR->getDecimalPoint()[0] || (!eo.parse_options.dot_as_separator && number[i] == '.'))) {
899 							if(i_dot == number.length()) i_dot = digits.size();
900 						} else if(!is_in(SPACES, number[i])) {
901 							CALCULATOR->error(true, _("Character \'%s\' was ignored in the number \"%s\" with base %s."), number.substr(i, l).c_str(), number.c_str(), format_and_print(mstruct).c_str(), NULL);
902 						}
903 					}
904 					i += l;
905 				}
906 			} else if(idigits == 4 || idigits == 5) {
907 				for(size_t i = 0; i < number.length();) {
908 					size_t l = 1;
909 					while(i + l < number.length() && number[i + l] <= 0 && (unsigned char) number[i + l] < 0xC0) l++;
910 					char c = 0;
911 					if(l == 1) {
912 						c = number[i];
913 					} else if(l == 2 && number[i] == -61) {
914 						if(number[i + 1] >= -128 && number[i + 1] <= -122) c = 'A';
915 						else if(number[i + 1] == -121) c = 'C';
916 						else if(number[i + 1] >= -120 && number[i + 1] <= -117) c = 'E';
917 						else if(number[i + 1] >= -116 && number[i + 1] <= -113) c = 'I';
918 						//else if(number[i + 1] == -112) c = 'D';
919 						else if(number[i + 1] == -111) c = 'N';
920 						else if(number[i + 1] >= -110 && number[i + 1] <= -106) c = 'O';
921 						else if(number[i + 1] == -104) c = 'O';
922 						else if(number[i + 1] >= -103 && number[i + 1] <= -100) c = 'U';
923 						else if(number[i + 1] == -99) c = 'Y';
924 						//else if(number[i + 1] == -98) c = 'T';
925 						else if(number[i + 1] == -97) c = 'S';
926 						else if(number[i + 1] >= -96 && number[i + 1] <= -90) c = 'a';
927 						else if(number[i + 1] == -89) c = 'c';
928 						else if(number[i + 1] >= -88 && number[i + 1] <= -85) c = 'e';
929 						else if(number[i + 1] >= -84 && number[i + 1] <= -81) c = 'i';
930 						//else if(number[i + 1] == -80) c = 'd';
931 						else if(number[i + 1] == -79) c = 'n';
932 						else if(number[i + 1] >= -78 && number[i + 1] <= -74) c = 'o';
933 						else if(number[i + 1] == -72) c = 'o';
934 						else if(number[i + 1] >= -71 && number[i + 1] <= -68) c = 'u';
935 						else if(number[i + 1] == -67) c = 'y';
936 						//else if(number[i + 1] == -66) c = 't';
937 						else if(number[i + 1] == -65) c = 'y';
938 					}
939 					if(c != 0) {
940 						if(c == '0') digits.push_back(0);
941 						else if(c == '1') digits.push_back(1);
942 						else if(is_in("2abcABC", c)) digits.push_back(2);
943 						else if(is_in("3defDEF", c)) digits.push_back(3);
944 						else if(is_in("4ghiGHI", c)) digits.push_back(4);
945 						else if(is_in("5jklJKL", c)) digits.push_back(5);
946 						else if(is_in("6mnoMNO", c)) digits.push_back(6);
947 						else if(is_in("7pqrsPQRS", c)) digits.push_back(7);
948 						else if(is_in("8tuvTUV", c)) digits.push_back(8);
949 						else if(is_in("9wxyzWXYZ", c)) digits.push_back(9);
950 					}
951 					i += l;
952 				}
953 			} else if(idigits <= 2) {
954 				remove_blanks(number);
955 				bool b_case = (idigits == 2);
956 				i_dot = number.length();
957 				for(size_t i = 0; i < number.length(); i++) {
958 					long int c = -1;
959 					if(number[i] >= '0' && number[i] <= '9') {
960 						c = number[i] - '0';
961 					} else if(number[i] >= 'a' && number[i] <= 'z') {
962 						if(b_case) c = number[i] - 'a' + 36;
963 						else c = number[i] - 'a' + 10;
964 					} else if(number[i] >= 'A' && number[i] <= 'Z') {
965 						c = number[i] - 'A' + 10;
966 					} else if(number[i] == CALCULATOR->getDecimalPoint()[0] || (!eo.parse_options.dot_as_separator && number[i] == '.')) {
967 						if(i_dot == number.length()) i_dot = digits.size();
968 					} else if(number[i] == '-' && digits.empty()) {
969 						b_minus = !b_minus;
970 					} else {
971 						string str_char = number.substr(i, 1);
972 						while(i + 1 < number.length() && number[i + 1] < 0 && number[i + 1] && (unsigned char) number[i + 1] < 0xC0) {
973 							i++;
974 							str_char += number[i];
975 						}
976 						CALCULATOR->error(true, _("Character \'%s\' was ignored in the number \"%s\" with base %s."), str_char.c_str(), number.c_str(), format_and_print(mstruct).c_str(), NULL);
977 					}
978 					if(c >= 0) {
979 						digits.push_back(c);
980 					}
981 				}
982 			} else {
983 				for(size_t i = 0; i < number.length(); i++) {
984 					long int c = (unsigned char) number[i];
985 					bool b_esc = false;
986 					if(number[i] == '\\' && i < number.length() - 1) {
987 						i++;
988 						Number nrd;
989 						if(is_in(NUMBERS, number[i])) {
990 							size_t i2 = number.find_first_not_of(NUMBERS, i);
991 							if(i2 == string::npos) i2 = number.length();
992 							nrd.set(number.substr(i, i2 - i));
993 							i = i2 - 1;
994 							b_esc = true;
995 						} else if(number[i] == 'x' && i < number.length() - 1 && is_in(NUMBERS "ABCDEFabcdef", number[i + 1])) {
996 							i++;
997 							size_t i2 = number.find_first_not_of(NUMBERS "ABCDEFabcdef", i);
998 							if(i2 == string::npos) i2 = number.length();
999 							ParseOptions po;
1000 							po.base = BASE_HEXADECIMAL;
1001 							nrd.set(number.substr(i, i2 - i), po);
1002 							i = i2 - 1;
1003 							b_esc = true;
1004 						}
1005 						if(digits.empty() && number[i] == (char) -30 && i + 3 < number.length() && number[i + 1] == (char) -120 && number[i + 2] == (char) -110) {
1006 							i += 2;
1007 							b_minus = !b_minus;
1008 							b_esc = true;
1009 						} else if(digits.empty() && number[i] == '-') {
1010 							b_minus = !b_minus;
1011 							b_esc = true;
1012 						} else if(i_dot == number.size() && (number[i] == CALCULATOR->getDecimalPoint()[0] || (!eo.parse_options.dot_as_separator && number[i] == '.'))) {
1013 							i_dot = digits.size();
1014 							b_esc = true;
1015 						} else if(b_esc) {
1016 							digits.push_back(nrd);
1017 
1018 						} else if(number[i] != '\\') {
1019 							i--;
1020 						}
1021 					}
1022 					if(!b_esc) {
1023 						if((c & 0x80) != 0) {
1024 							if(c<0xe0) {
1025 								i++;
1026 								if(i >= number.length()) return -2;
1027 								c = ((c & 0x1f) << 6) | (((unsigned char) number[i]) & 0x3f);
1028 							} else if(c<0xf0) {
1029 								i++;
1030 								if(i + 1 >= number.length()) return -2;
1031 								c = (((c & 0xf) << 12) | ((((unsigned char) number[i]) & 0x3f) << 6)|(((unsigned char) number[i + 1]) & 0x3f));
1032 								i++;
1033 							} else {
1034 								i++;
1035 								if(i + 2 >= number.length()) return -2;
1036 								c = ((c & 7) << 18) | ((((unsigned char) number[i]) & 0x3f) << 12) | ((((unsigned char) number[i + 1]) & 0x3f) << 6) | (((unsigned char) number[i + 2]) & 0x3f);
1037 								i += 2;
1038 							}
1039 						}
1040 						digits.push_back(c);
1041 					}
1042 				}
1043 			}
1044 			MathStructure mbase = mstruct;
1045 			mstruct.clear();
1046 			if(i_dot > digits.size()) i_dot = digits.size();
1047 			for(size_t i = 0; i < digits.size(); i++) {
1048 				long int exp = i_dot - 1 - i;
1049 				MathStructure m;
1050 				if(exp != 0) {
1051 					m = mbase;
1052 					m.raise(Number(exp, 1));
1053 					m.multiply(digits[i]);
1054 				} else {
1055 					m.set(digits[i]);
1056 				}
1057 				if(mstruct.isZero()) mstruct = m;
1058 				else mstruct.add(m, true);
1059 			}
1060 			if(b_minus) mstruct.negate();
1061 			return 1;
1062 		}
1063 	}
1064 	ParseOptions po = eo.parse_options;
1065 	if(nbase.isInteger() && nbase >= 2 && nbase <= 36) {
1066 		po.base = nbase.intValue();
1067 		CALCULATOR->parse(&mstruct, vargs[0].symbol(), po);
1068 	} else {
1069 		po.base = BASE_CUSTOM;
1070 		Number cb_save = CALCULATOR->customInputBase();
1071 		CALCULATOR->setCustomInputBase(nbase);
1072 		CALCULATOR->parse(&mstruct, vargs[0].symbol(), po);
1073 		CALCULATOR->setCustomInputBase(cb_save);
1074 	}
1075 	return 1;
1076 }
RomanFunction()1077 RomanFunction::RomanFunction() : MathFunction("roman", 1) {
1078 	setArgumentDefinition(1, new TextArgument());
1079 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1080 int RomanFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1081 	if(vargs[0].symbol().find_first_not_of("0123456789.:" SIGNS) == string::npos && vargs[0].symbol().find_first_not_of("0" SIGNS) != string::npos) {
1082 		CALCULATOR->parse(&mstruct, vargs[0].symbol(), eo.parse_options);
1083 		PrintOptions po; po.base = BASE_ROMAN_NUMERALS;
1084 		mstruct.eval(eo);
1085 		mstruct.set(mstruct.print(po), true, true);
1086 		return 1;
1087 	}
1088 	ParseOptions po = eo.parse_options;
1089 	po.base = BASE_ROMAN_NUMERALS;
1090 	CALCULATOR->parse(&mstruct, vargs[0].symbol(), po);
1091 	return 1;
1092 }
BijectiveFunction()1093 BijectiveFunction::BijectiveFunction() : MathFunction("bijective", 1) {
1094 	setArgumentDefinition(1, new TextArgument());
1095 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1096 int BijectiveFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1097 	if(vargs[0].symbol().find_first_not_of("0123456789.:" SIGNS) == string::npos && vargs[0].symbol().find_first_not_of(SIGNS) != string::npos) {
1098 		CALCULATOR->parse(&mstruct, vargs[0].symbol(), eo.parse_options);
1099 		PrintOptions po; po.base = BASE_BIJECTIVE_26;
1100 		mstruct.eval(eo);
1101 		mstruct.set(mstruct.print(po), true, true);
1102 		return 1;
1103 	}
1104 	ParseOptions po = eo.parse_options;
1105 	po.base = BASE_BIJECTIVE_26;
1106 	CALCULATOR->parse(&mstruct, vargs[0].symbol(), po);
1107 	return 1;
1108 }
ImFunction()1109 ImFunction::ImFunction() : MathFunction("im", 1) {
1110 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
1111 	arg->setHandleVector(true);
1112 	setArgumentDefinition(1, arg);
1113 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1114 int ImFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1115 	if(vargs[0].isVector()) return 0;
1116 	mstruct = vargs[0];
1117 	mstruct.eval(eo);
1118 	if(mstruct.isVector()) return -1;
1119 	if(mstruct.isNumber()) {
1120 		mstruct = mstruct.number().imaginaryPart();
1121 		return 1;
1122 	} else if(mstruct.representsReal(!eo.keep_zero_units)) {
1123 		mstruct.clear(true);
1124 		return 1;
1125 	} else if(mstruct.isUnit_exp()) {
1126 		mstruct *= m_zero;
1127 		mstruct.swapChildren(1, 2);
1128 		return 1;
1129 	} else if(mstruct.isPower() && mstruct[1].isNumber() && mstruct[1].number().denominatorIsTwo() && mstruct[0].representsNegative()) {
1130 		mstruct[0].negate();
1131 		Number num = mstruct[1].number().numerator();
1132 		num.rem(4);
1133 		if(num == 3 || num == -1) mstruct.negate();
1134 		return 1;
1135 	} else if(mstruct.isMultiplication() && mstruct.size() > 0) {
1136 		if(mstruct[0].isNumber()) {
1137 			Number nr = mstruct[0].number();
1138 			mstruct.delChild(1, true);
1139 			if(nr.hasImaginaryPart()) {
1140 				if(nr.hasRealPart()) {
1141 					MathStructure *madd = new MathStructure(mstruct);
1142 					mstruct.transformById(FUNCTION_ID_RE);
1143 					madd->transform(this);
1144 					madd->multiply(nr.realPart());
1145 					mstruct.multiply(nr.imaginaryPart());
1146 					mstruct.add_nocopy(madd);
1147 					return 1;
1148 				}
1149 				mstruct.transformById(FUNCTION_ID_RE);
1150 				mstruct.multiply(nr.imaginaryPart());
1151 				return 1;
1152 			}
1153 			mstruct.transform(this);
1154 			mstruct.multiply(nr.realPart());
1155 			return 1;
1156 		}
1157 		MathStructure *mreal = NULL;
1158 		for(size_t i = 0; i < mstruct.size();) {
1159 			if(mstruct[i].representsReal(true)) {
1160 				if(!mreal) {
1161 					mreal = new MathStructure(mstruct[i]);
1162 				} else {
1163 					mstruct[i].ref();
1164 					if(!mreal->isMultiplication()) mreal->transform(STRUCT_MULTIPLICATION);
1165 					mreal->addChild_nocopy(&mstruct[i]);
1166 				}
1167 				mstruct.delChild(i + 1);
1168 			} else {
1169 				i++;
1170 			}
1171 		}
1172 		if(mreal) {
1173 			if(mstruct.size() == 0) mstruct.clear(true);
1174 			else if(mstruct.size() == 1) mstruct.setToChild(1, true);
1175 			mstruct.transform(this);
1176 			mstruct.multiply_nocopy(mreal);
1177 			return 1;
1178 		}
1179 	}
1180 	return -1;
1181 }
representsPositive(const MathStructure &,bool) const1182 bool ImFunction::representsPositive(const MathStructure&, bool) const {return false;}
representsNegative(const MathStructure &,bool) const1183 bool ImFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool) const1184 bool ImFunction::representsNonNegative(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNonPositive(const MathStructure & vargs,bool) const1185 bool ImFunction::representsNonPositive(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsInteger(const MathStructure & vargs,bool) const1186 bool ImFunction::representsInteger(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsNumber(const MathStructure & vargs,bool) const1187 bool ImFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsRational(const MathStructure & vargs,bool) const1188 bool ImFunction::representsRational(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsReal(const MathStructure & vargs,bool) const1189 bool ImFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber();}
representsNonComplex(const MathStructure & vargs,bool) const1190 bool ImFunction::representsNonComplex(const MathStructure &vargs, bool) const {return true;}
representsComplex(const MathStructure &,bool) const1191 bool ImFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure & vargs,bool) const1192 bool ImFunction::representsNonZero(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsComplex();}
representsEven(const MathStructure & vargs,bool) const1193 bool ImFunction::representsEven(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsReal();}
representsOdd(const MathStructure &,bool) const1194 bool ImFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const1195 bool ImFunction::representsUndefined(const MathStructure&) const {return false;}
1196 
ReFunction()1197 ReFunction::ReFunction() : MathFunction("re", 1) {
1198 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
1199 	arg->setHandleVector(true);
1200 	setArgumentDefinition(1, arg);
1201 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1202 int ReFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1203 	if(vargs[0].isVector()) return 0;
1204 	mstruct = vargs[0];
1205 	mstruct.eval(eo);
1206 	if(mstruct.isVector()) return -1;
1207 	if(mstruct.isNumber()) {
1208 		mstruct = mstruct.number().realPart();
1209 		return 1;
1210 	} else if(mstruct.representsReal(true)) {
1211 		return 1;
1212 	} else if(mstruct.isPower() && mstruct[1].isNumber() && mstruct[1].number().denominatorIsTwo() && mstruct[0].representsNegative()) {
1213 		mstruct.clear(true);
1214 		return 1;
1215 	} else if(mstruct.isMultiplication() && mstruct.size() > 0) {
1216 		if(mstruct[0].isNumber()) {
1217 			Number nr = mstruct[0].number();
1218 			mstruct.delChild(1, true);
1219 			if(nr.hasImaginaryPart()) {
1220 				if(nr.hasRealPart()) {
1221 					MathStructure *madd = new MathStructure(mstruct);
1222 					mstruct.transformById(FUNCTION_ID_IM);
1223 					madd->transform(this);
1224 					madd->multiply(nr.realPart());
1225 					mstruct.multiply(-nr.imaginaryPart());
1226 					mstruct.add_nocopy(madd);
1227 					return 1;
1228 				}
1229 				mstruct.transformById(FUNCTION_ID_IM);
1230 				mstruct.multiply(-nr.imaginaryPart());
1231 				return 1;
1232 			}
1233 			mstruct.transform(this);
1234 			mstruct.multiply(nr.realPart());
1235 			return 1;
1236 		}
1237 		MathStructure *mreal = NULL;
1238 		for(size_t i = 0; i < mstruct.size();) {
1239 			if(mstruct[i].representsReal(true)) {
1240 				if(!mreal) {
1241 					mreal = new MathStructure(mstruct[i]);
1242 				} else {
1243 					mstruct[i].ref();
1244 					if(!mreal->isMultiplication()) mreal->transform(STRUCT_MULTIPLICATION);
1245 					mreal->addChild_nocopy(&mstruct[i]);
1246 				}
1247 				mstruct.delChild(i + 1);
1248 			} else {
1249 				i++;
1250 			}
1251 		}
1252 		if(mreal) {
1253 			if(mstruct.size() == 0) mstruct.clear(true);
1254 			else if(mstruct.size() == 1) mstruct.setToChild(1, true);
1255 			mstruct.transform(this);
1256 			mstruct.multiply_nocopy(mreal);
1257 			return 1;
1258 		}
1259 	}
1260 	return -1;
1261 }
representsPositive(const MathStructure & vargs,bool allow_units) const1262 bool ReFunction::representsPositive(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsPositive(allow_units);}
representsNegative(const MathStructure & vargs,bool allow_units) const1263 bool ReFunction::representsNegative(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNegative(allow_units);}
representsNonNegative(const MathStructure & vargs,bool allow_units) const1264 bool ReFunction::representsNonNegative(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNonNegative(allow_units);}
representsNonPositive(const MathStructure & vargs,bool allow_units) const1265 bool ReFunction::representsNonPositive(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNonPositive(allow_units);}
representsInteger(const MathStructure & vargs,bool allow_units) const1266 bool ReFunction::representsInteger(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsInteger(allow_units);}
representsNumber(const MathStructure & vargs,bool allow_units) const1267 bool ReFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsRational(const MathStructure & vargs,bool allow_units) const1268 bool ReFunction::representsRational(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsRational(allow_units);}
representsReal(const MathStructure & vargs,bool allow_units) const1269 bool ReFunction::representsReal(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsNumber(allow_units);}
representsNonComplex(const MathStructure & vargs,bool) const1270 bool ReFunction::representsNonComplex(const MathStructure &vargs, bool) const {return true;}
representsComplex(const MathStructure &,bool) const1271 bool ReFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure & vargs,bool allow_units) const1272 bool ReFunction::representsNonZero(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsReal(allow_units) && vargs[0].representsNonZero(true);}
representsEven(const MathStructure & vargs,bool allow_units) const1273 bool ReFunction::representsEven(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsEven(allow_units);}
representsOdd(const MathStructure & vargs,bool allow_units) const1274 bool ReFunction::representsOdd(const MathStructure &vargs, bool allow_units) const {return vargs.size() == 1 && vargs[0].representsOdd(allow_units);}
representsUndefined(const MathStructure &) const1275 bool ReFunction::representsUndefined(const MathStructure&) const {return false;}
1276 
ArgFunction()1277 ArgFunction::ArgFunction() : MathFunction("arg", 1) {
1278 	Argument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, false);
1279 	arg->setHandleVector(true);
1280 	setArgumentDefinition(1, arg);
1281 }
representsNumber(const MathStructure & vargs,bool) const1282 bool ArgFunction::representsNumber(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber(true);}
representsReal(const MathStructure & vargs,bool) const1283 bool ArgFunction::representsReal(const MathStructure &vargs, bool) const {return vargs.size() == 1 && vargs[0].representsNumber(true);}
representsNonComplex(const MathStructure & vargs,bool) const1284 bool ArgFunction::representsNonComplex(const MathStructure &vargs, bool) const {return true;}
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1285 int ArgFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1286 	if(vargs[0].isVector()) return 0;
1287 	mstruct = vargs[0];
1288 	mstruct.eval(eo);
1289 	if(mstruct.isVector()) return -1;
1290 
1291 	MathStructure msave;
1292 
1293 	arg_test_non_number:
1294 	if(!mstruct.isNumber()) {
1295 		if(mstruct.representsPositive(true)) {
1296 			mstruct.clear();
1297 			return 1;
1298 		}
1299 		if(mstruct.representsNegative(true)) {
1300 			switch(eo.parse_options.angle_unit) {
1301 				case ANGLE_UNIT_DEGREES: {mstruct.set(180, 1, 0); break;}
1302 				case ANGLE_UNIT_GRADIANS: {mstruct.set(200, 1, 0); break;}
1303 				case ANGLE_UNIT_RADIANS: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); break;}
1304 				default: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();}
1305 			}
1306 			return 1;
1307 		}
1308 		if(!msave.isZero()) {
1309 			mstruct = msave;
1310 			return -1;
1311 		}
1312 		if(mstruct.isMultiplication()) {
1313 			bool b = false;
1314 			for(size_t i = 0; i < mstruct.size();) {
1315 				if(mstruct[i].representsPositive()) {
1316 					mstruct.delChild(i + 1);
1317 					b = true;
1318 				} else {
1319 					if(!mstruct[i].isMinusOne() && mstruct[i].representsNegative()) {
1320 						mstruct[i].set(-1, 1, 0, true);
1321 						b = true;
1322 					}
1323 					i++;
1324 				}
1325 			}
1326 			if(b) {
1327 				if(mstruct.size() == 1) {
1328 					mstruct.setToChild(1);
1329 				} else if(mstruct.size() == 0) {
1330 					mstruct.clear(true);
1331 				}
1332 				mstruct.transform(STRUCT_FUNCTION);
1333 				mstruct.setFunction(this);
1334 				return 1;
1335 			}
1336 		}
1337 		if(mstruct.isPower() && mstruct[0].representsComplex() && mstruct[1].representsInteger()) {
1338 			mstruct.setType(STRUCT_MULTIPLICATION);
1339 			mstruct[0].transform(STRUCT_FUNCTION);
1340 			mstruct[0].setFunction(this);
1341 			return 1;
1342 		}
1343 		if(mstruct.isPower() && mstruct[0].isVariable() && mstruct[0].variable()->id() == VARIABLE_ID_E && mstruct[1].isNumber() && mstruct[1].number().hasImaginaryPart() && !mstruct[1].number().hasRealPart()) {
1344 			CALCULATOR->beginTemporaryEnableIntervalArithmetic();
1345 			if(CALCULATOR->usesIntervalArithmetic()) {
1346 				CALCULATOR->beginTemporaryStopMessages();
1347 				Number nr(*mstruct[1].number().internalImaginary());
1348 				Number nrpi; nrpi.pi();
1349 				nr.add(nrpi);
1350 				nr.divide(nrpi);
1351 				nr.divide(2);
1352 				Number nr_u(nr.upperEndPoint());
1353 				nr = nr.lowerEndPoint();
1354 				nr_u.floor();
1355 				nr.floor();
1356 				if(!CALCULATOR->endTemporaryStopMessages() && nr == nr_u) {
1357 					CALCULATOR->endTemporaryEnableIntervalArithmetic();
1358 					nr.setApproximate(false);
1359 					nr *= 2;
1360 					nr.negate();
1361 					mstruct = mstruct[1].number().imaginaryPart();
1362 					if(!nr.isZero()) {
1363 						mstruct += nr;
1364 						mstruct.last() *= CALCULATOR->getVariableById(VARIABLE_ID_PI);
1365 					}
1366 					return true;
1367 				}
1368 			}
1369 			CALCULATOR->endTemporaryEnableIntervalArithmetic();
1370 		}
1371 		if(eo.approximation == APPROXIMATION_EXACT) {
1372 			msave = mstruct;
1373 			if(!test_eval(mstruct, eo)) {
1374 				mstruct = msave;
1375 				return -1;
1376 			}
1377 		}
1378 	}
1379 	if(mstruct.isNumber()) {
1380 		if(!mstruct.number().hasImaginaryPart()) {
1381 			if(!mstruct.number().isNonZero()) {
1382 				if(!msave.isZero()) mstruct = msave;
1383 				return -1;
1384 			}
1385 			if(mstruct.number().isNegative()) {
1386 				switch(eo.parse_options.angle_unit) {
1387 					case ANGLE_UNIT_DEGREES: {mstruct.set(180, 1, 0); break;}
1388 					case ANGLE_UNIT_GRADIANS: {mstruct.set(200, 1, 0); break;}
1389 					case ANGLE_UNIT_RADIANS: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); break;}
1390 					default: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();}
1391 				}
1392 			} else {
1393 				mstruct.clear();
1394 			}
1395 		} else if(!mstruct.number().hasRealPart() && mstruct.number().imaginaryPartIsNonZero()) {
1396 			bool b_neg = mstruct.number().imaginaryPartIsNegative();
1397 			switch(eo.parse_options.angle_unit) {
1398 				case ANGLE_UNIT_DEGREES: {mstruct.set(90, 1, 0); break;}
1399 				case ANGLE_UNIT_GRADIANS: {mstruct.set(100, 1, 0); break;}
1400 				case ANGLE_UNIT_RADIANS: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); mstruct.multiply(nr_half); break;}
1401 				default: {mstruct.set(CALCULATOR->getVariableById(VARIABLE_ID_PI)); mstruct.multiply(nr_half); if(CALCULATOR->getRadUnit()) mstruct *= CALCULATOR->getRadUnit();}
1402 			}
1403 			if(b_neg) mstruct.negate();
1404 		} else if(!msave.isZero()) {
1405 			mstruct = msave;
1406 			return -1;
1407 		} else if(!mstruct.number().realPartIsNonZero()) {
1408 			FR_FUNCTION(arg)
1409 		} else {
1410 			MathStructure new_nr(mstruct.number().imaginaryPart());
1411 			if(!new_nr.number().divide(mstruct.number().realPart())) return -1;
1412 			if(mstruct.number().realPartIsNegative()) {
1413 				if(mstruct.number().imaginaryPartIsNegative()) {
1414 					mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
1415 					switch(eo.parse_options.angle_unit) {
1416 						case ANGLE_UNIT_DEGREES: {mstruct.add(-180); break;}
1417 						case ANGLE_UNIT_GRADIANS: {mstruct.add(-200); break;}
1418 						case ANGLE_UNIT_RADIANS: {mstruct.subtract(CALCULATOR->getVariableById(VARIABLE_ID_PI)); break;}
1419 						default: {MathStructure msub(CALCULATOR->getVariableById(VARIABLE_ID_PI)); if(CALCULATOR->getRadUnit()) msub *= CALCULATOR->getRadUnit(); mstruct.subtract(msub);}
1420 					}
1421 				} else if(mstruct.number().imaginaryPartIsNonNegative()) {
1422 					mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
1423 					switch(eo.parse_options.angle_unit) {
1424 						case ANGLE_UNIT_DEGREES: {mstruct.add(180); break;}
1425 						case ANGLE_UNIT_GRADIANS: {mstruct.add(200); break;}
1426 						case ANGLE_UNIT_RADIANS: {mstruct.add(CALCULATOR->getVariableById(VARIABLE_ID_PI)); break;}
1427 						default: {MathStructure madd(CALCULATOR->getVariableById(VARIABLE_ID_PI)); if(CALCULATOR->getRadUnit()) madd *= CALCULATOR->getRadUnit(); mstruct.add(madd);}
1428 					}
1429 				} else {
1430 					FR_FUNCTION(arg)
1431 				}
1432 			} else {
1433 				mstruct.set(CALCULATOR->getFunctionById(FUNCTION_ID_ATAN), &new_nr, NULL);
1434 			}
1435 		}
1436 		return 1;
1437 	}
1438 	if(!msave.isZero()) {
1439 		goto arg_test_non_number;
1440 	}
1441 	return -1;
1442 }
1443 
IsNumberFunction()1444 IsNumberFunction::IsNumberFunction() : MathFunction("isNumber", 1) {
1445 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1446 int IsNumberFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1447 	mstruct = vargs[0];
1448 	if(!mstruct.isNumber()) mstruct.eval(eo);
1449 	if(mstruct.isNumber()) {
1450 		mstruct.number().setTrue();
1451 	} else {
1452 		mstruct.clear();
1453 		mstruct.number().setFalse();
1454 	}
1455 	return 1;
1456 }
1457 
1458 #define IS_NUMBER_FUNCTION(x, y) x::x() : MathFunction(#y, 1) {} int x::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {mstruct = vargs[0]; if(!mstruct.isNumber()) mstruct.eval(eo); if(mstruct.isNumber() && mstruct.number().y()) {mstruct.number().setTrue();} else {mstruct.clear(); mstruct.number().setFalse();} return 1;}
1459 
IS_NUMBER_FUNCTION(IsIntegerFunction,isInteger)1460 IS_NUMBER_FUNCTION(IsIntegerFunction, isInteger)
1461 IS_NUMBER_FUNCTION(IsRealFunction, isReal)
1462 IS_NUMBER_FUNCTION(IsRationalFunction, isRational)
1463 
1464 IEEE754FloatFunction::IEEE754FloatFunction() : MathFunction("float", 1, 3) {
1465 	Argument *arg = new TextArgument();
1466 	arg->setHandleVector(true);
1467 	setArgumentDefinition(1, arg);
1468 	IntegerArgument *iarg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG);
1469 	Number nmin(8, 1);
1470 	iarg->setMin(&nmin);
1471 	setArgumentDefinition(2, iarg);
1472 	setDefaultValue(2, "32");
1473 	setArgumentDefinition(3,  new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG));
1474 	setDefaultValue(3, "0");
1475 	setCondition("\\z<\\y-1");
1476 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)1477 int IEEE754FloatFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
1478 	string sbin = vargs[0].symbol();
1479 	unsigned int bits = vargs[1].number().uintValue();
1480 	unsigned int expbits = vargs[2].number().uintValue();
1481 	remove_blanks(sbin);
1482 	if(sbin.find_first_not_of("01") != string::npos) {
1483 		MathStructure m;
1484 		CALCULATOR->parse(&m, vargs[0].symbol(), eo.parse_options);
1485 		m.eval(eo);
1486 		if(!m.isInteger() || !m.number().isNonNegative()) return 0;
1487 		PrintOptions po;
1488 		po.base = BASE_BINARY;
1489 		po.twos_complement = false;
1490 		po.binary_bits = bits;
1491 		po.min_exp = 0;
1492 		po.base_display = BASE_DISPLAY_NONE;
1493 		sbin = m.print(po);
1494 		remove_blanks(sbin);
1495 	}
1496 	Number nr;
1497 	int ret = from_float(nr, sbin, bits, expbits);
1498 	if(ret == 0) return 0;
1499 	if(ret < 0) mstruct.setUndefined();
1500 	else mstruct = nr;
1501 	return 1;
1502 }
IEEE754FloatBitsFunction()1503 IEEE754FloatBitsFunction::IEEE754FloatBitsFunction() : MathFunction("floatBits", 1, 3) {
1504 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, true);
1505 	arg->setComplexAllowed(false);
1506 	arg->setHandleVector(true);
1507 	setArgumentDefinition(1, arg);
1508 	IntegerArgument *iarg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG);
1509 	Number nmin(8, 1);
1510 	iarg->setMin(&nmin);
1511 	setArgumentDefinition(2, iarg);
1512 	setDefaultValue(2, "32");
1513 	setArgumentDefinition(3,  new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG));
1514 	setDefaultValue(3, "0");
1515 	setCondition("\\z<\\y-1");
1516 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)1517 int IEEE754FloatBitsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
1518 	unsigned int bits = vargs[1].number().uintValue();
1519 	unsigned int expbits = vargs[2].number().uintValue();
1520 	string sbin = to_float(vargs[0].number(), bits, expbits);
1521 	if(sbin.empty()) return 0;
1522 	ParseOptions pa;
1523 	pa.base = BASE_BINARY;
1524 	Number nr(sbin, pa);
1525 	if(nr.isInfinite() && !vargs[0].number().isInfinite()) CALCULATOR->error(false, _("Floating point overflow"), NULL);
1526 	else if(nr.isZero() && !vargs[0].isZero()) CALCULATOR->error(false, _("Floating point underflow"), NULL);
1527 	mstruct = nr;
1528 	return 1;
1529 }
IEEE754FloatComponentsFunction()1530 IEEE754FloatComponentsFunction::IEEE754FloatComponentsFunction() : MathFunction("floatParts", 1, 3) {
1531 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, true);
1532 	arg->setComplexAllowed(false);
1533 	arg->setHandleVector(true);
1534 	setArgumentDefinition(1, arg);
1535 	IntegerArgument *iarg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG);
1536 	Number nmin(8, 1);
1537 	iarg->setMin(&nmin);
1538 	setArgumentDefinition(2, iarg);
1539 	setDefaultValue(2, "32");
1540 	setArgumentDefinition(3,  new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG));
1541 	setDefaultValue(3, "0");
1542 	setCondition("\\z<\\y-1");
1543 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)1544 int IEEE754FloatComponentsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
1545 	unsigned int bits = vargs[1].number().uintValue();
1546 	unsigned int expbits = vargs[2].number().uintValue();
1547 	if(expbits == 0) expbits = standard_expbits(bits);
1548 	string sbin = to_float(vargs[0].number(), bits, expbits);
1549 	if(sbin.empty()) return 0;
1550 	Number sign, exponent, significand;
1551 	if(sbin[0] == '0') sign = 1;
1552 	else sign = -1;
1553 	ParseOptions pa;
1554 	pa.base = BASE_BINARY;
1555 	exponent.set(sbin.substr(1, expbits), pa);
1556 	Number expbias(2);
1557 	expbias ^= (expbits - 1);
1558 	expbias--;
1559 	bool subnormal = exponent.isZero();
1560 	exponent -= expbias;
1561 	if(exponent > expbias) return 0;
1562 	if(subnormal) exponent++;
1563 	if(subnormal) significand.set(string("0.") + sbin.substr(1 + expbits), pa);
1564 	else significand.set(string("1.") + sbin.substr(1 + expbits), pa);
1565 	if(subnormal && significand.isZero()) exponent.clear();
1566 	mstruct.clearVector();
1567 	mstruct.addChild(sign);
1568 	mstruct.addChild(exponent);
1569 	mstruct.addChild(significand);
1570 	return 1;
1571 }
IEEE754FloatValueFunction()1572 IEEE754FloatValueFunction::IEEE754FloatValueFunction() : MathFunction("floatValue", 1, 3) {
1573 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, true);
1574 	arg->setComplexAllowed(false);
1575 	arg->setHandleVector(true);
1576 	setArgumentDefinition(1, arg);
1577 	IntegerArgument *iarg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG);
1578 	Number nmin(8, 1);
1579 	iarg->setMin(&nmin);
1580 	setArgumentDefinition(2, iarg);
1581 	setDefaultValue(2, "32");
1582 	setArgumentDefinition(3,  new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG));
1583 	setDefaultValue(3, "0");
1584 	setCondition("\\z<\\y-1");
1585 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)1586 int IEEE754FloatValueFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
1587 	unsigned int bits = vargs[1].number().uintValue();
1588 	unsigned int expbits = vargs[2].number().uintValue();
1589 	string sbin = to_float(vargs[0].number(), bits, expbits);
1590 	if(sbin.empty()) return 0;
1591 	Number nr;
1592 	int ret = from_float(nr, sbin, bits, expbits);
1593 	if(ret == 0) mstruct.setUndefined();
1594 	else mstruct = nr;
1595 	return 1;
1596 }
IEEE754FloatErrorFunction()1597 IEEE754FloatErrorFunction::IEEE754FloatErrorFunction() : MathFunction("floatError", 1, 3) {
1598 	NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, true, true);
1599 	arg->setComplexAllowed(false);
1600 	arg->setHandleVector(true);
1601 	setArgumentDefinition(1, arg);
1602 	IntegerArgument *iarg = new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG);
1603 	Number nmin(8, 1);
1604 	iarg->setMin(&nmin);
1605 	setArgumentDefinition(2, iarg);
1606 	setDefaultValue(2, "32");
1607 	setArgumentDefinition(3,  new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_ULONG));
1608 	setDefaultValue(3, "0");
1609 	setCondition("\\z<\\y-1");
1610 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)1611 int IEEE754FloatErrorFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
1612 	unsigned int bits = vargs[1].number().uintValue();
1613 	unsigned int expbits = vargs[2].number().uintValue();
1614 	string sbin = to_float(vargs[0].number(), bits, expbits);
1615 	if(sbin.empty()) return 0;
1616 	Number nr;
1617 	int ret = from_float(nr, sbin, bits, expbits);
1618 	if(ret == 0) return 0;
1619 	if(ret < 0 || (vargs[0].number().isInfinite() && nr.isInfinite())) {
1620 		mstruct.clear();
1621 	} else {
1622 		nr -= vargs[0].number();
1623 		nr.abs();
1624 		mstruct = nr;
1625 	}
1626 	return 1;
1627 }
1628 
1629