1 /*
2     Qalculate
3 
4     Copyright (C) 2003-2007, 2008, 2016-2019  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 "Calculator.h"
15 #include "BuiltinFunctions.h"
16 #include "util.h"
17 #include "MathStructure.h"
18 #include "Unit.h"
19 #include "Variable.h"
20 #include "Function.h"
21 #include "DataSet.h"
22 #include "ExpressionItem.h"
23 #include "Prefix.h"
24 #include "Number.h"
25 #include "QalculateDateTime.h"
26 
27 #include <locale.h>
28 #include <unistd.h>
29 #include <time.h>
30 #include <utime.h>
31 #include <sys/types.h>
32 
33 #include "MathStructure-support.h"
34 
35 using std::string;
36 using std::cout;
37 using std::vector;
38 using std::endl;
39 
40 #include "Calculator_p.h"
41 
autoConvert(const MathStructure & morig,MathStructure & mconv,const EvaluationOptions & eo)42 void autoConvert(const MathStructure &morig, MathStructure &mconv, const EvaluationOptions &eo) {
43 	if(!morig.containsType(STRUCT_UNIT, true)) {
44 		if(&mconv != &morig) mconv.set(morig);
45 		return;
46 	}
47 	switch(eo.auto_post_conversion) {
48 		case POST_CONVERSION_OPTIMAL: {
49 			mconv.set(CALCULATOR->convertToOptimalUnit(morig, eo, false));
50 			break;
51 		}
52 		case POST_CONVERSION_BASE: {
53 			mconv.set(CALCULATOR->convertToBaseUnits(morig, eo));
54 			break;
55 		}
56 		case POST_CONVERSION_OPTIMAL_SI: {
57 			mconv.set(CALCULATOR->convertToOptimalUnit(morig, eo, true));
58 			break;
59 		}
60 		default: {
61 			if(&mconv != &morig) mconv.set(morig);
62 		}
63 	}
64 	if(eo.mixed_units_conversion != MIXED_UNITS_CONVERSION_NONE) mconv.set(CALCULATOR->convertToMixedUnits(mconv, eo));
65 }
66 
run()67 void CalculateThread::run() {
68 	enableAsynchronousCancel();
69 	while(true) {
70 		bool b_parse = true;
71 		if(!read<bool>(&b_parse)) break;
72 		void *x = NULL;
73 		if(!read<void *>(&x) || !x) break;
74 		MathStructure *mstruct = (MathStructure*) x;
75 		CALCULATOR->startControl();
76 		if(b_parse) {
77 			mstruct->setAborted();
78 			if(CALCULATOR->tmp_parsedstruct) CALCULATOR->tmp_parsedstruct->setAborted();
79 			//if(CALCULATOR->tmp_tostruct) CALCULATOR->tmp_tostruct->setUndefined();
80 			mstruct->set(CALCULATOR->calculate(CALCULATOR->expression_to_calculate, CALCULATOR->tmp_evaluationoptions, CALCULATOR->tmp_parsedstruct, CALCULATOR->tmp_tostruct, CALCULATOR->tmp_maketodivision));
81 		} else {
82 			MathStructure meval(*mstruct);
83 			mstruct->setAborted();
84 			mstruct->set(CALCULATOR->calculate(meval, CALCULATOR->tmp_evaluationoptions, CALCULATOR->tmp_tostruct ? CALCULATOR->tmp_tostruct->symbol() : ""));
85 		}
86 		switch(CALCULATOR->tmp_proc_command) {
87 			case PROC_RPN_ADD: {
88 				CALCULATOR->RPNStackEnter(mstruct, false);
89 				break;
90 			}
91 			case PROC_RPN_SET: {
92 				CALCULATOR->setRPNRegister(CALCULATOR->tmp_rpnindex, mstruct, false);
93 				break;
94 			}
95 			case PROC_RPN_OPERATION_1: {
96 				if(CALCULATOR->RPNStackSize() > 0) {
97 					CALCULATOR->setRPNRegister(1, mstruct, false);
98 				} else {
99 					CALCULATOR->RPNStackEnter(mstruct, false);
100 				}
101 				break;
102 			}
103 			case PROC_RPN_OPERATION_2: {
104 				if(CALCULATOR->RPNStackSize() > 1) {
105 					CALCULATOR->deleteRPNRegister(1);
106 				}
107 				if(CALCULATOR->RPNStackSize() > 0) {
108 					CALCULATOR->setRPNRegister(1, mstruct, false);
109 				} else {
110 					CALCULATOR->RPNStackEnter(mstruct, false);
111 				}
112 				break;
113 			}
114 			case PROC_RPN_OPERATION_F: {
115 				for(size_t i = 0; (CALCULATOR->tmp_proc_registers < 0 || (int) i < CALCULATOR->tmp_proc_registers - 1) && CALCULATOR->RPNStackSize() > 1; i++) {
116 					CALCULATOR->deleteRPNRegister(1);
117 				}
118 				if(CALCULATOR->RPNStackSize() > 0 && CALCULATOR->tmp_proc_registers != 0) {
119 					CALCULATOR->setRPNRegister(1, mstruct, false);
120 				} else {
121 					CALCULATOR->RPNStackEnter(mstruct, false);
122 				}
123 				break;
124 			}
125 			case PROC_NO_COMMAND: {}
126 		}
127 		CALCULATOR->stopControl();
128 		CALCULATOR->b_busy = false;
129 	}
130 }
saveState()131 void Calculator::saveState() {
132 }
restoreState()133 void Calculator::restoreState() {
134 }
clearBuffers()135 void Calculator::clearBuffers() {
136 	for(unordered_map<size_t, bool>::iterator it = priv->ids_p.begin(); it != priv->ids_p.end(); ++it) {
137 		if(!it->second) {
138 			priv->freed_ids.push_back(it->first);
139 			priv->id_structs.erase(it->first);
140 			priv->ids_p.erase(it);
141 		}
142 	}
143 }
abort()144 bool Calculator::abort() {
145 	i_aborted = 1;
146 	if(!b_busy) return true;
147 	if(!calculate_thread->running) {
148 		b_busy = false;
149 	} else {
150 		// wait 5 seconds for clean abortation
151 		int msecs = 5000;
152 		while(b_busy && msecs > 0) {
153 			sleep_ms(10);
154 			msecs -= 10;
155 		}
156 		if(b_busy) {
157 
158 			// force thread cancellation
159 			calculate_thread->cancel();
160 			stopControl();
161 
162 			// clean up
163 			stopped_messages_count.clear();
164 			stopped_warnings_count.clear();
165 			stopped_errors_count.clear();
166 			stopped_messages.clear();
167 			disable_errors_ref = 0;
168 			if(tmp_rpn_mstruct) tmp_rpn_mstruct->unref();
169 			tmp_rpn_mstruct = NULL;
170 
171 			// thread cancellation is not safe
172 			error(true, _("The calculation has been forcibly terminated. Please restart the application and report this as a bug."), NULL);
173 
174 			b_busy = false;
175 			calculate_thread->start();
176 			return false;
177 		}
178 	}
179 	return true;
180 }
busy()181 bool Calculator::busy() {
182 	return b_busy;
183 }
terminateThreads()184 void Calculator::terminateThreads() {
185 	if(calculate_thread->running) {
186 		if(!calculate_thread->write(false) || !calculate_thread->write(NULL)) calculate_thread->cancel();
187 		for(size_t i = 0; i < 10 && calculate_thread->running; i++) {
188 			sleep_ms(1);
189 		}
190 		if(calculate_thread->running) calculate_thread->cancel();
191 	}
192 }
calculateRPNRegister(size_t index,int msecs,const EvaluationOptions & eo)193 bool Calculator::calculateRPNRegister(size_t index, int msecs, const EvaluationOptions &eo) {
194 	if(index <= 0 || index > rpn_stack.size()) return false;
195 	return calculateRPN(new MathStructure(*rpn_stack[rpn_stack.size() - index]), PROC_RPN_SET, index, msecs, eo);
196 }
197 
calculateRPN(MathStructure * mstruct,int command,size_t index,int msecs,const EvaluationOptions & eo,int function_arguments)198 bool Calculator::calculateRPN(MathStructure *mstruct, int command, size_t index, int msecs, const EvaluationOptions &eo, int function_arguments) {
199 	b_busy = true;
200 	if(!calculate_thread->running && !calculate_thread->start()) {mstruct->setAborted(); return false;}
201 	bool had_msecs = msecs > 0;
202 	tmp_evaluationoptions = eo;
203 	tmp_proc_command = command;
204 	tmp_rpnindex = index;
205 	tmp_rpn_mstruct = mstruct;
206 	tmp_proc_registers = function_arguments;
207 	tmp_tostruct = NULL;
208 	if(!calculate_thread->write(false)) {calculate_thread->cancel(); mstruct->setAborted(); return false;}
209 	if(!calculate_thread->write((void*) mstruct)) {calculate_thread->cancel(); mstruct->setAborted(); return false;}
210 	while(msecs > 0 && b_busy) {
211 		sleep_ms(10);
212 		msecs -= 10;
213 	}
214 	if(had_msecs && b_busy) {
215 		abort();
216 		return false;
217 	}
218 	return true;
219 }
calculateRPN(string str,int command,size_t index,int msecs,const EvaluationOptions & eo,MathStructure * parsed_struct,MathStructure * to_struct,bool make_to_division,int function_arguments)220 bool Calculator::calculateRPN(string str, int command, size_t index, int msecs, const EvaluationOptions &eo, MathStructure *parsed_struct, MathStructure *to_struct, bool make_to_division, int function_arguments) {
221 	MathStructure *mstruct = new MathStructure();
222 	b_busy = true;
223 	if(!calculate_thread->running && !calculate_thread->start()) {mstruct->setAborted(); return false;}
224 	bool had_msecs = msecs > 0;
225 	expression_to_calculate = str;
226 	tmp_evaluationoptions = eo;
227 	tmp_proc_command = command;
228 	tmp_rpnindex = index;
229 	tmp_rpn_mstruct = mstruct;
230 	tmp_parsedstruct = parsed_struct;
231 	tmp_tostruct = to_struct;
232 	tmp_maketodivision = make_to_division;
233 	tmp_proc_registers = function_arguments;
234 	if(!calculate_thread->write(true)) {calculate_thread->cancel(); mstruct->setAborted(); return false;}
235 	if(!calculate_thread->write((void*) mstruct)) {calculate_thread->cancel(); mstruct->setAborted(); return false;}
236 	while(msecs > 0 && b_busy) {
237 		sleep_ms(10);
238 		msecs -= 10;
239 	}
240 	if(had_msecs && b_busy) {
241 		abort();
242 		return false;
243 	}
244 	return true;
245 }
246 
calculateRPN(MathOperation op,int msecs,const EvaluationOptions & eo,MathStructure * parsed_struct)247 bool Calculator::calculateRPN(MathOperation op, int msecs, const EvaluationOptions &eo, MathStructure *parsed_struct) {
248 	MathStructure *mstruct;
249 	if(rpn_stack.size() == 0) {
250 		mstruct = new MathStructure();
251 		mstruct->add(m_zero, op);
252 		if(parsed_struct) parsed_struct->clear();
253 	} else if(rpn_stack.size() == 1) {
254 		if(parsed_struct) {
255 			parsed_struct->set(*rpn_stack.back());
256 			if(op == OPERATION_SUBTRACT) {
257 				parsed_struct->transform(STRUCT_NEGATE);
258 			} else if(op == OPERATION_DIVIDE) {
259 				parsed_struct->transform(STRUCT_INVERSE);
260 			} else {
261 				parsed_struct->add(*rpn_stack.back(), op);
262 			}
263 		}
264 		if(op == OPERATION_SUBTRACT) {
265 			mstruct = new MathStructure();
266 		} else if(op == OPERATION_DIVIDE) {
267 			mstruct = new MathStructure(1, 1, 0);
268 		} else {
269 			mstruct = new MathStructure(*rpn_stack.back());
270 		}
271 		mstruct->add(*rpn_stack.back(), op);
272 	} else {
273 		if(parsed_struct) {
274 			parsed_struct->set(*rpn_stack[rpn_stack.size() - 2]);
275 			if(op == OPERATION_SUBTRACT) {
276 				parsed_struct->transform(STRUCT_ADDITION, *rpn_stack.back());
277 				(*parsed_struct)[1].transform(STRUCT_NEGATE);
278 			} else if(op == OPERATION_DIVIDE) {
279 				parsed_struct->transform(STRUCT_DIVISION, *rpn_stack.back());
280 			} else {
281 				parsed_struct->add(*rpn_stack.back(), op);
282 			}
283 		}
284 		mstruct = new MathStructure(*rpn_stack[rpn_stack.size() - 2]);
285 		mstruct->add(*rpn_stack.back(), op);
286 	}
287 	return calculateRPN(mstruct, PROC_RPN_OPERATION_2, 0, msecs, eo);
288 }
calculateRPN(MathFunction * f,int msecs,const EvaluationOptions & eo,MathStructure * parsed_struct)289 bool Calculator::calculateRPN(MathFunction *f, int msecs, const EvaluationOptions &eo, MathStructure *parsed_struct) {
290 	MathStructure *mstruct = new MathStructure(f, NULL);
291 	int iregs = 0;
292 	if(f->args() != 0) {
293 		size_t i = f->minargs();
294 		bool fill_vector = (i > 0 && f->getArgumentDefinition(i) && f->getArgumentDefinition(i)->type() == ARGUMENT_TYPE_VECTOR);
295 		if(fill_vector && rpn_stack.size() < i) fill_vector = false;
296 		if(fill_vector && rpn_stack.size() > 0 && rpn_stack.back()->isVector()) fill_vector = false;
297 		if(fill_vector) {
298 			i = rpn_stack.size();
299 		} else if(i < 1) {
300 			i = 1;
301 		}
302 		for(; i > 0; i--) {
303 			if(i > rpn_stack.size()) {
304 				error(false, _("Stack is empty. Filling remaining function arguments with zeroes."), NULL);
305 				mstruct->addChild(m_zero);
306 			} else {
307 				if(fill_vector && rpn_stack.size() - i == (size_t) f->minargs() - 1) mstruct->addChild(m_empty_vector);
308 				if(fill_vector && rpn_stack.size() - i >= (size_t) f->minargs() - 1) mstruct->getChild(f->minargs())->addChild(*rpn_stack[rpn_stack.size() - i]);
309 				else mstruct->addChild(*rpn_stack[rpn_stack.size() - i]);
310 				iregs++;
311 			}
312 			if(!fill_vector && f->getArgumentDefinition(i) && f->getArgumentDefinition(i)->type() == ARGUMENT_TYPE_ANGLE) {
313 				switch(eo.parse_options.angle_unit) {
314 					case ANGLE_UNIT_DEGREES: {
315 						(*mstruct)[i - 1].multiply(getDegUnit());
316 						break;
317 					}
318 					case ANGLE_UNIT_GRADIANS: {
319 						(*mstruct)[i - 1].multiply(getGraUnit());
320 						break;
321 					}
322 					case ANGLE_UNIT_RADIANS: {
323 						(*mstruct)[i - 1].multiply(getRadUnit());
324 						break;
325 					}
326 					default: {}
327 				}
328 			}
329 		}
330 		if(fill_vector) mstruct->childrenUpdated();
331 		f->appendDefaultValues(*mstruct);
332 	}
333 	if(parsed_struct) parsed_struct->set(*mstruct);
334 	return calculateRPN(mstruct, PROC_RPN_OPERATION_F, 0, msecs, eo, iregs);
335 }
calculateRPNBitwiseNot(int msecs,const EvaluationOptions & eo,MathStructure * parsed_struct)336 bool Calculator::calculateRPNBitwiseNot(int msecs, const EvaluationOptions &eo, MathStructure *parsed_struct) {
337 	MathStructure *mstruct;
338 	if(rpn_stack.size() == 0) {
339 		mstruct = new MathStructure();
340 		mstruct->setBitwiseNot();
341 	} else {
342 		mstruct = new MathStructure(*rpn_stack.back());
343 		mstruct->setBitwiseNot();
344 	}
345 	if(parsed_struct) parsed_struct->set(*mstruct);
346 	return calculateRPN(mstruct, PROC_RPN_OPERATION_1, 0, msecs, eo);
347 }
calculateRPNLogicalNot(int msecs,const EvaluationOptions & eo,MathStructure * parsed_struct)348 bool Calculator::calculateRPNLogicalNot(int msecs, const EvaluationOptions &eo, MathStructure *parsed_struct) {
349 	MathStructure *mstruct;
350 	if(rpn_stack.size() == 0) {
351 		mstruct = new MathStructure();
352 		mstruct->setLogicalNot();
353 	} else {
354 		mstruct = new MathStructure(*rpn_stack.back());
355 		mstruct->setLogicalNot();
356 	}
357 	if(parsed_struct) parsed_struct->set(*rpn_stack.back());
358 	return calculateRPN(mstruct, PROC_RPN_OPERATION_1, 0, msecs, eo);
359 }
calculateRPN(MathOperation op,const EvaluationOptions & eo,MathStructure * parsed_struct)360 MathStructure *Calculator::calculateRPN(MathOperation op, const EvaluationOptions &eo, MathStructure *parsed_struct) {
361 	current_stage = MESSAGE_STAGE_PARSING;
362 	MathStructure *mstruct;
363 	if(rpn_stack.size() == 0) {
364 		mstruct = new MathStructure();
365 		mstruct->add(m_zero, op);
366 		if(parsed_struct) parsed_struct->clear();
367 	} else if(rpn_stack.size() == 1) {
368 		if(parsed_struct) {
369 			parsed_struct->clear();
370 			if(op == OPERATION_SUBTRACT) {
371 				parsed_struct->transform(STRUCT_ADDITION, *rpn_stack.back());
372 				(*parsed_struct)[1].transform(STRUCT_NEGATE);
373 			} else if(op == OPERATION_DIVIDE) {
374 				parsed_struct->transform(STRUCT_DIVISION, *rpn_stack.back());
375 			} else {
376 				parsed_struct->add(*rpn_stack.back(), op);
377 			}
378 		}
379 		mstruct = new MathStructure();
380 		mstruct->add(*rpn_stack.back(), op);
381 	} else {
382 		if(parsed_struct) {
383 			parsed_struct->set(*rpn_stack[rpn_stack.size() - 2]);
384 			if(op == OPERATION_SUBTRACT) {
385 				parsed_struct->transform(STRUCT_ADDITION, *rpn_stack.back());
386 				(*parsed_struct)[1].transform(STRUCT_NEGATE);
387 			} else if(op == OPERATION_DIVIDE) {
388 				parsed_struct->transform(STRUCT_DIVISION, *rpn_stack.back());
389 			} else {
390 				parsed_struct->add(*rpn_stack.back(), op);
391 			}
392 		}
393 		mstruct = new MathStructure(*rpn_stack[rpn_stack.size() - 2]);
394 		mstruct->add(*rpn_stack.back(), op);
395 	}
396 	current_stage = MESSAGE_STAGE_CALCULATION;
397 	mstruct->eval(eo);
398 	current_stage = MESSAGE_STAGE_CONVERSION;
399 	autoConvert(*mstruct, *mstruct, eo);
400 	current_stage = MESSAGE_STAGE_UNSET;
401 	if(rpn_stack.size() > 1) {
402 		rpn_stack.back()->unref();
403 		rpn_stack.erase(rpn_stack.begin() + (rpn_stack.size() - 1));
404 	}
405 	if(rpn_stack.size() > 0) {
406 		rpn_stack.back()->unref();
407 		rpn_stack.back() = mstruct;
408 	} else {
409 		rpn_stack.push_back(mstruct);
410 	}
411 	return rpn_stack.back();
412 }
calculateRPN(MathFunction * f,const EvaluationOptions & eo,MathStructure * parsed_struct)413 MathStructure *Calculator::calculateRPN(MathFunction *f, const EvaluationOptions &eo, MathStructure *parsed_struct) {
414 	current_stage = MESSAGE_STAGE_PARSING;
415 	MathStructure *mstruct = new MathStructure(f, NULL);
416 	size_t iregs = 0;
417 	if(f->args() != 0) {
418 		size_t i = f->minargs();
419 		bool fill_vector = (i > 0 && f->getArgumentDefinition(i) && f->getArgumentDefinition(i)->type() == ARGUMENT_TYPE_VECTOR);
420 		if(fill_vector && rpn_stack.size() < i) fill_vector = false;
421 		if(fill_vector && rpn_stack.size() > 0 && rpn_stack.back()->isVector()) fill_vector = false;
422 		if(fill_vector) {
423 			i = rpn_stack.size();
424 		} else if(i < 1) {
425 			i = 1;
426 		}
427 		for(; i > 0; i--) {
428 			if(i > rpn_stack.size()) {
429 				error(false, _("Stack is empty. Filling remaining function arguments with zeroes."), NULL);
430 				mstruct->addChild(m_zero);
431 			} else {
432 				if(fill_vector && rpn_stack.size() - i == (size_t) f->minargs() - 1) mstruct->addChild(m_empty_vector);
433 				if(fill_vector && rpn_stack.size() - i >= (size_t) f->minargs() - 1) mstruct->getChild(f->minargs())->addChild(*rpn_stack[rpn_stack.size() - i]);
434 				else mstruct->addChild(*rpn_stack[rpn_stack.size() - i]);
435 				iregs++;
436 			}
437 			if(!fill_vector && f->getArgumentDefinition(i) && f->getArgumentDefinition(i)->type() == ARGUMENT_TYPE_ANGLE) {
438 				switch(eo.parse_options.angle_unit) {
439 					case ANGLE_UNIT_DEGREES: {
440 						(*mstruct)[i - 1].multiply(getDegUnit());
441 						break;
442 					}
443 					case ANGLE_UNIT_GRADIANS: {
444 						(*mstruct)[i - 1].multiply(getGraUnit());
445 						break;
446 					}
447 					case ANGLE_UNIT_RADIANS: {
448 						(*mstruct)[i - 1].multiply(getRadUnit());
449 						break;
450 					}
451 					default: {}
452 				}
453 			}
454 		}
455 		if(fill_vector) mstruct->childrenUpdated();
456 		f->appendDefaultValues(*mstruct);
457 	}
458 	if(parsed_struct) parsed_struct->set(*mstruct);
459 	current_stage = MESSAGE_STAGE_CALCULATION;
460 	mstruct->eval(eo);
461 	current_stage = MESSAGE_STAGE_CONVERSION;
462 	autoConvert(*mstruct, *mstruct, eo);
463 	current_stage = MESSAGE_STAGE_UNSET;
464 	if(iregs == 0) {
465 		rpn_stack.push_back(mstruct);
466 	} else {
467 		for(size_t i = 0; i < iregs - 1 && rpn_stack.size() > 1; i++) {
468 			rpn_stack.back()->unref();
469 			rpn_stack.pop_back();
470 			deleteRPNRegister(1);
471 		}
472 		rpn_stack.back()->unref();
473 		rpn_stack.back() = mstruct;
474 	}
475 	return rpn_stack.back();
476 }
calculateRPNBitwiseNot(const EvaluationOptions & eo,MathStructure * parsed_struct)477 MathStructure *Calculator::calculateRPNBitwiseNot(const EvaluationOptions &eo, MathStructure *parsed_struct) {
478 	current_stage = MESSAGE_STAGE_PARSING;
479 	MathStructure *mstruct;
480 	if(rpn_stack.size() == 0) {
481 		mstruct = new MathStructure();
482 		mstruct->setBitwiseNot();
483 	} else {
484 		mstruct = new MathStructure(*rpn_stack.back());
485 		mstruct->setBitwiseNot();
486 	}
487 	if(parsed_struct) parsed_struct->set(*mstruct);
488 	current_stage = MESSAGE_STAGE_CALCULATION;
489 	mstruct->eval(eo);
490 	current_stage = MESSAGE_STAGE_CONVERSION;
491 	autoConvert(*mstruct, *mstruct, eo);
492 	current_stage = MESSAGE_STAGE_UNSET;
493 	if(rpn_stack.size() == 0) {
494 		rpn_stack.push_back(mstruct);
495 	} else {
496 		rpn_stack.back()->unref();
497 		rpn_stack.back() = mstruct;
498 	}
499 	return rpn_stack.back();
500 }
calculateRPNLogicalNot(const EvaluationOptions & eo,MathStructure * parsed_struct)501 MathStructure *Calculator::calculateRPNLogicalNot(const EvaluationOptions &eo, MathStructure *parsed_struct) {
502 	current_stage = MESSAGE_STAGE_PARSING;
503 	MathStructure *mstruct;
504 	if(rpn_stack.size() == 0) {
505 		mstruct = new MathStructure();
506 		mstruct->setLogicalNot();
507 	} else {
508 		mstruct = new MathStructure(*rpn_stack.back());
509 		mstruct->setLogicalNot();
510 	}
511 	if(parsed_struct) parsed_struct->set(*mstruct);
512 	current_stage = MESSAGE_STAGE_CALCULATION;
513 	mstruct->eval(eo);
514 	current_stage = MESSAGE_STAGE_CONVERSION;
515 	autoConvert(*mstruct, *mstruct, eo);
516 	current_stage = MESSAGE_STAGE_UNSET;
517 	if(rpn_stack.size() == 0) {
518 		rpn_stack.push_back(mstruct);
519 	} else {
520 		rpn_stack.back()->unref();
521 		rpn_stack.back() = mstruct;
522 	}
523 	return rpn_stack.back();
524 }
RPNStackEnter(MathStructure * mstruct,int msecs,const EvaluationOptions & eo)525 bool Calculator::RPNStackEnter(MathStructure *mstruct, int msecs, const EvaluationOptions &eo) {
526 	return calculateRPN(mstruct, PROC_RPN_ADD, 0, msecs, eo);
527 }
RPNStackEnter(string str,int msecs,const EvaluationOptions & eo,MathStructure * parsed_struct,MathStructure * to_struct,bool make_to_division)528 bool Calculator::RPNStackEnter(string str, int msecs, const EvaluationOptions &eo, MathStructure *parsed_struct, MathStructure *to_struct, bool make_to_division) {
529 	remove_blank_ends(str);
530 	if(str.empty() && rpn_stack.size() > 0) {
531 		rpn_stack.push_back(new MathStructure(*rpn_stack.back()));
532 		return true;
533 	}
534 	return calculateRPN(str, PROC_RPN_ADD, 0, msecs, eo, parsed_struct, to_struct, make_to_division);
535 }
RPNStackEnter(MathStructure * mstruct,bool eval,const EvaluationOptions & eo)536 void Calculator::RPNStackEnter(MathStructure *mstruct, bool eval, const EvaluationOptions &eo) {
537 	if(eval) {
538 		current_stage = MESSAGE_STAGE_CALCULATION;
539 		mstruct->eval(eo);
540 		current_stage = MESSAGE_STAGE_CONVERSION;
541 		autoConvert(*mstruct, *mstruct, eo);
542 		current_stage = MESSAGE_STAGE_UNSET;
543 	}
544 	rpn_stack.push_back(mstruct);
545 }
RPNStackEnter(string str,const EvaluationOptions & eo,MathStructure * parsed_struct,MathStructure * to_struct,bool make_to_division)546 void Calculator::RPNStackEnter(string str, const EvaluationOptions &eo, MathStructure *parsed_struct, MathStructure *to_struct, bool make_to_division) {
547 	remove_blank_ends(str);
548 	if(str.empty() && rpn_stack.size() > 0) rpn_stack.push_back(new MathStructure(*rpn_stack.back()));
549 	else rpn_stack.push_back(new MathStructure(calculate(str, eo, parsed_struct, to_struct, make_to_division)));
550 }
setRPNRegister(size_t index,MathStructure * mstruct,int msecs,const EvaluationOptions & eo)551 bool Calculator::setRPNRegister(size_t index, MathStructure *mstruct, int msecs, const EvaluationOptions &eo) {
552 	if(mstruct == NULL) {
553 		deleteRPNRegister(index);
554 		return true;
555 	}
556 	if(index <= 0 || index > rpn_stack.size()) return false;
557 	return calculateRPN(mstruct, PROC_RPN_SET, index, msecs, eo);
558 }
setRPNRegister(size_t index,string str,int msecs,const EvaluationOptions & eo,MathStructure * parsed_struct,MathStructure * to_struct,bool make_to_division)559 bool Calculator::setRPNRegister(size_t index, string str, int msecs, const EvaluationOptions &eo, MathStructure *parsed_struct, MathStructure *to_struct, bool make_to_division) {
560 	if(index <= 0 || index > rpn_stack.size()) return false;
561 	return calculateRPN(str, PROC_RPN_SET, index, msecs, eo, parsed_struct, to_struct, make_to_division);
562 }
setRPNRegister(size_t index,MathStructure * mstruct,bool eval,const EvaluationOptions & eo)563 void Calculator::setRPNRegister(size_t index, MathStructure *mstruct, bool eval, const EvaluationOptions &eo) {
564 	if(mstruct == NULL) {
565 		deleteRPNRegister(index);
566 		return;
567 	}
568 	if(eval) {
569 		current_stage = MESSAGE_STAGE_CALCULATION;
570 		mstruct->eval(eo);
571 		current_stage = MESSAGE_STAGE_CONVERSION;
572 		autoConvert(*mstruct, *mstruct, eo);
573 		current_stage = MESSAGE_STAGE_UNSET;
574 	}
575 	if(index <= 0 || index > rpn_stack.size()) return;
576 	index = rpn_stack.size() - index;
577 	rpn_stack[index]->unref();
578 	rpn_stack[index] = mstruct;
579 }
setRPNRegister(size_t index,string str,const EvaluationOptions & eo,MathStructure * parsed_struct,MathStructure * to_struct,bool make_to_division)580 void Calculator::setRPNRegister(size_t index, string str, const EvaluationOptions &eo, MathStructure *parsed_struct, MathStructure *to_struct, bool make_to_division) {
581 	if(index <= 0 || index > rpn_stack.size()) return;
582 	index = rpn_stack.size() - index;
583 	MathStructure *mstruct = new MathStructure(calculate(str, eo, parsed_struct, to_struct, make_to_division));
584 	rpn_stack[index]->unref();
585 	rpn_stack[index] = mstruct;
586 }
deleteRPNRegister(size_t index)587 void Calculator::deleteRPNRegister(size_t index) {
588 	if(index <= 0 || index > rpn_stack.size()) return;
589 	index = rpn_stack.size() - index;
590 	rpn_stack[index]->unref();
591 	rpn_stack.erase(rpn_stack.begin() + index);
592 }
getRPNRegister(size_t index) const593 MathStructure *Calculator::getRPNRegister(size_t index) const {
594 	if(index > 0 && index <= rpn_stack.size()) {
595 		index = rpn_stack.size() - index;
596 		return rpn_stack[index];
597 	}
598 	return NULL;
599 }
RPNStackSize() const600 size_t Calculator::RPNStackSize() const {
601 	return rpn_stack.size();
602 }
clearRPNStack()603 void Calculator::clearRPNStack() {
604 	for(size_t i = 0; i < rpn_stack.size(); i++) {
605 		rpn_stack[i]->unref();
606 	}
607 	rpn_stack.clear();
608 }
moveRPNRegister(size_t old_index,size_t new_index)609 void Calculator::moveRPNRegister(size_t old_index, size_t new_index) {
610 	if(old_index == new_index) return;
611 	if(old_index > 0 && old_index <= rpn_stack.size()) {
612 		old_index = rpn_stack.size() - old_index;
613 		MathStructure *mstruct = rpn_stack[old_index];
614 		if(new_index > rpn_stack.size()) {
615 			new_index = 0;
616 		} else if(new_index <= 1) {
617 			rpn_stack.push_back(mstruct);
618 			rpn_stack.erase(rpn_stack.begin() + old_index);
619 			return;
620 		} else {
621 			new_index = rpn_stack.size() - new_index;
622 		}
623 		if(new_index > old_index) {
624 			rpn_stack.erase(rpn_stack.begin() + old_index);
625 			rpn_stack.insert(rpn_stack.begin() + new_index, mstruct);
626 		} else if(new_index < old_index) {
627 			rpn_stack.insert(rpn_stack.begin() + new_index, mstruct);
628 			rpn_stack.erase(rpn_stack.begin() + (old_index + 1));
629 		}
630 	}
631 }
moveRPNRegisterUp(size_t index)632 void Calculator::moveRPNRegisterUp(size_t index) {
633 	if(index > 1 && index <= rpn_stack.size()) {
634 		index = rpn_stack.size() - index;
635 		MathStructure *mstruct = rpn_stack[index];
636 		rpn_stack.erase(rpn_stack.begin() + index);
637 		index++;
638 		if(index == rpn_stack.size()) rpn_stack.push_back(mstruct);
639 		else rpn_stack.insert(rpn_stack.begin() + index, mstruct);
640 	}
641 }
moveRPNRegisterDown(size_t index)642 void Calculator::moveRPNRegisterDown(size_t index) {
643 	if(index > 0 && index < rpn_stack.size()) {
644 		index = rpn_stack.size() - index;
645 		MathStructure *mstruct = rpn_stack[index];
646 		rpn_stack.erase(rpn_stack.begin() + index);
647 		index--;
648 		rpn_stack.insert(rpn_stack.begin() + index, mstruct);
649 	}
650 }
651 
has_information_unit(const MathStructure & m,bool top)652 int has_information_unit(const MathStructure &m, bool top) {
653 	if(m.isUnit_exp()) {
654 		if(m.isUnit()) {
655 			if(m.unit()->baseUnit()->referenceName() == "bit") return 1;
656 		} else {
657 			if(m[0].unit()->baseUnit()->referenceName() == "bit") {
658 				if(m[1].isInteger() && m[1].number().isPositive()) return 1;
659 				return 2;
660 			}
661 		}
662 		return 0;
663 	}
664 	for(size_t i = 0; i < m.size(); i++) {
665 		int ret = has_information_unit(m[i], false);
666 		if(ret > 0) {
667 			if(ret == 1 && top && m.isMultiplication() && m[0].isNumber() && m[0].number().isFraction()) return 2;
668 			return ret;
669 		}
670 	}
671 	return 0;
672 }
673 
fix_to_struct(MathStructure & m)674 void fix_to_struct(MathStructure &m) {
675 	if(m.isPower() && m[0].isUnit()) {
676 		if(m[0].prefix() == NULL && m[0].unit()->referenceName() == "g") {
677 			m[0].setPrefix(CALCULATOR->getOptimalDecimalPrefix(3));
678 		} else if(m[0].unit() == CALCULATOR->getUnitById(UNIT_ID_EURO)) {
679 			Unit *u = CALCULATOR->getLocalCurrency();
680 			if(u) m[0].setUnit(u);
681 		}
682 	} else if(m.isUnit()) {
683 		if(m.prefix() == NULL && m.unit()->referenceName() == "g") {
684 			m.setPrefix(CALCULATOR->getOptimalDecimalPrefix(3));
685 		} else if(m.unit() == CALCULATOR->getUnitById(UNIT_ID_EURO)) {
686 			Unit *u = CALCULATOR->getLocalCurrency();
687 			if(u) m.setUnit(u);
688 		}
689 	} else {
690 		for(size_t i = 0; i < m.size();) {
691 			if(m[i].isUnit()) {
692 				if(m[i].prefix() == NULL && m[i].unit()->referenceName() == "g") {
693 					m[i].setPrefix(CALCULATOR->getOptimalDecimalPrefix(3));
694 				} else if(m[i].unit() == CALCULATOR->getUnitById(UNIT_ID_EURO)) {
695 					Unit *u = CALCULATOR->getLocalCurrency();
696 					if(u) m[i].setUnit(u);
697 				}
698 				i++;
699 			} else if(m[i].isPower() && m[i][0].isUnit()) {
700 				if(m[i][0].prefix() == NULL && m[i][0].unit()->referenceName() == "g") {
701 					m[i][0].setPrefix(CALCULATOR->getOptimalDecimalPrefix(3));
702 				} else if(m[i][0].unit() == CALCULATOR->getUnitById(UNIT_ID_EURO)) {
703 					Unit *u = CALCULATOR->getLocalCurrency();
704 					if(u) m[i][0].setUnit(u);
705 				}
706 				i++;
707 			} else {
708 				m.delChild(i + 1);
709 			}
710 		}
711 		if(m.size() == 0) m.clear();
712 		if(m.size() == 1) m.setToChild(1);
713 	}
714 }
715 
716 
replace_result_cis(string & resstr)717 void replace_result_cis(string &resstr) {
718 	gsub(" cis ", "∠", resstr);
719 }
720 
721 // test if contains decimal value (if test_orig = true, check for decimal point in original expression)
contains_decimal(const MathStructure & m,const string * original_expression=NULL)722 bool contains_decimal(const MathStructure &m, const string *original_expression = NULL) {
723 	if(original_expression && !original_expression->empty()) return original_expression->find(DOT) != string::npos;
724 	if(m.isNumber()) return !m.number().isInteger();
725 	for(size_t i = 0; i < m.size(); i++) {
726 		if(contains_decimal(m[i])) return true;
727 	}
728 	return false;
729 }
730 
731 // test size of simple or combined (if top value) fraction
test_frac(const MathStructure & m,bool test_combined=true,int limit=1000)732 int test_frac(const MathStructure &m, bool test_combined = true, int limit = 1000) {
733 	if(m.isNumber()) {
734 		if(!m.number().isRational()) return 0;
735 		if(limit < 0 || m.number().isInteger()) return 1;
736 		if(m.number().denominatorIsLessThan(limit)) {
737 			if(m.number().numeratorIsLessThan(limit) && m.number().numeratorIsGreaterThan(-limit)) return 1;
738 			else if(test_combined) return 2;
739 		}
740 		return 0;
741 	}
742 	if(test_combined && m.isNegate()) return test_frac(m[0], true, limit);
743 	for(size_t i = 0; i < m.size(); i++) {
744 		if(!test_frac(m[i], false, limit)) return 0;
745 	}
746 	return 1;
747 }
748 
print_m(PrintOptions & po,const EvaluationOptions & evalops,string & str,vector<string> & results_v,MathStructure & m,const MathStructure * mresult,const string & original_expression,const MathStructure * mparse,int dfrac,int dappr,bool cplx_angle,bool only_cmp=false,bool format=false,int colorize=0,int tagtype=TAG_TYPE_HTML,int max_length=-1)749 void print_m(PrintOptions &po, const EvaluationOptions &evalops, string &str, vector<string> &results_v, MathStructure &m, const MathStructure *mresult, const string &original_expression, const MathStructure *mparse, int dfrac, int dappr, bool cplx_angle, bool only_cmp = false, bool format = false, int colorize = 0, int tagtype = TAG_TYPE_HTML, int max_length = -1) {
750 	bool b_exact = !mresult->isApproximate();
751 	// avoid multiple results with inequalities
752 	if((dfrac != 0 || dappr < 0) && (only_cmp || dfrac <= 0) && b_exact && m.isComparison() && (m.comparisonType() != COMPARISON_EQUALS || (!m[0].isSymbolic() && !m[0].isVariable())) && po.number_fraction_format == FRACTION_DECIMAL) {
753 		po.number_fraction_format = (dfrac != 0 && (!m[0].isSymbolic() || !m[0].isVariable())) ? FRACTION_FRACTIONAL : FRACTION_DECIMAL_EXACT;
754 		m.format(po);
755 		str = m.print(po, format, colorize, tagtype);
756 		po.number_fraction_format = FRACTION_DECIMAL;
757 	} else {
758 		str = m.print(po, format, colorize, tagtype);
759 	}
760 	if(cplx_angle) replace_result_cis(str);
761 	// do not use thin space (meaningless with monospace font) in terminal
762 	if(po.use_unicode_signs) gsub(" ", " ", str);
763 	// use almost equal sign in approximate equality
764 	if(m.isComparison() && m.comparisonType() == COMPARISON_EQUALS && po.is_approximate && *po.is_approximate && po.use_unicode_signs) {
765 		size_t ipos = str.find(" = ");
766 		if(ipos != string::npos) {
767 			str.replace(ipos + 1, 1, SIGN_ALMOST_EQUAL);
768 			if(po.is_approximate) *po.is_approximate = false;
769 		}
770 	}
771 	bool b_cmp3 = false;
772 	// with dual approximation, equalities contain three values
773 	if(m.isComparison() && m.size() == 3 && m.comparisonType() == COMPARISON_EQUALS) {
774 		if(m[2].isUndefined()) {
775 			// the only unique value is exact
776 			b_exact = true;
777 			m.delChild(3);
778 		} else {
779 			b_cmp3 = true;
780 		}
781 	}
782 	// do not show simple fractions in auto modes if result includes units or expression contains decimals
783 	if(!CALCULATOR->aborted() && (b_cmp3 || ((dfrac || (dappr && po.is_approximate && *po.is_approximate)) && (!only_cmp || (m.isComparison() && m.comparisonType() == COMPARISON_EQUALS && (m[0].isSymbolic() || m[0].isVariable()))) && po.base == 10 && b_exact && (po.number_fraction_format == FRACTION_DECIMAL_EXACT || po.number_fraction_format == FRACTION_DECIMAL) && (dfrac > 0 || dappr > 0 || mresult->containsType(STRUCT_UNIT, false, true, true) <= 0)))) {
784 		bool do_frac = false, do_mixed = false;
785 		const MathStructure *mcmp = mresult;
786 		if(b_cmp3) {
787 			do_frac = true;
788 			mcmp = &m[2];
789 		} else if(!mparse || ((dfrac > 0 || dappr > 0 || !contains_decimal(*mparse, &original_expression)) && !mparse->isNumber())) {
790 			if(contains_decimal(m)) {
791 				if(m.isComparison() && m.comparisonType() == COMPARISON_EQUALS && (m[0].isSymbolic() || m[0].isVariable())) {
792 					mcmp = mresult->getChild(2);
793 				}
794 				int itf = test_frac(*mcmp, !only_cmp, dfrac > 0 || dappr > 0 ? -1 : 1000);
795 				if(itf) {
796 					do_frac = (itf == 1);
797 					if(mcmp == mresult && mparse) {
798 						if(mcmp->isNumber() && mcmp->number().isRational()) {
799 							do_frac = itf == 1 && ((evalops.parse_options.base != po.base) || ((!mparse->isDivision() || (*mparse)[1] != mcmp->number().denominator() || ((*mparse)[0] != mcmp->number().numerator() && (!(*mparse)[0].isNegate() || (*mparse)[0][0] != -mcmp->number().numerator()))) && (!mparse->isNegate() || !(*mparse)[0].isDivision() || (*mparse)[0][1] != mcmp->number().denominator() || (*mparse)[0][0] != -mcmp->number().numerator())));
800 							do_mixed = (dfrac != 0 || !do_frac) && !mcmp->number().isNegative() && !mcmp->number().isFraction();
801 						} else if(do_frac && mresult->isFunction() && mparse->isFunction() && mresult->function() == mparse->function()) {
802 							do_frac = false;
803 						}
804 					}
805 				}
806 			}
807 		}
808 		bool *old_approx = po.is_approximate;
809 		NumberFractionFormat old_fr = po.number_fraction_format;
810 		bool old_rfl = po.restrict_fraction_length;
811 		bool b_approx = false;
812 		po.is_approximate = &b_approx;
813 		if(do_frac) {
814 			po.number_fraction_format = FRACTION_FRACTIONAL;
815 			po.restrict_fraction_length = true;
816 			MathStructure m2(*mcmp);
817 			m.removeDefaultAngleUnit(evalops);
818 			m2.format(po);
819 			results_v.push_back(m2.print(po, format, colorize, tagtype));
820 			if(b_approx) {
821 				results_v.pop_back();
822 			} else {
823 				if(po.use_unicode_signs) gsub(" ", " ", results_v.back());
824 			}
825 		}
826 		if(do_mixed) {
827 			b_approx = false;
828 			po.number_fraction_format = FRACTION_COMBINED;
829 			po.restrict_fraction_length = true;
830 			MathStructure m2(*mcmp);
831 			m.removeDefaultAngleUnit(evalops);
832 			m2.format(po);
833 			if(m2 != *mparse) {
834 				results_v.push_back(m2.print(po, format, colorize, tagtype));
835 				if(b_approx) {
836 					results_v.pop_back();
837 				} else {
838 					if(po.use_unicode_signs) gsub(" ", " ", results_v.back());
839 				}
840 			}
841 		}
842 		// results are added to equalities instead of shown as multiple results
843 		if(m.isComparison() && m.comparisonType() == COMPARISON_EQUALS && (m[0].isSymbolic() || m[0].isVariable()) && !results_v.empty()) {
844 			size_t ipos = str.find(" = ");
845 			if(ipos == string::npos) ipos = str.find(" " SIGN_ALMOST_EQUAL " ");
846 			if(ipos != string::npos) {
847 				for(size_t i = results_v.size(); i > 0; i--) {
848 					if(max_length < 0 || (unicode_length(str) + unicode_length(results_v[i - 1]) + 3 <= (size_t) max_length)) {
849 						str.insert(ipos, results_v[i - 1]);
850 						str.insert(ipos, " = ");
851 					}
852 				}
853 			}
854 			results_v.clear();
855 		}
856 		po.number_fraction_format = old_fr;
857 		po.is_approximate = old_approx;
858 		po.restrict_fraction_length = old_rfl;
859 	}
860 }
861 
862 // check for for unknown variables/symbols not on the left side of (in)equalities
test_fr_unknowns(const MathStructure & m)863 bool test_fr_unknowns(const MathStructure &m) {
864 	if(m.isComparison()) {
865 		return m[1].containsUnknowns();
866 	} else if(m.isLogicalOr() || m.isLogicalAnd()) {
867 		for(size_t i = 0; i < m.size(); i++) {
868 			if(test_fr_unknowns(m[i])) return true;
869 		}
870 		return false;
871 	}
872 	return m.containsUnknowns();
873 }
test_power_func(const MathStructure & m)874 bool test_power_func(const MathStructure &m) {
875 	if(m.isFunction() || (m.isPower() && !m[0].containsType(STRUCT_UNIT, false, false, false) && !m[1].isInteger())) return true;
876 	for(size_t i = 0; i < m.size(); i++) {
877 		if(test_power_func(m[i])) return true;
878 	}
879 	return false;
880 }
test_parsed_comparison(const MathStructure & m)881 bool test_parsed_comparison(const MathStructure &m) {
882 	if(m.isComparison()) return true;
883 	if((m.isLogicalOr() || m.isLogicalAnd()) && m.size() > 0) {
884 		for(size_t i = 0; i < m.size(); i++) {
885 			if(!test_parsed_comparison(m[i])) return false;
886 		}
887 		return true;
888 	}
889 	return false;
890 }
print_dual(const MathStructure & mresult,const string & original_expression,const MathStructure & mparse,MathStructure & mexact,string & result_str,vector<string> & results_v,PrintOptions & po,const EvaluationOptions & evalops,AutomaticFractionFormat auto_frac,AutomaticApproximation auto_approx,bool cplx_angle,bool * exact_cmp,bool b_parsed,bool format,int colorize,int tagtype,int max_length)891 void print_dual(const MathStructure &mresult, const string &original_expression, const MathStructure &mparse, MathStructure &mexact, string &result_str, vector<string> &results_v, PrintOptions &po, const EvaluationOptions &evalops, AutomaticFractionFormat auto_frac, AutomaticApproximation auto_approx, bool cplx_angle, bool *exact_cmp, bool b_parsed, bool format, int colorize, int tagtype, int max_length) {
892 
893 	MathStructure m(mresult);
894 
895 	if(po.spell_out_logical_operators && test_parsed_comparison(mparse)) {
896 		if(m.isZero()) {
897 			Variable *v = CALCULATOR->getActiveVariable("false");
898 			if(v) m.set(v);
899 		} else if(m.isOne()) {
900 			Variable *v = CALCULATOR->getActiveVariable("true");
901 			if(v) m.set(v);
902 		}
903 	}
904 
905 	// convert time units to hours when using time format
906 	if(po.base == BASE_TIME) {
907 		bool b = false;
908 		if(m.isUnit() && m.unit()->baseUnit()->referenceName() == "s") {
909 			b = true;
910 		} else if(m.isMultiplication() && m.size() == 2 && m[0].isNumber() && m[1].isUnit() && m[1].unit()->baseUnit()->referenceName() == "s") {
911 			b = true;
912 		} else if(m.isAddition() && m.size() > 0) {
913 			b = true;
914 			for(size_t i = 0; i < m.size(); i++) {
915 				if(m[i].isUnit() && m[i].unit()->baseUnit()->referenceName() == "s") {}
916 				else if(m[i].isMultiplication() && m[i].size() == 2 && m[i][0].isNumber() && m[i][1].isUnit() && m[i][1].unit()->baseUnit()->referenceName() == "s") {}
917 				else {b = false; break;}
918 			}
919 		}
920 		if(b) {
921 			Unit *u = CALCULATOR->getActiveUnit("h");
922 			if(u) {
923 				m.divide(u);
924 				m.eval(evalops);
925 			}
926 		}
927 	}
928 
929 	// dual and auto approximation and fractions
930 	results_v.clear();
931 	if(exact_cmp) *exact_cmp = false;
932 	bool *save_is_approximate = po.is_approximate;
933 	bool tmp_approx = false;
934 	if(!po.is_approximate) po.is_approximate = &tmp_approx;
935 
936 	// dual/auto approximation: requires that the value is approximate and exact result is set
937 	bool do_exact = !mexact.isUndefined() && m.isApproximate();
938 
939 	// If parsed value is number (simple fractions are parsed as division) only show result as combined fraction
940 	if(auto_frac != AUTOMATIC_FRACTION_OFF && po.base == 10 && po.base == evalops.parse_options.base && !m.isApproximate() && b_parsed && mparse.isNumber()) {
941 		po.number_fraction_format = FRACTION_COMBINED;
942 	// with auto fractions show expressions with unknown variables/symbols only using simple fractions (if not parsed value contains decimals)
943 	} else if((auto_frac == AUTOMATIC_FRACTION_AUTO || auto_frac == AUTOMATIC_FRACTION_SINGLE) && !m.isApproximate() && (test_fr_unknowns(m) || (m.containsType(STRUCT_ADDITION) && test_power_func(m))) && test_frac(m, false, -1) && (!b_parsed || !contains_decimal(mparse, &original_expression))) {
944 		po.number_fraction_format = FRACTION_FRACTIONAL;
945 		po.restrict_fraction_length = true;
946 	// with auto fractions and exact approximation (or inequality) do not show approximate decimal fractions
947 	} else if(auto_frac != AUTOMATIC_FRACTION_OFF && po.number_fraction_format == FRACTION_DECIMAL && (evalops.approximation == APPROXIMATION_EXACT || (auto_frac != AUTOMATIC_FRACTION_DUAL && m.isComparison() && m.comparisonType() != COMPARISON_EQUALS))) {
948 		po.number_fraction_format = FRACTION_DECIMAL_EXACT;
949 	}
950 
951 	// for equalities, append exact values to approximate value (as third part of equalities)
952 	if(do_exact) {
953 		if(mexact.isComparison() && mexact.comparisonType() == COMPARISON_EQUALS) {
954 			mexact[1].ref();
955 			if(m.isComparison()) {
956 				m.addChild_nocopy(&mexact[1]);
957 				if(exact_cmp && po.use_unicode_signs) *exact_cmp = true;
958 			} else {
959 				// only the first exact value is used from logical and
960 				m[0].addChild_nocopy(&mexact[1]);
961 			}
962 		} else if(mexact.isLogicalOr()) {
963 			if(exact_cmp && po.use_unicode_signs) *exact_cmp = true;
964 			for(size_t i = 0; i < mexact.size(); i++) {
965 				mexact[i][1].ref();
966 				if(m[i].isComparison()) {
967 					m[i].addChild_nocopy(&mexact[i][1]);
968 				} else {
969 					// only the first exact value is used from logical and
970 					m[i][0].addChild_nocopy(&mexact[i][1]);
971 					if(exact_cmp) *exact_cmp = false;
972 				}
973 			}
974 		}
975 	}
976 
977 	m.removeDefaultAngleUnit(evalops);
978 	m.format(po);
979 	m.removeDefaultAngleUnit(evalops);
980 
981 	if(auto_frac != AUTOMATIC_FRACTION_OFF && po.base == 10 && po.base == evalops.parse_options.base && po.number_fraction_format == FRACTION_DECIMAL_EXACT && !m.isApproximate() && mresult.isNumber() && !mresult.number().isFraction() && !mresult.number().isNegative() && b_parsed && mparse.equals(m)) {
982 		po.number_fraction_format = FRACTION_COMBINED;
983 		m = mresult;
984 		m.removeDefaultAngleUnit(evalops);
985 		m.format(po);
986 		m.removeDefaultAngleUnit(evalops);
987 	}
988 	int dappr = 0, dfrac = 0;
989 	if(auto_frac == AUTOMATIC_FRACTION_AUTO) dfrac = -1;
990 	else if(auto_frac == AUTOMATIC_FRACTION_DUAL) dfrac = 1;
991 	if(auto_approx == AUTOMATIC_APPROXIMATION_AUTO) dappr = -1;
992 	else if(auto_approx == AUTOMATIC_APPROXIMATION_DUAL) dappr = 1;
993 	if(m.isLogicalOr()) {
994 		if(max_length > 0) max_length /= m.size();
995 		InternalPrintStruct ips;
996 		bool b_approx = false;
997 		for(size_t i = 0; i < m.size(); i++) {
998 			if(CALCULATOR->aborted()) {result_str = CALCULATOR->abortedMessage(); break;}
999 			if(i == 0) {
1000 				result_str = "";
1001 			} else if(po.spell_out_logical_operators) {
1002 				result_str += " ";
1003 				result_str += _("or");
1004 				result_str += " ";
1005 			} else {
1006 				if(po.spacious) result_str += " ";
1007 				result_str += "||";
1008 				if(po.spacious) result_str += " ";
1009 			}
1010 			if(m[i].isLogicalAnd() && (po.preserve_format || m[i].size() != 2 || !m[i][0].isComparison() || !m[i][1].isComparison() || m[i][0].comparisonType() == COMPARISON_EQUALS || m[i][0].comparisonType() == COMPARISON_NOT_EQUALS || m[i][1].comparisonType() == COMPARISON_EQUALS || m[i][1].comparisonType() == COMPARISON_NOT_EQUALS || m[i][0][0] != m[i][1][0])) {
1011 				int ml = max_length / m[i].size();
1012 				for(size_t i2 = 0; i2 < m[i].size(); i2++) {
1013 					if(CALCULATOR->aborted()) {result_str = CALCULATOR->abortedMessage(); break;}
1014 					if(i2 > 0) {
1015 						if(po.spell_out_logical_operators) {
1016 							result_str += " ";
1017 							result_str += _("and");
1018 							result_str += " ";
1019 						} else {
1020 							if(po.spacious) result_str += " ";
1021 							result_str += "&&";
1022 							if(po.spacious) result_str += " ";
1023 						}
1024 					}
1025 					bool b_wrap = m[i][i2].needsParenthesis(po, ips, m[i], i2 + 1, true, true);
1026 					string str;
1027 					print_m(po, evalops, str, results_v, m[i][i2], &m[i][i2], original_expression, &mparse, dfrac, dappr, cplx_angle, true, format, colorize, tagtype, ml);
1028 					if(b_wrap) result_str += "(";
1029 					result_str += str;
1030 					if(b_wrap) result_str += ")";
1031 					if(b_approx) *po.is_approximate = true;
1032 					b_approx = *po.is_approximate;
1033 				}
1034 			} else {
1035 				bool b_wrap = m[i].needsParenthesis(po, ips, m, i + 1, true, true);
1036 				string str;
1037 				print_m(po, evalops, str, results_v, m[i], &m[i], original_expression, &mparse, dfrac, dappr, cplx_angle, true, format, colorize, tagtype, max_length);
1038 				if(b_wrap) result_str += "(";
1039 				result_str += str;
1040 				if(b_wrap) result_str += ")";
1041 				if(b_approx) *po.is_approximate = true;
1042 				b_approx = *po.is_approximate;
1043 			}
1044 		}
1045 	} else if(m.isLogicalAnd() && (po.preserve_format || m.size() != 2 || !m[0].isComparison() || !m[1].isComparison() || m[0].comparisonType() == COMPARISON_EQUALS || m[0].comparisonType() == COMPARISON_NOT_EQUALS || m[1].comparisonType() == COMPARISON_EQUALS || m[1].comparisonType() == COMPARISON_NOT_EQUALS || m[0][0] != m[1][0])) {
1046 		InternalPrintStruct ips;
1047 		bool b_approx = false;
1048 		max_length /= m.size();
1049 		for(size_t i = 0; i < m.size(); i++) {
1050 			if(CALCULATOR->aborted()) {result_str = CALCULATOR->abortedMessage(); break;}
1051 			if(i == 0) {
1052 				result_str = "";
1053 			} else if(po.spell_out_logical_operators) {
1054 				result_str += " ";
1055 				result_str += _("and");
1056 				result_str += " ";
1057 			} else {
1058 				if(po.spacious) result_str += " ";
1059 				result_str += "&&";
1060 				if(po.spacious) result_str += " ";
1061 			}
1062 			bool b_wrap = m[i].needsParenthesis(po, ips, m, i + 1, true, true);
1063 			string str;
1064 			print_m(po, evalops, str, results_v, m[i], &m[i], original_expression, &mparse, dfrac, dappr, cplx_angle, true, format, colorize, tagtype, max_length);
1065 			if(b_wrap) result_str += "(";
1066 			result_str += str;
1067 			if(b_wrap) result_str += ")";
1068 			if(b_approx) *po.is_approximate = true;
1069 			b_approx = *po.is_approximate;
1070 		}
1071 	} else {
1072 		print_m(po, evalops, result_str, results_v, m, &mresult, original_expression, &mparse, dfrac, dappr, cplx_angle, false, format, colorize, tagtype, max_length);
1073 		if(do_exact && (m.type() != STRUCT_COMPARISON || m.comparisonType() != COMPARISON_EQUALS)) {
1074 			bool *old_approx = po.is_approximate;
1075 			bool b_approx = false;
1076 			po.is_approximate = &b_approx;
1077 			MathStructure mexact2(mexact);
1078 			po.number_fraction_format = FRACTION_FRACTIONAL;
1079 			po.restrict_fraction_length = true;
1080 			mexact2.removeDefaultAngleUnit(evalops);
1081 			mexact2.format(po);
1082 			mexact2.removeDefaultAngleUnit(evalops);
1083 			string str = mexact2.print(po, format, colorize, tagtype);
1084 			if(!b_approx) {
1085 				results_v.push_back(str);
1086 			}
1087 			po.is_approximate = old_approx;
1088 		}
1089 	}
1090 	po.is_approximate = save_is_approximate;
1091 	if(po.is_approximate && result_str == _("aborted")) {
1092 		*po.is_approximate = false;
1093 	}
1094 }
1095 
test_simplified(const MathStructure & m)1096 bool test_simplified(const MathStructure &m) {
1097 	if(m.isFunction() || (m.isVariable() && m.variable()->isKnown()) || (m.isUnit() && m.unit()->hasApproximateRelationToBase())) return false;
1098 	for(size_t i = 0; i < m.size(); i++) {
1099 		if(!test_simplified(m[i])) return false;
1100 	}
1101 	if(m.isPower() && m[0].containsType(STRUCT_NUMBER)) return false;
1102 	return true;
1103 }
flatten_addmulti(MathStructure & m)1104 void flatten_addmulti(MathStructure &m) {
1105 	if(m.isMultiplication() || m.isAddition()) {
1106 		for(size_t i = 0; i < m.size();) {
1107 			if(m[i].type() == m.type()) {
1108 				for(size_t i2 = 0; i2 < m[i].size(); i2++) {
1109 					m[i][i2].ref();
1110 					m.insertChild_nocopy(&m[i][i2], i + i2 + 2);
1111 				}
1112 				m.delChild(i + 1);
1113 			} else {
1114 				i++;
1115 			}
1116 		}
1117 	}
1118 	for(size_t i = 0; i < m.size(); i++) {
1119 		flatten_addmulti(m[i]);
1120 	}
1121 }
replace_negdiv(MathStructure & m)1122 void replace_negdiv(MathStructure &m) {
1123 	if(m.isDivision() && m[1].isMultiplication() && m[1].size() > 0) {
1124 		for(size_t i = 0; i < m[1].size(); i++) {
1125 			m[1][i].transform(STRUCT_INVERSE);
1126 		}
1127 		if(m[0].isOne()) {
1128 			m.setToChild(2);
1129 		} else {
1130 			m[0].ref();
1131 			MathStructure *m0 = &m[0];
1132 			m.setToChild(2);
1133 			m.insertChild_nocopy(m0, 1);
1134 		}
1135 		return replace_negdiv(m);
1136 	}
1137 	if(m.isDivision() && m[1].isPower()) {
1138 		if(m[1][1].isNegate()) {
1139 			m[1][1].setToChild(1);
1140 		} else {
1141 			m[1][1].transform(STRUCT_NEGATE);
1142 		}
1143 		if(m[0].isOne()) {
1144 			m.setToChild(2);
1145 		} else {
1146 			m.setType(STRUCT_MULTIPLICATION);
1147 		}
1148 		return replace_negdiv(m);
1149 	}
1150 	if(m.isInverse() && m[0].isMultiplication() && m[0].size() > 0) {
1151 		for(size_t i = 0; i < m[0].size(); i++) {
1152 			m[0][i].transform(STRUCT_INVERSE);
1153 		}
1154 		m.setToChild(1);
1155 		return replace_negdiv(m);
1156 	}
1157 	if(m.isInverse() && m[0].isPower()) {
1158 		if(m[0][1].isNegate()) {
1159 			m[0][1].setToChild(1);
1160 		} else {
1161 			m[0][1].transform(STRUCT_NEGATE);
1162 		}
1163 		m.setToChild(1);
1164 		return replace_negdiv(m);
1165 	}
1166 	if(m.isNegate()) {
1167 		if(m[0].isNumber()) {
1168 			m[0].number().negate();
1169 			m.setToChild(1);
1170 			return replace_negdiv(m);
1171 		} else if((m[0].isDivision() || m[0].isInverse() || m[0].isMultiplication()) && m[0].size() > 0) {
1172 			m[0][0].transform(STRUCT_NEGATE);
1173 			m.setToChild(1);
1174 			return replace_negdiv(m);
1175 		}
1176 	}
1177 	for(size_t i = 0; i < m.size(); i++) {
1178 		replace_negdiv(m[i]);
1179 	}
1180 	if(m.isFunction()) {
1181 		if(m.function()->id() == FUNCTION_ID_SQRT && m.size() == 1) {
1182 			m.setType(STRUCT_POWER);
1183 			m.addChild(nr_half);
1184 		} else if(m.function()->id() == FUNCTION_ID_CBRT && m.size() == 1) {
1185 			if(m[0].representsNonNegative()) {
1186 				m.setType(STRUCT_POWER);
1187 				m.addChild(Number(1, 3));
1188 			} else if(m[0].representsNonPositive()) {
1189 				if(m[0].isNumber()) m[0].number().negate();
1190 				else m[0].negate();
1191 				m.setType(STRUCT_POWER);
1192 				m.addChild(Number(1, 3));
1193 				m.negate();
1194 			} else {
1195 				m.setFunctionId(FUNCTION_ID_ROOT);
1196 				m.addChild(nr_three);
1197 			}
1198 		} else if(m.function()->id() == FUNCTION_ID_ROOT && m.size() == 2 && m[1].isInteger()) {
1199 			if(m[0].representsNonNegative()) {
1200 				m.setType(STRUCT_POWER);
1201 				m[1].number().recip();
1202 			} else if(m[1].representsOdd() && m[0].representsNonPositive()) {
1203 				if(m[0].isNumber()) m[0].number().negate();
1204 				else m[0].negate();
1205 				m[1].number().recip();
1206 				m.setType(STRUCT_POWER);
1207 				m.negate();
1208 			}
1209 		}
1210 	}
1211 	if(m.isDivision()) {
1212 		if(m[1].isInteger()) {
1213 			if(m[0].isMultiplication() && m[0].size() > 0) {
1214 				m[0].unformat();
1215 				flatten_addmulti(m[0]);
1216 				m[0].evalSort(false);
1217 				if(m[0][0].isInteger()) {
1218 					m[0][0].number() /= m[1].number();
1219 					m.setToChild(1);
1220 				} else {
1221 					m.setType(STRUCT_MULTIPLICATION);
1222 					m[1].number().recip();
1223 				}
1224 			} else if(m[0].isInteger()) {
1225 				m[0].number() /= m[1].number();
1226 				m.setToChild(1);
1227 			} else {
1228 				m.setType(STRUCT_MULTIPLICATION);
1229 				m[1].number().recip();
1230 			}
1231 		}
1232 	}
1233 }
replace_zero_symbol(MathStructure & m)1234 void replace_zero_symbol(MathStructure &m) {
1235 	if(m.isFunction()) {
1236 		for(size_t i = 1; i < m.size(); i++) {
1237 			Argument *arg = m.function()->getArgumentDefinition(i + 1);
1238 			if(arg && arg->type() == ARGUMENT_TYPE_SYMBOLIC && (m[i].isZero() || m[i].isUndefined())) {
1239 				m[i].set(m[0].find_x_var(), true);
1240 				if(m[i].isUndefined() && m[0].isVariable() && m[0].variable()->isKnown()) m[i].set(((KnownVariable*) m[0].variable())->get().find_x_var(), true);
1241 				if(m[i].isUndefined()) m[i].set(CALCULATOR->getVariableById(VARIABLE_ID_X), true);
1242 			}
1243 		}
1244 	}
1245 	for(size_t i = 0; i < m.size(); i++) {
1246 		replace_zero_symbol(m[i]);
1247 	}
1248 }
comparison_compare(const MathStructure m1,const MathStructure & m2)1249 bool comparison_compare(const MathStructure m1, const MathStructure &m2) {
1250 	if(m1.isNumber() && m2.isNumber()) {
1251 		ComparisonResult cr = m1.number().compare(m2.number(), true);
1252 		if(cr == COMPARISON_RESULT_EQUAL || cr > COMPARISON_RESULT_UNKNOWN) {
1253 			if(m1.number().hasImaginaryPart() || m2.number().hasImaginaryPart()) {
1254 				cr = m1.number().compareImaginaryParts(m2.number());
1255 				return cr == COMPARISON_RESULT_EQUAL || cr > COMPARISON_RESULT_UNKNOWN;
1256 			}
1257 			return true;
1258 		}
1259 		return false;
1260 	} else if(m1.isMultiplication() && m2.isMultiplication() && m1.size() > 0 && (m1[0].isNumber() || m2[0].isNumber())) {
1261 		size_t i1 = 0, i2 = 0;
1262 		if(m1[0].isNumber()) i1 = 1;
1263 		if(m2[0].isNumber()) i2 = 1;
1264 		if(m1.size() + i1 == m2.size() + i2) {
1265 			for(size_t i = 0; i < m1.size() - i1; i++) {
1266 				if(!m1[i + i1].equals(m2[i + i2], true)) return false;
1267 			}
1268 			ComparisonResult cr;
1269 			if(i1 == 0) cr = nr_one.compare(m2[0].number(), true);
1270 			else cr = m1[0].number().compare(i2 == 0 ? nr_one : m2[0].number(), true);
1271 			if(cr == COMPARISON_RESULT_EQUAL || cr > COMPARISON_RESULT_UNKNOWN) {
1272 				if((i1 > 0 && m1[0].number().hasImaginaryPart()) || (i2 > 0 && m2[0].number().hasImaginaryPart())) {
1273 					if(i1 == 0) cr = nr_one.compareImaginaryParts(m2[0].number());
1274 					else cr = m1[0].number().compareImaginaryParts(i2 == 0 ? nr_one : m2[0].number());
1275 					return cr == COMPARISON_RESULT_EQUAL || cr > COMPARISON_RESULT_UNKNOWN;
1276 				}
1277 				return true;
1278 			}
1279 		}
1280 		return false;
1281 	} else {
1282 		return m1.equals(m2, true);
1283 	}
1284 	return false;
1285 }
test_max_addition_size(const MathStructure & m,size_t n)1286 bool test_max_addition_size(const MathStructure &m, size_t n) {
1287 	if(m.isAddition() && m.size() > n) return true;
1288 	for(size_t i = 0; i < m.size(); i++) {
1289 		if(test_max_addition_size(m[i], n)) return true;
1290 	}
1291 	return false;
1292 }
1293 
calculate_dual_exact(MathStructure & mstruct_exact,MathStructure * mstruct,const string & original_expression,const MathStructure * parsed_mstruct,EvaluationOptions & evalops,AutomaticApproximation auto_approx,int msecs,int max_size)1294 void calculate_dual_exact(MathStructure &mstruct_exact, MathStructure *mstruct, const string &original_expression, const MathStructure *parsed_mstruct, EvaluationOptions &evalops, AutomaticApproximation auto_approx, int msecs, int max_size) {
1295 	int dual_approximation = 0;
1296 	if(auto_approx == AUTOMATIC_APPROXIMATION_AUTO) dual_approximation = -1;
1297 	else if(auto_approx == AUTOMATIC_APPROXIMATION_DUAL) dual_approximation = 1;
1298 	if(dual_approximation != 0 && evalops.approximation == APPROXIMATION_TRY_EXACT && mstruct->isApproximate() && (dual_approximation > 0 || (!mstruct->containsType(STRUCT_UNIT, false, false, false) && !parsed_mstruct->containsType(STRUCT_UNIT, false, false, false) && original_expression.find(DOT) == string::npos)) && !parsed_mstruct->containsFunctionId(FUNCTION_ID_SAVE) && !parsed_mstruct->containsFunctionId(FUNCTION_ID_PLOT) && !parsed_mstruct->containsInterval(true, false, false, false, true)) {
1299 		evalops.approximation = APPROXIMATION_EXACT;
1300 		evalops.expand = -2;
1301 		CALCULATOR->beginTemporaryStopMessages();
1302 		if(msecs > 0) CALCULATOR->startControl(msecs);
1303 		mstruct_exact = CALCULATOR->calculate(original_expression, evalops);
1304 		if(CALCULATOR->aborted() || mstruct_exact.isApproximate() || (dual_approximation < 0 && max_size > 0 && (test_max_addition_size(mstruct_exact, (size_t) max_size) || mstruct_exact.countTotalChildren(false) > (size_t) max_size * 5))) {
1305 			mstruct_exact.setUndefined();
1306 		} else if(test_simplified(mstruct_exact)) {
1307 			mstruct->set(mstruct_exact);
1308 			mstruct_exact.setUndefined();
1309 		}
1310 		evalops.approximation = APPROXIMATION_TRY_EXACT;
1311 		evalops.expand = true;
1312 		if(mstruct_exact.containsType(STRUCT_COMPARISON)) {
1313 			bool b = false;
1314 			MathStructure *mcmp = mstruct;
1315 			if(mcmp->isLogicalAnd() && mcmp->size() > 0) mcmp = &(*mcmp)[0];
1316 			if(mcmp->isComparison() && (mcmp->comparisonType() == COMPARISON_EQUALS || dual_approximation > 0) && !(*mcmp)[0].isNumber()) {
1317 				if(mstruct_exact.isLogicalAnd() && mstruct_exact.size() > 0) mstruct_exact.setToChild(1);
1318 				if(mstruct_exact.isComparison() && mstruct_exact.comparisonType() == mcmp->comparisonType() && mstruct_exact[0] == (*mcmp)[0]) {
1319 					MathStructure mtest(mstruct_exact[1]);
1320 					mtest.eval(evalops);
1321 					if(comparison_compare(mtest, (*mcmp)[1])) {
1322 						if(!mtest.isApproximate()) {(*mcmp)[1].set(mtest); mstruct_exact[1].setUndefined();}
1323 						b = true;
1324 					}
1325 				} else if(mstruct_exact.isLogicalOr()) {
1326 					for(size_t i = 0; i < mstruct_exact.size(); i++) {
1327 						if(mstruct_exact[i].isLogicalAnd() && mstruct_exact[i].size() > 0) mstruct_exact[i].setToChild(1);
1328 						if(mstruct_exact[i].isComparison() && mstruct_exact[i].comparisonType() == mcmp->comparisonType() && mstruct_exact[i][0] == (*mcmp)[0]) {
1329 							MathStructure mtest(mstruct_exact[i][1]);
1330 							if(CALCULATOR->aborted()) break;
1331 							mtest.eval(evalops);
1332 							if(comparison_compare(mtest, (*mcmp)[1])) {
1333 								mstruct_exact.setToChild(i + 1);
1334 								if(!mtest.isApproximate()) {(*mcmp)[1].set(mtest); mstruct_exact[1].setUndefined();}
1335 								b = true;
1336 								break;
1337 							}
1338 						}
1339 					}
1340 				}
1341 			} else if(mcmp->isLogicalOr()) {
1342 				if(mstruct_exact.isLogicalOr() && mstruct_exact.size() >= mcmp->size()) {
1343 					b = true;
1344 					for(size_t i = 0; i < mcmp->size() && b; i++) {
1345 						MathStructure *mcmpi = &(*mcmp)[i];
1346 						if(mcmpi->isLogicalAnd() && mcmpi->size() > 0) mcmpi = &(*mcmpi)[0];
1347 						if(!mcmpi->isComparison() || mcmpi->comparisonType() != COMPARISON_EQUALS || (*mcmpi)[0].isNumber()) {b = false; break;}
1348 						for(size_t i2 = 0; i2 < mstruct_exact.size();) {
1349 							if(mstruct_exact[i2].isProtected()) {
1350 								i2++;
1351 							} else {
1352 								if(mstruct_exact[i2].isLogicalAnd() && mstruct_exact[i2].size() > 0) mstruct_exact[i2].setToChild(1);
1353 								if(mstruct_exact[i2].isComparison() && mstruct_exact[i2].comparisonType() == mcmpi->comparisonType() && mstruct_exact[i2][0] == (*mcmpi)[0]) {
1354 									MathStructure mtest(mstruct_exact[i2][1]);
1355 									if(CALCULATOR->aborted()) break;
1356 									mtest.eval(evalops);
1357 									if(comparison_compare(mtest, (*mcmpi)[1])) {
1358 										if(!mtest.isApproximate()) {(*mcmpi)[1].set(mtest); mstruct_exact[i2][1].setUndefined();}
1359 										mstruct_exact[i2].setProtected();
1360 										break;
1361 									}
1362 								}
1363 								if(mstruct_exact.size() <= mcmp->size()) {b = false; break;}
1364 								mstruct_exact.delChild(i2 + 1);
1365 							}
1366 						}
1367 					}
1368 					if(b) {
1369 						for(size_t i2 = 0; i2 < mstruct_exact.size(); i2++) mstruct_exact[i2].setProtected(false);
1370 					}
1371 				}
1372 			}
1373 			if(!b) mstruct_exact.setUndefined();
1374 		}
1375 		if(!mstruct_exact.isUndefined()) {
1376 			MathStructure mtest(*parsed_mstruct);
1377 			flatten_addmulti(mtest);
1378 			replace_negdiv(mtest);
1379 			mtest.unformat(evalops);
1380 			flatten_addmulti(mtest);
1381 			replace_zero_symbol(mtest);
1382 			mtest.evalSort(true);
1383 			if(mstruct_exact.equals(mtest, true, true)) mstruct_exact.setUndefined();
1384 		}
1385 		if(msecs > 0) CALCULATOR->stopControl();
1386 		CALCULATOR->endTemporaryStopMessages();
1387 	}
1388 }
1389 
1390 #define EQUALS_IGNORECASE_AND_LOCAL(x,y,z)	(equalsIgnoreCase(x, y) || equalsIgnoreCase(x, z))
calculateAndPrint(string str,int msecs,const EvaluationOptions & eo,const PrintOptions & po)1391 string Calculator::calculateAndPrint(string str, int msecs, const EvaluationOptions &eo, const PrintOptions &po) {
1392 	return calculateAndPrint(str, msecs, eo, po, NULL);
1393 }
calculateAndPrint(string str,int msecs,const EvaluationOptions & eo,const PrintOptions & po,std::string * parsed_expression)1394 string Calculator::calculateAndPrint(string str, int msecs, const EvaluationOptions &eo, const PrintOptions &po, std::string *parsed_expression) {
1395 	return calculateAndPrint(str, msecs, eo, po, AUTOMATIC_FRACTION_OFF, AUTOMATIC_APPROXIMATION_OFF, parsed_expression, -1);
1396 }
calculateAndPrint(string str,int msecs,const EvaluationOptions & eo,const PrintOptions & po,AutomaticFractionFormat auto_fraction,AutomaticApproximation auto_approx,std::string * parsed_expression,int max_length,bool * result_is_comparison)1397 string Calculator::calculateAndPrint(string str, int msecs, const EvaluationOptions &eo, const PrintOptions &po, AutomaticFractionFormat auto_fraction, AutomaticApproximation auto_approx, std::string *parsed_expression, int max_length, bool *result_is_comparison) {
1398 
1399 	if(msecs > 0) startControl(msecs);
1400 
1401 	PrintOptions printops = po;
1402 	EvaluationOptions evalops = eo;
1403 
1404 	if(auto_fraction != AUTOMATIC_FRACTION_OFF) printops.number_fraction_format = FRACTION_DECIMAL;
1405 	if(auto_approx != AUTOMATIC_APPROXIMATION_OFF) evalops.approximation = APPROXIMATION_TRY_EXACT;
1406 
1407 	MathStructure mstruct;
1408 	bool do_bases = false, do_factors = false, do_pfe = false, do_calendars = false, do_expand = false, do_binary_prefixes = false, complex_angle_form = false;
1409 
1410 	string to_str = parseComments(str, evalops.parse_options);
1411 	if(!to_str.empty() && str.empty()) {stopControl(); if(parsed_expression) {*parsed_expression = "";} return "";}
1412 
1413 	// separate and handle string after "to"
1414 	string from_str = str, str_conv;
1415 	Number base_save;
1416 	bool custom_base_set = false;
1417 	int save_bin = priv->use_binary_prefixes;
1418 	bool had_to_expression = false;
1419 	if(separateToExpression(from_str, to_str, evalops, true)) {
1420 		remove_duplicate_blanks(to_str);
1421 		string str_left;
1422 		string to_str1, to_str2;
1423 		had_to_expression = true;
1424 		while(true) {
1425 			CALCULATOR->separateToExpression(to_str, str_left, evalops, true);
1426 			remove_blank_ends(to_str);
1427 			size_t ispace = to_str.find_first_of(SPACES);
1428 			if(ispace != string::npos) {
1429 				to_str1 = to_str.substr(0, ispace);
1430 				remove_blank_ends(to_str1);
1431 				to_str2 = to_str.substr(ispace + 1);
1432 				remove_blank_ends(to_str2);
1433 			}
1434 			if(equalsIgnoreCase(to_str, "hex") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "hexadecimal", _("hexadecimal"))) {
1435 				printops.base = BASE_HEXADECIMAL;
1436 			} else if(equalsIgnoreCase(to_str, "bin") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "binary", _("binary"))) {
1437 				printops.base = BASE_BINARY;
1438 			} else if(equalsIgnoreCase(to_str, "dec") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "decimal", _("decimal"))) {
1439 				printops.base = BASE_DECIMAL;
1440 			} else if(equalsIgnoreCase(to_str, "oct") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "octal", _("octal"))) {
1441 				printops.base = BASE_OCTAL;
1442 			} else if(equalsIgnoreCase(to_str, "duo") || EQUALS_IGNORECASE_AND_LOCAL(to_str, "duodecimal", _("duodecimal"))) {
1443 				printops.base = BASE_DUODECIMAL;
1444 			} else if(equalsIgnoreCase(to_str, "roman") || equalsIgnoreCase(to_str, _("roman"))) {
1445 				printops.base = BASE_ROMAN_NUMERALS;
1446 			} else if(equalsIgnoreCase(to_str, "bijective") || equalsIgnoreCase(to_str, _("bijective"))) {
1447 				printops.base = BASE_BIJECTIVE_26;
1448 			} else if(equalsIgnoreCase(to_str, "sexa") || equalsIgnoreCase(to_str, "sexagesimal") || equalsIgnoreCase(to_str, _("sexagesimal"))) {
1449 				printops.base = BASE_SEXAGESIMAL;
1450 			} else if(equalsIgnoreCase(to_str, "binary32") || equalsIgnoreCase(to_str, "float") || equalsIgnoreCase(to_str, "fp32")) {
1451 				printops.base = BASE_FP32;
1452 			} else if(equalsIgnoreCase(to_str, "binary64") || equalsIgnoreCase(to_str, "double") || equalsIgnoreCase(to_str, "fp64")) {
1453 				printops.base = BASE_FP64;
1454 			} else if(equalsIgnoreCase(to_str, "binary16") || equalsIgnoreCase(to_str, "fp16")) {
1455 				printops.base = BASE_FP16;
1456 			} else if(equalsIgnoreCase(to_str, "fp80")) {
1457 				printops.base = BASE_FP80;
1458 			} else if(equalsIgnoreCase(to_str, "binary128") || equalsIgnoreCase(to_str, "fp128")) {
1459 				printops.base = BASE_FP128;
1460 			} else if(equalsIgnoreCase(to_str, "time") || equalsIgnoreCase(to_str, _("time"))) {
1461 				printops.base = BASE_TIME;
1462 			} else if(equalsIgnoreCase(to_str, "unicode")) {
1463 				printops.base = BASE_UNICODE;
1464 			} else if(equalsIgnoreCase(to_str, "utc") || equalsIgnoreCase(to_str, "gmt")) {
1465 				printops.time_zone = TIME_ZONE_UTC;
1466 			} else if(to_str.length() > 3 && equalsIgnoreCase(to_str.substr(0, 3), "bin") && is_in(NUMBERS, to_str[3])) {
1467 				printops.base = BASE_BINARY;
1468 				printops.binary_bits = s2i(to_str.substr(3));
1469 			} else if(to_str.length() > 3 && equalsIgnoreCase(to_str.substr(0, 3), "hex") && is_in(NUMBERS, to_str[3])) {
1470 				printops.base = BASE_HEXADECIMAL;
1471 				printops.binary_bits = s2i(to_str.substr(3));
1472 			} else if(to_str.length() > 3 && (equalsIgnoreCase(to_str.substr(0, 3), "utc") || equalsIgnoreCase(to_str.substr(0, 3), "gmt"))) {
1473 				to_str = to_str.substr(3);
1474 				remove_blanks(to_str);
1475 				bool b_minus = false;
1476 				if(to_str[0] == '+') {
1477 					to_str.erase(0, 1);
1478 				} else if(to_str[0] == '-') {
1479 					b_minus = true;
1480 					to_str.erase(0, 1);
1481 				} else if(to_str.find(SIGN_MINUS) == 0) {
1482 					b_minus = true;
1483 					to_str.erase(0, strlen(SIGN_MINUS));
1484 				}
1485 				unsigned int tzh = 0, tzm = 0;
1486 				int itz = 0;
1487 				if(!to_str.empty() && sscanf(to_str.c_str(), "%2u:%2u", &tzh, &tzm) > 0) {
1488 					itz = tzh * 60 + tzm;
1489 					if(b_minus) itz = -itz;
1490 				} else {
1491 					error(true, _("Time zone parsing failed."), NULL);
1492 				}
1493 				printops.time_zone = TIME_ZONE_CUSTOM;
1494 				printops.custom_time_zone = itz;
1495 			} else if(to_str == "CET") {
1496 				printops.time_zone = TIME_ZONE_CUSTOM;
1497 				printops.custom_time_zone = 60;
1498 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "rectangular", _("rectangular")) || EQUALS_IGNORECASE_AND_LOCAL(to_str, "cartesian", _("cartesian")) || str == "rect") {
1499 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_RECTANGULAR;
1500 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "exponential", _("exponential")) || to_str == "exp") {
1501 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_EXPONENTIAL;
1502 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "polar", _("polar"))) {
1503 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_POLAR;
1504 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "angle", _("angle")) || EQUALS_IGNORECASE_AND_LOCAL(to_str, "phasor", _("phasor"))) {
1505 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
1506 				complex_angle_form = true;
1507 			} else if(to_str == "cis") {
1508 				evalops.complex_number_form = COMPLEX_NUMBER_FORM_CIS;
1509 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "fraction", _("fraction"))) {
1510 				printops.number_fraction_format = FRACTION_COMBINED;
1511 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "factors", _("factors")) || equalsIgnoreCase(to_str, "factor")) {
1512 				evalops.structuring = STRUCTURING_FACTORIZE;
1513 				do_factors = true;
1514 			}  else if(equalsIgnoreCase(to_str, "partial fraction") || equalsIgnoreCase(to_str, _("partial fraction"))) {
1515 				do_pfe = true;
1516 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "bases", _("bases"))) {
1517 				do_bases = true;
1518 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "calendars", _("calendars"))) {
1519 				do_calendars = true;
1520 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "optimal", _("optimal"))) {
1521 				evalops.parse_options.units_enabled = true;
1522 				evalops.auto_post_conversion = POST_CONVERSION_OPTIMAL_SI;
1523 				str_conv = "";
1524 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "base", _("base"))) {
1525 				evalops.parse_options.units_enabled = true;
1526 				evalops.auto_post_conversion = POST_CONVERSION_BASE;
1527 				str_conv = "";
1528 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str1, "base", _("base"))) {
1529 				if(to_str2 == "b26" || to_str2 == "B26") printops.base = BASE_BIJECTIVE_26;
1530 				else if(equalsIgnoreCase(to_str2, "golden") || equalsIgnoreCase(to_str2, "golden ratio") || to_str2 == "φ") printops.base = BASE_GOLDEN_RATIO;
1531 				else if(equalsIgnoreCase(to_str2, "unicode")) printops.base = BASE_UNICODE;
1532 				else if(equalsIgnoreCase(to_str2, "supergolden") || equalsIgnoreCase(to_str2, "supergolden ratio") || to_str2 == "ψ") printops.base = BASE_SUPER_GOLDEN_RATIO;
1533 				else if(equalsIgnoreCase(to_str2, "pi") || to_str2 == "π") printops.base = BASE_PI;
1534 				else if(to_str2 == "e") printops.base = BASE_E;
1535 				else if(to_str2 == "sqrt(2)" || to_str2 == "sqrt 2" || to_str2 == "sqrt2" || to_str2 == "√2") printops.base = BASE_SQRT2;
1536 				else {
1537 					EvaluationOptions eo = evalops;
1538 					eo.parse_options.base = 10;
1539 					MathStructure m = calculate(to_str2, eo);
1540 					if(m.isInteger() && m.number() >= 2 && m.number() <= 36) {
1541 						printops.base = m.number().intValue();
1542 					} else {
1543 						printops.base = BASE_CUSTOM;
1544 						base_save = customOutputBase();
1545 						custom_base_set = true;
1546 						setCustomOutputBase(m.number());
1547 					}
1548 				}
1549 			} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "mixed", _("mixed"))) {
1550 				evalops.parse_options.units_enabled = true;
1551 				evalops.auto_post_conversion = POST_CONVERSION_NONE;
1552 				evalops.mixed_units_conversion = MIXED_UNITS_CONVERSION_FORCE_INTEGER;
1553 			} else {
1554 				// ? in front of unit epxression is interpreted as a request for the optimal prefix.
1555 				evalops.parse_options.units_enabled = true;
1556 				if(to_str[0] == '?' || (to_str.length() > 1 && to_str[1] == '?' && (to_str[0] == 'a' || to_str[0] == 'd'))) {
1557 					printops.use_unit_prefixes = true;
1558 					printops.use_prefixes_for_currencies = true;
1559 					printops.use_prefixes_for_all_units = true;
1560 					if(to_str[0] == 'a') printops.use_all_prefixes = true;
1561 					else if(to_str[0] == 'd') priv->use_binary_prefixes = 0;
1562 				} else if(to_str.length() > 1 && to_str[1] == '?' && to_str[0] == 'b') {
1563 					// b? in front of unit epxression: use binary prefixes
1564 					do_binary_prefixes = true;
1565 				}
1566 				// expression after "to" is by default interpreted as unit epxression
1567 				if(!str_conv.empty()) str_conv += " to ";
1568 				str_conv += to_str;
1569 			}
1570 			if(str_left.empty()) break;
1571 			to_str = str_left;
1572 		}
1573 		str = from_str;
1574 		if(!str_conv.empty()) {
1575 			str += " to ";
1576 			str += str_conv;
1577 		}
1578 	}
1579 
1580 	// check for factor or expand instruction at front a expression
1581 	size_t i = str.find_first_of(SPACES LEFT_PARENTHESIS);
1582 	if(i != string::npos) {
1583 		to_str = str.substr(0, i);
1584 		if(to_str == "factor" || EQUALS_IGNORECASE_AND_LOCAL(to_str, "factorize", _("factorize"))) {
1585 			str = str.substr(i + 1);
1586 			do_factors = true;
1587 			evalops.structuring = STRUCTURING_FACTORIZE;
1588 		} else if(EQUALS_IGNORECASE_AND_LOCAL(to_str, "expand", _("expand"))) {
1589 			str = str.substr(i + 1);
1590 			evalops.structuring = STRUCTURING_SIMPLIFY;
1591 			do_expand = true;
1592 		}
1593 	}
1594 
1595 	MathStructure parsed_struct;
1596 
1597 	bool units_changed = false;
1598 
1599 	// perform calculation
1600 	if(str_conv.empty() || hasToExpression(str_conv, false, evalops)) {
1601 		mstruct = calculate(str, evalops, &parsed_struct);
1602 	} else {
1603 		// handle case where conversion to units requested, but original expression and result does not contains any unit
1604 		MathStructure to_struct;
1605 		mstruct = calculate(str, evalops, &parsed_struct, &to_struct);
1606 		if(to_struct.containsType(STRUCT_UNIT, true) && !mstruct.contains(STRUCT_UNIT) && !parsed_struct.containsType(STRUCT_UNIT, false, true, true)) {
1607 			// convert "to"-expression to base units
1608 			to_struct.unformat();
1609 			to_struct = CALCULATOR->convertToOptimalUnit(to_struct, evalops, true);
1610 			// remove non-units, set local currency and use kg instead of g
1611 			fix_to_struct(to_struct);
1612 			// add base unit to from value
1613 			mstruct.multiply(to_struct);
1614 			to_struct.format(printops);
1615 			if(to_struct.isMultiplication() && to_struct.size() >= 2) {
1616 				if(to_struct[0].isOne()) to_struct.delChild(1, true);
1617 				else if(to_struct[1].isOne()) to_struct.delChild(2, true);
1618 			}
1619 			parsed_struct.multiply(to_struct, true);
1620 			// recalculate
1621 			if(!to_struct.isZero()) mstruct = calculate(mstruct, evalops, str_conv);
1622 			units_changed = true;
1623 		}
1624 	}
1625 
1626 	// Always perform conversion to optimal (SI) unit when the expression is a number multiplied by a unit and input equals output
1627 	if(!had_to_expression && ((evalops.approximation == APPROXIMATION_EXACT && evalops.auto_post_conversion != POST_CONVERSION_NONE) || evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL) && ((parsed_struct.isMultiplication() && parsed_struct.size() == 2 && parsed_struct[0].isNumber() && parsed_struct[1].isUnit_exp() && parsed_struct.equals(mstruct)) || (parsed_struct.isNegate() && parsed_struct[0].isMultiplication() && parsed_struct[0].size() == 2 && parsed_struct[0][0].isNumber() && parsed_struct[0][1].isUnit_exp() && mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[1] == parsed_struct[0][1] && mstruct[0].isNumber() && parsed_struct[0][0].number() == -mstruct[0].number()) || (parsed_struct.isUnit_exp() && parsed_struct.equals(mstruct)))) {
1628 		Unit *u = NULL;
1629 		MathStructure *munit = NULL;
1630 		if(mstruct.isMultiplication()) munit = &mstruct[1];
1631 		else munit = &mstruct;
1632 		if(munit->isUnit()) u = munit->unit();
1633 		else u = (*munit)[0].unit();
1634 		if(u && u->isCurrency()) {
1635 			if(evalops.local_currency_conversion && getLocalCurrency() && u != getLocalCurrency()) {
1636 				if(evalops.approximation == APPROXIMATION_EXACT) evalops.approximation = APPROXIMATION_TRY_EXACT;
1637 				mstruct.set(convertToOptimalUnit(mstruct, evalops, true));
1638 			}
1639 		} else if(u && u->subtype() != SUBTYPE_BASE_UNIT && !u->isSIUnit()) {
1640 			MathStructure mbak(mstruct);
1641 			if(evalops.auto_post_conversion == POST_CONVERSION_OPTIMAL) {
1642 				if(munit->isUnit() && u->referenceName() == "oF") {
1643 					u = getActiveUnit("oC");
1644 					if(u) mstruct.set(convert(mstruct, u, evalops, true, false));
1645 				} else {
1646 					mstruct.set(convertToOptimalUnit(mstruct, evalops, true));
1647 				}
1648 			}
1649 			if(evalops.approximation == APPROXIMATION_EXACT && (evalops.auto_post_conversion != POST_CONVERSION_OPTIMAL || mstruct.equals(mbak))) {
1650 				evalops.approximation = APPROXIMATION_TRY_EXACT;
1651 				if(evalops.auto_post_conversion == POST_CONVERSION_BASE) mstruct.set(convertToBaseUnits(mstruct, evalops));
1652 				else mstruct.set(convertToOptimalUnit(mstruct, evalops, true));
1653 			}
1654 		}
1655 	}
1656 
1657 	MathStructure mstruct_exact;
1658 	mstruct_exact.setUndefined();
1659 	if((!do_calendars || !mstruct.isDateTime()) && !do_bases && !units_changed && auto_approx != AUTOMATIC_APPROXIMATION_OFF && (auto_approx == AUTOMATIC_APPROXIMATION_DUAL || printops.base == BASE_DECIMAL)) {
1660 		bool b = true;
1661 		if(msecs > 0) {
1662 			long int usec, sec;
1663 #ifndef CLOCK_MONOTONIC
1664 			struct timeval tv;
1665 			gettimeofday(&tv, NULL);
1666 			usec = tv.tv_usec + msecs / 3L * 2L * 1000L;
1667 			sec = tv.tv_sec;
1668 			if(usec > 1000000L) {sec += usec / 1000000L; usec = usec % 1000000L;}
1669 #else
1670 			struct timespec tv;
1671 			clock_gettime(CLOCK_MONOTONIC, &tv);
1672 			usec = tv.tv_nsec / 1000L + msecs / 3L * 2L * 1000L;
1673 			sec = tv.tv_sec;
1674 			if(usec > 1000000L) {sec += usec / 1000000L; usec = usec % 1000000L;}
1675 #endif
1676 			if(sec > t_end.tv_sec || (sec == t_end.tv_sec && usec > t_end.tv_usec)) {
1677 				b = false;
1678 			}
1679 		}
1680 		if(b) {
1681 			calculate_dual_exact(mstruct_exact, &mstruct, str, &parsed_struct, evalops, auto_approx, 0, max_length);
1682 			if(CALCULATOR->aborted()) {
1683 				mstruct_exact.setUndefined();
1684 				CALCULATOR->stopControl();
1685 				CALCULATOR->startControl(msecs / 5);
1686 			}
1687 		}
1688 	}
1689 
1690 	// handle "to factors", and "factor" or "expand" in front of the expression
1691 	if(do_factors) {
1692 		mstruct.integerFactorize();
1693 		mstruct_exact.integerFactorize();
1694 	} else if(do_expand) {
1695 		mstruct.expand(evalops, false);
1696 	}
1697 
1698 	// handle "to partial fraction"
1699 	if(do_pfe) {
1700 		mstruct.expandPartialFractions(evalops);
1701 		mstruct_exact.expandPartialFractions(evalops);
1702 	}
1703 
1704 	printops.allow_factorization = printops.allow_factorization || evalops.structuring == STRUCTURING_FACTORIZE || do_factors;
1705 
1706 	bool exact_comparison = false;
1707 	vector<string> alt_results;
1708 	string result;
1709 	bool tmp_approx = false;
1710 	bool *save_is_approximate = printops.is_approximate;
1711 	if(!printops.is_approximate) printops.is_approximate = &tmp_approx;
1712 
1713 	if(do_calendars && mstruct.isDateTime()) {
1714 		// handle "to calendars"
1715 		bool b_fail;
1716 		long int y, m, d;
1717 #define PRINT_CALENDAR(x, c) if(!result.empty()) {result += "\n";} result += x; result += " "; b_fail = !dateToCalendar(*mstruct.datetime(), y, m, d, c); if(b_fail) {result += _("failed");} else {result += i2s(d); result += " "; result += monthName(m, c, true); result += " "; result += i2s(y);}
1718 		PRINT_CALENDAR(string(_("Gregorian:")), CALENDAR_GREGORIAN);
1719 		PRINT_CALENDAR(string(_("Hebrew:")), CALENDAR_HEBREW);
1720 		PRINT_CALENDAR(string(_("Islamic:")), CALENDAR_ISLAMIC);
1721 		PRINT_CALENDAR(string(_("Persian:")), CALENDAR_PERSIAN);
1722 		PRINT_CALENDAR(string(_("Indian national:")), CALENDAR_INDIAN);
1723 		PRINT_CALENDAR(string(_("Chinese:")), CALENDAR_CHINESE);
1724 		long int cy, yc, st, br;
1725 		chineseYearInfo(y, cy, yc, st, br);
1726 		if(!b_fail) {result += " ("; result += chineseStemName(st); result += string(" "); result += chineseBranchName(br); result += ")";}
1727 		PRINT_CALENDAR(string(_("Julian:")), CALENDAR_JULIAN);
1728 		PRINT_CALENDAR(string(_("Revised julian:")), CALENDAR_MILANKOVIC);
1729 		PRINT_CALENDAR(string(_("Coptic:")), CALENDAR_COPTIC);
1730 		PRINT_CALENDAR(string(_("Ethiopian:")), CALENDAR_ETHIOPIAN);
1731 		goto after_print;
1732 	} else if(do_bases) {
1733 		// handle "to bases"
1734 		printops.base = BASE_BINARY;
1735 		result = print(mstruct, 0, printops);
1736 		result += " = ";
1737 		printops.base = BASE_OCTAL;
1738 		result += print(mstruct, 0, printops);
1739 		result += " = ";
1740 		printops.base = BASE_DECIMAL;
1741 		result += print(mstruct, 0, printops);
1742 		result += " = ";
1743 		printops.base = BASE_HEXADECIMAL;
1744 		result += print(mstruct, 0, printops);
1745 		if(complex_angle_form) gsub(" cis ", "∠", result);
1746 		goto after_print;
1747 	} else if(do_binary_prefixes) {
1748 		// b? in front of unit expression: use binary prefixes
1749 		printops.use_unit_prefixes = true;
1750 		// check for information units in unit expression: if found use only binary prefixes for information units
1751 		int i = has_information_unit(mstruct);
1752 		priv->use_binary_prefixes = (i > 0 ? 1 : 2);
1753 		if(i == 1) {
1754 			printops.use_denominator_prefix = false;
1755 		} else if(i > 1) {
1756 			printops.use_denominator_prefix = true;
1757 		} else {
1758 			printops.use_prefixes_for_currencies = true;
1759 			printops.use_prefixes_for_all_units = true;
1760 		}
1761 	}
1762 
1763 	if(result_is_comparison) *result_is_comparison = false;
1764 
1765 	if(auto_fraction != AUTOMATIC_FRACTION_OFF || auto_approx != AUTOMATIC_APPROXIMATION_OFF) {
1766 		print_dual(mstruct, str, parsed_struct, mstruct_exact, result, alt_results, printops, evalops, auto_fraction, auto_approx, complex_angle_form, &exact_comparison, true, false, 0, TAG_TYPE_HTML, max_length);
1767 		if(!alt_results.empty()) {
1768 			bool use_par = mstruct.isComparison() || mstruct.isLogicalAnd() || mstruct.isLogicalOr();
1769 			str = result; result = "";
1770 			size_t equals_length = 3;
1771 			if(!printops.use_unicode_signs && (mstruct.isApproximate() || *printops.is_approximate)) equals_length += 1 + strlen(_("approx."));
1772 			for(size_t i = 0; i < alt_results.size();) {
1773 				if(max_length > 0 && unicode_length(str) + unicode_length(result) + unicode_length(alt_results[i]) + equals_length > (size_t) max_length) {
1774 					alt_results.erase(alt_results.begin() + i);
1775 				} else {
1776 					if(i > 0) result += " = ";
1777 					if(use_par) result += LEFT_PARENTHESIS;
1778 					result += alt_results[i];
1779 					if(use_par) result += RIGHT_PARENTHESIS;
1780 					i++;
1781 				}
1782 			}
1783 			if(alt_results.empty()) {
1784 				result += str;
1785 			} else {
1786 				if(mstruct.isApproximate() || *printops.is_approximate) {
1787 					if(printops.use_unicode_signs) {
1788 						result += " " SIGN_ALMOST_EQUAL " ";
1789 					} else {
1790 						result += " = ";
1791 						result += _("approx.");
1792 						result += " ";
1793 					}
1794 				} else {
1795 					result += " = ";
1796 				}
1797 				if(use_par) result += LEFT_PARENTHESIS;
1798 				result += str;
1799 				if(use_par) result += RIGHT_PARENTHESIS;
1800 			}
1801 		} else if(mstruct.isComparison() || mstruct.isLogicalOr() || mstruct.isLogicalAnd()) {
1802 			if(result_is_comparison) {
1803 				*result_is_comparison = true;
1804 			} else {
1805 				result.insert(0, LEFT_PARENTHESIS);
1806 				result += RIGHT_PARENTHESIS;
1807 			}
1808 		}
1809 	} else {
1810 
1811 		if(po.spell_out_logical_operators && test_parsed_comparison(parsed_struct)) {
1812 			if(mstruct.isZero()) {
1813 				Variable *v = getActiveVariable("false");
1814 				if(v) mstruct.set(v);
1815 			} else if(mstruct.isOne()) {
1816 				Variable *v = getActiveVariable("true");
1817 				if(v) mstruct.set(v);
1818 			}
1819 		}
1820 
1821 		// convert time units to hours when using time format
1822 		if(printops.base == BASE_TIME) {
1823 			bool b = false;
1824 			if(mstruct.isUnit() && mstruct.unit()->baseUnit()->referenceName() == "s") {
1825 				b = true;
1826 			} else if(mstruct.isMultiplication() && mstruct.size() == 2 && mstruct[0].isNumber() && mstruct[1].isUnit() && mstruct[1].unit()->baseUnit()->referenceName() == "s") {
1827 				b = true;
1828 			} else if(mstruct.isAddition() && mstruct.size() > 0) {
1829 				b = true;
1830 				for(size_t i = 0; i < mstruct.size(); i++) {
1831 					if(mstruct[i].isUnit() && mstruct[i].unit()->baseUnit()->referenceName() == "s") {}
1832 					else if(mstruct[i].isMultiplication() && mstruct[i].size() == 2 && mstruct[i][0].isNumber() && mstruct[i][1].isUnit() && mstruct[i][1].unit()->baseUnit()->referenceName() == "s") {}
1833 					else {b = false; break;}
1834 				}
1835 			}
1836 			if(b) {
1837 				Unit *u = getActiveUnit("h");
1838 				if(u) {
1839 					mstruct.divide(u);
1840 					mstruct.eval(evalops);
1841 				}
1842 			}
1843 		}
1844 
1845 		if(result_is_comparison && (mstruct.isComparison() || mstruct.isLogicalOr() || mstruct.isLogicalAnd())) *result_is_comparison = true;
1846 
1847 		// do not display the default angle unit in trigonometric functions
1848 		mstruct.removeDefaultAngleUnit(evalops);
1849 
1850 		// format and print
1851 		mstruct.format(printops);
1852 		mstruct.removeDefaultAngleUnit(evalops);
1853 		result = mstruct.print(printops);
1854 
1855 		// "to angle": replace "cis" with angle symbol
1856 		if(complex_angle_form) gsub(" cis ", "∠", result);
1857 	}
1858 
1859 	after_print:
1860 
1861 	if(msecs > 0) stopControl();
1862 
1863 	// restore options
1864 	if(custom_base_set) setCustomOutputBase(base_save);
1865 	priv->use_binary_prefixes = save_bin;
1866 
1867 	// output parsed value
1868 	if(parsed_expression) {
1869 		PrintOptions po_parsed;
1870 		po_parsed.preserve_format = true;
1871 		po_parsed.show_ending_zeroes = false;
1872 		po_parsed.lower_case_e = printops.lower_case_e;
1873 		po_parsed.lower_case_numbers = printops.lower_case_numbers;
1874 		po_parsed.base_display = printops.base_display;
1875 		po_parsed.twos_complement = printops.twos_complement;
1876 		po_parsed.hexadecimal_twos_complement = printops.hexadecimal_twos_complement;
1877 		po_parsed.base = evalops.parse_options.base;
1878 		Number nr_base;
1879 		if(po_parsed.base == BASE_CUSTOM && (usesIntervalArithmetic() || customInputBase().isRational()) && (customInputBase().isInteger() || !customInputBase().isNegative()) && (customInputBase() > 1 || customInputBase() < -1)) {
1880 			nr_base = customOutputBase();
1881 			setCustomOutputBase(customInputBase());
1882 		} else if(po_parsed.base == BASE_CUSTOM || (po_parsed.base < BASE_CUSTOM && !usesIntervalArithmetic() && po_parsed.base != BASE_UNICODE)) {
1883 			po_parsed.base = 10;
1884 			po_parsed.min_exp = 6;
1885 			po_parsed.use_max_decimals = true;
1886 			po_parsed.max_decimals = 5;
1887 			po_parsed.preserve_format = false;
1888 		}
1889 		po_parsed.abbreviate_names = false;
1890 		po_parsed.digit_grouping = printops.digit_grouping;
1891 		po_parsed.use_unicode_signs = printops.use_unicode_signs;
1892 		po_parsed.multiplication_sign = printops.multiplication_sign;
1893 		po_parsed.division_sign = printops.division_sign;
1894 		po_parsed.short_multiplication = false;
1895 		po_parsed.excessive_parenthesis = true;
1896 		po_parsed.improve_division_multipliers = false;
1897 		po_parsed.restrict_to_parent_precision = false;
1898 		po_parsed.spell_out_logical_operators = printops.spell_out_logical_operators;
1899 		po_parsed.interval_display = INTERVAL_DISPLAY_PLUSMINUS;
1900 		if(po_parsed.base == BASE_CUSTOM) {
1901 			setCustomOutputBase(nr_base);
1902 		}
1903 		parsed_struct.format(po_parsed);
1904 		*parsed_expression = parsed_struct.print(po_parsed);
1905 	}
1906 
1907 	printops.is_approximate = save_is_approximate;
1908 	if(po.is_approximate && (exact_comparison || !alt_results.empty())) *po.is_approximate = false;
1909 	else if(po.is_approximate && mstruct.isApproximate()) *po.is_approximate = true;
1910 
1911 	return result;
1912 }
calculate(MathStructure * mstruct,string str,int msecs,const EvaluationOptions & eo,MathStructure * parsed_struct,MathStructure * to_struct,bool make_to_division)1913 bool Calculator::calculate(MathStructure *mstruct, string str, int msecs, const EvaluationOptions &eo, MathStructure *parsed_struct, MathStructure *to_struct, bool make_to_division) {
1914 
1915 	mstruct->set(string(_("calculating...")), false, true);
1916 	b_busy = true;
1917 	if(!calculate_thread->running && !calculate_thread->start()) {mstruct->setAborted(); return false;}
1918 	bool had_msecs = msecs > 0;
1919 
1920 	// send calculation command to calculation thread
1921 	expression_to_calculate = str;
1922 	tmp_evaluationoptions = eo;
1923 	tmp_proc_command = PROC_NO_COMMAND;
1924 	tmp_rpn_mstruct = NULL;
1925 	tmp_parsedstruct = parsed_struct;
1926 	tmp_tostruct = to_struct;
1927 	tmp_maketodivision = make_to_division;
1928 	if(!calculate_thread->write(true)) {calculate_thread->cancel(); mstruct->setAborted(); return false;}
1929 	if(!calculate_thread->write((void*) mstruct)) {calculate_thread->cancel(); mstruct->setAborted(); return false;}
1930 
1931 	// check time while calculation proceeds
1932 	while(msecs > 0 && b_busy) {
1933 		sleep_ms(10);
1934 		msecs -= 10;
1935 	}
1936 	if(had_msecs && b_busy) {
1937 		if(!abort()) mstruct->setAborted();
1938 		return false;
1939 	}
1940 	return true;
1941 }
calculate(MathStructure * mstruct,int msecs,const EvaluationOptions & eo,string to_str)1942 bool Calculator::calculate(MathStructure *mstruct, int msecs, const EvaluationOptions &eo, string to_str) {
1943 
1944 	b_busy = true;
1945 	if(!calculate_thread->running && !calculate_thread->start()) {mstruct->setAborted(); return false;}
1946 	bool had_msecs = msecs > 0;
1947 
1948 	// send calculation command to calculation thread
1949 	expression_to_calculate = "";
1950 	tmp_evaluationoptions = eo;
1951 	tmp_proc_command = PROC_NO_COMMAND;
1952 	tmp_rpn_mstruct = NULL;
1953 	tmp_parsedstruct = NULL;
1954 	if(!to_str.empty()) tmp_tostruct = new MathStructure(to_str);
1955 	else tmp_tostruct = NULL;
1956 	tmp_maketodivision = false;
1957 	if(!calculate_thread->write(false)) {calculate_thread->cancel(); mstruct->setAborted(); return false;}
1958 	if(!calculate_thread->write((void*) mstruct)) {calculate_thread->cancel(); mstruct->setAborted(); return false;}
1959 
1960 	// check time while calculation proceeds
1961 	while(msecs > 0 && b_busy) {
1962 		sleep_ms(10);
1963 		msecs -= 10;
1964 	}
1965 	if(had_msecs && b_busy) {
1966 		if(!abort()) mstruct->setAborted();
1967 		return false;
1968 	}
1969 	return true;
1970 }
hasToExpression(const string & str,bool allow_empty_from) const1971 bool Calculator::hasToExpression(const string &str, bool allow_empty_from) const {
1972 	if(str.empty()) return false;
1973 	size_t i = str.rfind("->");
1974 	if(i != string::npos && (allow_empty_from || i > 0)) return true;
1975 	i = str.rfind("→");
1976 	if(i != string::npos && (allow_empty_from || i > 0)) return true;
1977 	i = str.rfind(SIGN_MINUS ">");
1978 	if(i != string::npos && (allow_empty_from || i > 0)) return true;
1979 	i = allow_empty_from ? 0 : 1;
1980 	while(true) {
1981 		// dingbat arrows
1982 		i = str.find("\xe2\x9e", i);
1983 		if(i == string::npos || i >= str.length() - 2) break;
1984 		if((unsigned char) str[i + 2] >= 0x94 && (unsigned char) str[i + 2] <= 0xbf) return true;
1985 	}
1986 	i = allow_empty_from ? 0 : 1;
1987 	size_t i2 = i;
1988 	int l = 2;
1989 	while(true) {
1990 		i2 = str.find(_("to"), i);
1991 		i = str.find("to", i);
1992 		if(i2 != string::npos && (i == string::npos || i2 < i)) {l = strlen(_("to")); i = i2;}
1993 		else l = 2;
1994 		if(i == string::npos) break;
1995 		if(((i > 0 && is_in(SPACES, str[i - 1])) || (allow_empty_from && i == 0)) && i + l < str.length() && is_in(SPACES, str[i + l])) return true;
1996 		i++;
1997 	}
1998 	return false;
1999 }
hasToExpression(const string & str,bool allow_empty_from,const EvaluationOptions & eo) const2000 bool Calculator::hasToExpression(const string &str, bool allow_empty_from, const EvaluationOptions &eo) const {
2001 	if(eo.parse_options.base == BASE_UNICODE || (eo.parse_options.base == BASE_CUSTOM && priv->custom_input_base_i > 62)) return false;
2002 	if(str.empty()) return false;
2003 	size_t i = str.rfind("->");
2004 	if(i != string::npos && (allow_empty_from || i > 0)) return true;
2005 	i = str.rfind("→");
2006 	if(i != string::npos && (allow_empty_from || i > 0)) return true;
2007 	i = str.rfind(SIGN_MINUS ">");
2008 	if(i != string::npos && (allow_empty_from || i > 0)) return true;
2009 	i = allow_empty_from ? 0 : 1;
2010 	while(true) {
2011 		// dingbat arrows
2012 		i = str.find("\xe2\x9e", i);
2013 		if(i == string::npos || i >= str.length() - 2) break;
2014 		if((unsigned char) str[i + 2] >= 148 && (unsigned char) str[i + 2] <= 191) return true;
2015 	}
2016 	i = allow_empty_from ? 0 : 1;
2017 	size_t i2 = i;
2018 	int l = 2;
2019 	while(true) {
2020 		i2 = str.find(_("to"), i);
2021 		i = str.find("to", i);
2022 		if(i2 != string::npos && (i == string::npos || i2 < i)) {l = strlen(_("to")); i = i2;}
2023 		else l = 2;
2024 		if(i == string::npos) break;
2025 		if(((i > 0 && is_in(SPACES, str[i - 1])) || (allow_empty_from && i == 0)) && i + l < str.length() && is_in(SPACES, str[i + l])) return true;
2026 		i++;
2027 	}
2028 	return false;
2029 }
separateToExpression(string & str,string & to_str,const EvaluationOptions & eo,bool keep_modifiers,bool allow_empty_from) const2030 bool Calculator::separateToExpression(string &str, string &to_str, const EvaluationOptions &eo, bool keep_modifiers, bool allow_empty_from) const {
2031 	if(eo.parse_options.base == BASE_UNICODE || (eo.parse_options.base == BASE_CUSTOM && priv->custom_input_base_i > 62)) return false;
2032 	to_str = "";
2033 	if(str.empty()) return false;
2034 	size_t i = 1, i2, l_arrow = 2;
2035 	if(allow_empty_from) i = 0;
2036 	size_t i_arrow = str.find("->", i);
2037 	i2 = str.find("→", i);
2038 	if(i2 != string::npos && i2 < i_arrow) {i_arrow = i2; l_arrow = 3;}
2039 	i2 = str.find(SIGN_MINUS ">", i);
2040 	if(i2 != string::npos && i2 < i_arrow) {i_arrow = i2; l_arrow = 4;}
2041 	while(true) {
2042 		// dingbat arrows
2043 		i = str.find("\xe2\x9e", i);
2044 		if(i == string::npos || (i_arrow != string::npos && i > i_arrow) || i >= str.length() - 2) break;
2045 		if((unsigned char) str[i + 2] >= 148 && (unsigned char) str[i + 2] <= 191) {i_arrow = i; l_arrow = 3; break;}
2046 		i += 3;
2047 	}
2048 	i = 0;
2049 	int l = 2;
2050 	while(true) {
2051 		i2 = str.find(_("to"), i);
2052 		i = str.find("to", i);
2053 		l = 2;
2054 		bool b_arrow = false;
2055 		if(i2 != string::npos && (i == string::npos || i2 < i)) {l = strlen(_("to")); i = i2;}
2056 		if(i_arrow != string::npos && (i == string::npos || i_arrow < i)) {l = l_arrow; i = i_arrow; b_arrow = true;}
2057 		if(i == string::npos) break;
2058 		if(b_arrow || (((i > 0 && is_in(SPACES, str[i - 1])) || (allow_empty_from && i == 0)) && i + l < str.length() && is_in(SPACES, str[i + l]))) {
2059 			to_str = str.substr(i + l , str.length() - i - l);
2060 			if(!b_arrow && to_str.empty()) return false;
2061 			remove_blank_ends(to_str);
2062 			if(!to_str.empty()) {
2063 				if(to_str.rfind(SIGN_MINUS, 0) == 0) {
2064 					to_str.replace(0, strlen(SIGN_MINUS), MINUS);
2065 				}
2066 				if(!keep_modifiers && (to_str[0] == '0' || to_str[0] == '?' || to_str[0] == '+' || to_str[0] == '-')) {
2067 					to_str = to_str.substr(1, str.length() - 1);
2068 					remove_blank_ends(to_str);
2069 				} else if(!keep_modifiers && to_str.length() > 1 && to_str[1] == '?' && (to_str[0] == 'b' || to_str[0] == 'a' || to_str[0] == 'd')) {
2070 					to_str = to_str.substr(2, str.length() - 2);
2071 					remove_blank_ends(to_str);
2072 				}
2073 			}
2074 			str = str.substr(0, i);
2075 			remove_blank_ends(str);
2076 			return true;
2077 		}
2078 		i++;
2079 	}
2080 	return false;
2081 }
hasWhereExpression(const string & str,const EvaluationOptions & eo) const2082 bool Calculator::hasWhereExpression(const string &str, const EvaluationOptions &eo) const {
2083 	if(eo.parse_options.base == BASE_UNICODE || (eo.parse_options.base == BASE_CUSTOM && priv->custom_input_base_i > 62)) return false;
2084 	if(str.empty()) return false;
2085 	size_t i = str.length() - 1, i2 = i;
2086 	int l = 2;
2087 	while(i != 0) {
2088 		//"where"-operator
2089 		i2 = str.rfind(_("where"), i - 1);
2090 		i = str.rfind("where", i - 1);
2091 		if(i2 != string::npos && (i == string::npos || i < i2)) {l = strlen(_("where")); i = i2;}
2092 		else l = 2;
2093 		if(i == string::npos) break;
2094 		if(i > 0 && is_in(SPACES, str[i - 1]) && i + l < str.length() && is_in(SPACES, str[i + l])) return true;
2095 	}
2096 	if((i = str.rfind("/.", str.length() - 2)) != string::npos && eo.parse_options.base >= 2 && eo.parse_options.base <= 10 && (str[i + 2] < '0' || str[i + 2] > '9')) return true;
2097 	return false;
2098 }
separateWhereExpression(string & str,string & to_str,const EvaluationOptions & eo) const2099 bool Calculator::separateWhereExpression(string &str, string &to_str, const EvaluationOptions &eo) const {
2100 	if(eo.parse_options.base == BASE_UNICODE || (eo.parse_options.base == BASE_CUSTOM && priv->custom_input_base_i > 62)) return false;
2101 	to_str = "";
2102 	size_t i = 0;
2103 	if((i = str.rfind("/.", str.length() - 2)) != string::npos && i != str.length() - 2 && eo.parse_options.base >= 2 && eo.parse_options.base <= 10 && (str[i + 2] < '0' || str[i + 2] > '9')) {
2104 		to_str = str.substr(i + 2 , str.length() - i - 2);
2105 	} else {
2106 		i = str.length() - 1;
2107 		size_t i2 = i;
2108 		int l = 5;
2109 		while(i != 0) {
2110 			i2 = str.rfind(_("where"), i - 1);
2111 			i = str.rfind("where", i - 1);
2112 			if(i2 != string::npos && (i == string::npos || i < i2)) {l = strlen(_("where")); i = i2;}
2113 			else l = 5;
2114 			if(i == string::npos) break;
2115 			if(i > 0 && is_in(SPACES, str[i - 1]) && i + l < str.length() && is_in(SPACES, str[i + l])) {
2116 				to_str = str.substr(i + l , str.length() - i - l);
2117 				break;
2118 			}
2119 		}
2120 	}
2121 	if(!to_str.empty()) {
2122 		remove_blank_ends(to_str);
2123 		str = str.substr(0, i);
2124 		parseSigns(str);
2125 		if(to_str.find("&&") == string::npos) {
2126 			int par = 0;
2127 			int bra = 0;
2128 			for(size_t i = 0; i < to_str.length(); i++) {
2129 				switch(to_str[i]) {
2130 					case '(': {par++; break;}
2131 					case ')': {if(par > 0) par--; break;}
2132 					case '[': {bra++; break;}
2133 					case ']': {if(bra > 0) bra--; break;}
2134 					case COMMA_CH: {
2135 						if(par == 0 && bra == 0) {
2136 							to_str.replace(i, 1, LOGICAL_AND);
2137 							i++;
2138 						}
2139 						break;
2140 					}
2141 					default: {}
2142 				}
2143 			}
2144 		}
2145 		return true;
2146 	}
2147 	return false;
2148 }
calculate_rand(MathStructure & mstruct,const EvaluationOptions & eo)2149 bool calculate_rand(MathStructure &mstruct, const EvaluationOptions &eo) {
2150 	if(mstruct.isFunction() && (mstruct.function()->id() == FUNCTION_ID_RAND || mstruct.function()->id() == FUNCTION_ID_RANDN || mstruct.function()->id() == FUNCTION_ID_RAND_POISSON)) {
2151 		mstruct.unformat(eo);
2152 		mstruct.calculateFunctions(eo, false);
2153 		return true;
2154 	}
2155 	bool ret = false;
2156 	for(size_t i = 0; i < mstruct.size(); i++) {
2157 		if(calculate_rand(mstruct[i], eo)) {
2158 			ret = true;
2159 			mstruct.childUpdated(i + 1);
2160 		}
2161 	}
2162 	return ret;
2163 }
calculate_ans(MathStructure & mstruct,const EvaluationOptions & eo)2164 bool calculate_ans(MathStructure &mstruct, const EvaluationOptions &eo) {
2165 	if(mstruct.isFunction() && (mstruct.function()->hasName("answer") || mstruct.function()->hasName("expression"))) {
2166 		mstruct.unformat(eo);
2167 		mstruct.calculateFunctions(eo, false);
2168 		return true;
2169 	} else if(mstruct.isVariable() && mstruct.variable()->isKnown() && (mstruct.variable()->referenceName() == "ans" || (mstruct.variable()->referenceName().length() == 4 && mstruct.variable()->referenceName().substr(0, 3) == "ans" && is_in(NUMBERS, mstruct.variable()->referenceName()[3])))) {
2170 		mstruct.set(((KnownVariable*) mstruct.variable())->get(), true);
2171 		return true;
2172 	}
2173 	bool ret = false;
2174 	for(size_t i = 0; i < mstruct.size(); i++) {
2175 		if(calculate_ans(mstruct[i], eo)) {
2176 			mstruct.childUpdated(i + 1);
2177 			ret = true;
2178 		}
2179 	}
2180 	return ret;
2181 }
handle_where_expression(MathStructure & m,MathStructure & mstruct,const EvaluationOptions & eo,vector<UnknownVariable * > & vars,vector<MathStructure> & varms,bool empty_func,bool do_eval=true)2182 bool handle_where_expression(MathStructure &m, MathStructure &mstruct, const EvaluationOptions &eo, vector<UnknownVariable*>& vars, vector<MathStructure>& varms, bool empty_func, bool do_eval = true) {
2183 	if(m.isComparison()) {
2184 		if(m.comparisonType() == COMPARISON_EQUALS) {
2185 			// x=y
2186 			if(m[0].size() > 0 && do_eval) {
2187 				// not a single variable (or empty function) on the left side of the comparison: perform calculation
2188 				MathStructure m2(m);
2189 				MathStructure xvar = m[0].find_x_var();
2190 				EvaluationOptions eo2 = eo;
2191 				eo2.isolate_x = true;
2192 				if(!xvar.isUndefined()) eo2.isolate_var = &xvar;
2193 				m2.eval(eo2);
2194 				if(m2.isComparison()) return handle_where_expression(m2, mstruct, eo, vars, varms, false, false);
2195 			}
2196 			if(m[0].isFunction() && m[1].isFunction() && (m[0].size() == 0 || (empty_func && m[0].function()->minargs() == 0)) && (m[1].size() == 0 || (empty_func && m[1].function()->minargs() == 0))) {
2197 				// if left value is a function without any arguments, do function replacement
2198 				if(!replace_function(mstruct, m[0].function(), m[1].function(), eo)) CALCULATOR->error(false, _("Original value (%s) was not found."), (m[0].function()->name() + "()").c_str(), NULL);
2199 			} else {
2200 				if(mstruct.countOccurrences(m[0]) > 1) {
2201 
2202 					// make sure that only a single random value is used
2203 					calculate_rand(m[1], eo);
2204 
2205 					if(m[1].containsInterval(true, false, false, 0, true)) {
2206 						// replace interval with variable if multiple occurrences if original value
2207 						MathStructure mv(m[1]);
2208 						replace_f_interval(mv, eo);
2209 						replace_intervals_f(mv);
2210 						if(!mstruct.replace(m[0], mv)) CALCULATOR->error(false, _("Original value (%s) was not found."), format_and_print(m[0]).c_str(), NULL);
2211 					} else {
2212 						if(!mstruct.replace(m[0], m[1])) CALCULATOR->error(false, _("Original value (%s) was not found."), format_and_print(m[0]).c_str(), NULL);
2213 					}
2214 				} else {
2215 					if(!mstruct.replace(m[0], m[1])) CALCULATOR->error(false, _("Original value (%s) was not found."), format_and_print(m[0]).c_str(), NULL);
2216 				}
2217 			}
2218 			return true;
2219 		} else if(m[0].isSymbolic() || (m[0].isVariable() && !m[0].variable()->isKnown())) {
2220 			// inequality found
2221 			// unknown variable range specification (e.g. x>0)
2222 			// right hand side value must be a non-complex number
2223 			if(!m[1].isNumber()) m[1].eval(eo);
2224 			if(m[1].isNumber() && !m[1].number().hasImaginaryPart()) {
2225 				Assumptions *ass = NULL;
2226 				// search for assumptions from previous "where" replacements
2227 				for(size_t i = 0; i < varms.size(); i++) {
2228 					if(varms[i] == m[0]) {
2229 						ass = vars[0]->assumptions();
2230 						break;
2231 					}
2232 				}
2233 				// can only handle not equals if value is zero
2234 				if((m.comparisonType() != COMPARISON_NOT_EQUALS || (!ass && m[1].isZero()))) {
2235 					if(ass) {
2236 						// change existing assumptions
2237 						if(m.comparisonType() == COMPARISON_EQUALS_GREATER) {
2238 							if(!ass->min() || (*ass->min() < m[1].number())) {
2239 								ass->setMin(&m[1].number()); ass->setIncludeEqualsMin(true);
2240 								return true;
2241 							} else if(*ass->min() >= m[1].number()) {
2242 								return true;
2243 							}
2244 						} else if(m.comparisonType() == COMPARISON_EQUALS_LESS) {
2245 							if(!ass->max() || (*ass->max() > m[1].number())) {
2246 								ass->setMax(&m[1].number()); ass->setIncludeEqualsMax(true);
2247 								return true;
2248 							} else if(*ass->max() <= m[1].number()) {
2249 								return true;
2250 							}
2251 						} else if(m.comparisonType() == COMPARISON_GREATER) {
2252 							if(!ass->min() || (ass->includeEqualsMin() && *ass->min() <= m[1].number()) || (!ass->includeEqualsMin() && *ass->min() < m[1].number())) {
2253 								ass->setMin(&m[1].number()); ass->setIncludeEqualsMin(false);
2254 								return true;
2255 							} else if((ass->includeEqualsMin() && *ass->min() > m[1].number()) || (!ass->includeEqualsMin() && *ass->min() >= m[1].number())) {
2256 								return true;
2257 							}
2258 						} else if(m.comparisonType() == COMPARISON_LESS) {
2259 							if(!ass->max() || (ass->includeEqualsMax() && *ass->max() >= m[1].number()) || (!ass->includeEqualsMax() && *ass->max() > m[1].number())) {
2260 								ass->setMax(&m[1].number()); ass->setIncludeEqualsMax(false);
2261 								return true;
2262 							} else if((ass->includeEqualsMax() && *ass->max() < m[1].number()) || (!ass->includeEqualsMax() && *ass->max() <= m[1].number())) {
2263 								return true;
2264 							}
2265 						}
2266 					} else {
2267 						// create a new unknown variable and modify the assumptions
2268 						UnknownVariable *var = new UnknownVariable("", format_and_print(m[0]));
2269 						ass = new Assumptions();
2270 						if(m[1].isZero()) {
2271 							if(m.comparisonType() == COMPARISON_EQUALS_GREATER) ass->setSign(ASSUMPTION_SIGN_NONNEGATIVE);
2272 							else if(m.comparisonType() == COMPARISON_EQUALS_LESS) ass->setSign(ASSUMPTION_SIGN_NONPOSITIVE);
2273 							else if(m.comparisonType() == COMPARISON_GREATER) ass->setSign(ASSUMPTION_SIGN_POSITIVE);
2274 							else if(m.comparisonType() == COMPARISON_LESS) ass->setSign(ASSUMPTION_SIGN_NEGATIVE);
2275 							else if(m.comparisonType() == COMPARISON_NOT_EQUALS) ass->setSign(ASSUMPTION_SIGN_NONZERO);
2276 						} else {
2277 							if(m.comparisonType() == COMPARISON_EQUALS_GREATER) {ass->setMin(&m[1].number()); ass->setIncludeEqualsMin(true);}
2278 							else if(m.comparisonType() == COMPARISON_EQUALS_LESS) {ass->setMax(&m[1].number()); ass->setIncludeEqualsMax(true);}
2279 							else if(m.comparisonType() == COMPARISON_GREATER) {ass->setMin(&m[1].number()); ass->setIncludeEqualsMin(false);}
2280 							else if(m.comparisonType() == COMPARISON_LESS) {ass->setMax(&m[1].number()); ass->setIncludeEqualsMax(false);}
2281 						}
2282 						var->setAssumptions(ass);
2283 						vars.push_back(var);
2284 						varms.push_back(m[0]);
2285 						MathStructure u_var(var);
2286 						if(!mstruct.replace(m[0], u_var)) CALCULATOR->error(false, _("Original value (%s) was not found."), format_and_print(m[0]).c_str(), NULL);
2287 						return true;
2288 					}
2289 				}
2290 			}
2291 		} else if(do_eval) {
2292 			// inequality without a single variable on the left side: calculate expression and try again
2293 			MathStructure xvar = m[0].find_x_var();
2294 			EvaluationOptions eo2 = eo;
2295 			eo2.isolate_x = true;
2296 			if(!xvar.isUndefined()) eo2.isolate_var = &xvar;
2297 			m.eval(eo2);
2298 			return handle_where_expression(m, mstruct, eo, vars, varms, false, false);
2299 		}
2300 	} else if(m.isLogicalAnd()) {
2301 		// logical and (e.g. x=2&&y=3): perform multiple "where" replacments
2302 		bool ret = true;
2303 		for(size_t i = 0; i < m.size(); i++) {
2304 			if(!handle_where_expression(m[i], mstruct, eo, vars, varms, empty_func, do_eval)) ret = false;
2305 		}
2306 		return ret;
2307 	}
2308 	CALCULATOR->error(true, _("Unhandled \"where\" expression: %s"), format_and_print(m).c_str(), NULL);
2309 	return false;
2310 }
calculate(string str,const EvaluationOptions & eo,MathStructure * parsed_struct,MathStructure * to_struct,bool make_to_division)2311 MathStructure Calculator::calculate(string str, const EvaluationOptions &eo, MathStructure *parsed_struct, MathStructure *to_struct, bool make_to_division) {
2312 
2313 	string str2, str_where;
2314 
2315 	bool provided_to = false;
2316 
2317 	// retrieve expression after " to " and remove "to ..." from expression
2318 	if(make_to_division) separateToExpression(str, str2, eo, true);
2319 
2320 	// retrieve expression after " where " (or "/.") and remove "to ..." from expression
2321 	separateWhereExpression(str, str_where, eo);
2322 
2323 	// handle to expression provided as argument
2324 	Unit *u = NULL;
2325 	if(to_struct) {
2326 		// ignore if expression contains "to" expression
2327 		if(str2.empty()) {
2328 			if(to_struct->isSymbolic() && !to_struct->symbol().empty()) {
2329 				// if to_struct is symbol, treat as "to" string
2330 				str2 = to_struct->symbol();
2331 				remove_blank_ends(str2);
2332 			} else if(to_struct->isUnit()) {
2333 				// if to_struct is unit, convert to this unit (later)
2334 				u = to_struct->unit();
2335 			}
2336 			provided_to = true;
2337 		}
2338 		to_struct->setUndefined();
2339 	}
2340 
2341 	MathStructure mstruct;
2342 	current_stage = MESSAGE_STAGE_PARSING;
2343 	size_t n_messages = messages.size();
2344 
2345 	// perform expression parsing
2346 	parse(&mstruct, str, eo.parse_options);
2347 	if(parsed_struct) {
2348 		// set parsed_struct to parsed expression with preserved formatting
2349 		beginTemporaryStopMessages();
2350 		ParseOptions po = eo.parse_options;
2351 		po.preserve_format = true;
2352 		parse(parsed_struct, str, po);
2353 		endTemporaryStopMessages();
2354 	}
2355 
2356 	// handle "where" expression
2357 	vector<UnknownVariable*> vars;
2358 	vector<MathStructure> varms;
2359 	if(!str_where.empty()) {
2360 
2361 		// parse "where" expression
2362 		MathStructure where_struct;
2363 		parse(&where_struct, str_where, eo.parse_options);
2364 
2365 		current_stage = MESSAGE_STAGE_CALCULATION;
2366 
2367 		// replace answer variables and functions in expression before performing any replacements from "where" epxression
2368 		calculate_ans(mstruct, eo);
2369 
2370 		string str_test = str_where;
2371 		remove_blanks(str_test);
2372 
2373 		// check if "where" expression includes function replacements
2374 		bool empty_func = str_test.find("()=") != string::npos;
2375 
2376 		if(mstruct.isComparison() || (mstruct.isFunction() && mstruct.function()->id() == FUNCTION_ID_SOLVE && mstruct.size() >= 1 && mstruct[0].isComparison())) {
2377 			beginTemporaryStopMessages();
2378 			MathStructure mbak(mstruct);
2379 			if(handle_where_expression(where_struct, mstruct, eo, vars, varms, empty_func)) {
2380 				endTemporaryStopMessages(true);
2381 			} else {
2382 				endTemporaryStopMessages();
2383 				mstruct = mbak;
2384 				// if where expression handling fails we can add the parsed "where" expression using logical and,
2385 				// if the original expression is an equation
2386 				if(mstruct.isComparison()) mstruct.transform(STRUCT_LOGICAL_AND, where_struct);
2387 				else {mstruct[0].transform(STRUCT_LOGICAL_AND, where_struct); mstruct.childUpdated(1);}
2388 			}
2389 		} else {
2390 			if(eo.approximation == APPROXIMATION_EXACT) {
2391 				EvaluationOptions eo2 = eo;
2392 				eo2.approximation = APPROXIMATION_TRY_EXACT;
2393 				handle_where_expression(where_struct, mstruct, eo2, vars, varms, empty_func);
2394 			} else {
2395 				handle_where_expression(where_struct, mstruct, eo, vars, varms, empty_func);
2396 			}
2397 		}
2398 	}
2399 
2400 	current_stage = MESSAGE_STAGE_CALCULATION;
2401 
2402 	// perform calculation
2403 	mstruct.eval(eo);
2404 
2405 	current_stage = MESSAGE_STAGE_UNSET;
2406 
2407 	if(!aborted()) {
2408 		// do unit conversion
2409 		bool b_units = mstruct.containsType(STRUCT_UNIT, true);
2410 		if(u) {
2411 			// convert to unit provided in to_struct
2412 			if(to_struct) to_struct->set(u);
2413 			if(b_units) {
2414 				current_stage = MESSAGE_STAGE_CONVERSION;
2415 				mstruct.set(convert(mstruct, u, eo, false, false));
2416 				if(eo.mixed_units_conversion != MIXED_UNITS_CONVERSION_NONE) mstruct.set(convertToMixedUnits(mstruct, eo));
2417 			}
2418 		} else if(!str2.empty()) {
2419 			// conversion using "to" expression
2420 			if(provided_to) {
2421 				mstruct.set(convert(mstruct, str2, eo, to_struct));
2422 			} else {
2423 				string str2b;
2424 				while(true) {
2425 					separateToExpression(str2, str2b, eo, true);
2426 					if(to_struct && !to_struct->isUndefined()) {
2427 						MathStructure mto;
2428 						mto.setUndefined();
2429 						mstruct.set(convert(mstruct, str2, eo, &mto));
2430 						if(!mto.isUndefined()) to_struct->multiply(mto, true);
2431 					} else {
2432 						mstruct.set(convert(mstruct, str2, eo, to_struct));
2433 					}
2434 					if(str2b.empty()) break;
2435 					str2 = str2b;
2436 				}
2437 			}
2438 		} else if(b_units) {
2439 			// do automatic conversion
2440 			current_stage = MESSAGE_STAGE_CONVERSION;
2441 			switch(eo.auto_post_conversion) {
2442 				case POST_CONVERSION_OPTIMAL: {
2443 					mstruct.set(convertToOptimalUnit(mstruct, eo, false));
2444 					break;
2445 				}
2446 				case POST_CONVERSION_BASE: {
2447 					mstruct.set(convertToBaseUnits(mstruct, eo));
2448 					break;
2449 				}
2450 				case POST_CONVERSION_OPTIMAL_SI: {
2451 					mstruct.set(convertToOptimalUnit(mstruct, eo, true));
2452 					break;
2453 				}
2454 				default: {}
2455 			}
2456 			if(eo.mixed_units_conversion != MIXED_UNITS_CONVERSION_NONE) mstruct.set(convertToMixedUnits(mstruct, eo));
2457 		}
2458 	}
2459 
2460 	// clean up all new messages (removes "wide interval" warning if final value does not contains any wide interval)
2461 	cleanMessages(mstruct, n_messages + 1);
2462 
2463 	current_stage = MESSAGE_STAGE_UNSET;
2464 
2465 	// replace variables generated from "where" expression
2466 	for(size_t i = 0; i < vars.size(); i++) {
2467 		mstruct.replace(vars[i], varms[i]);
2468 		vars[i]->destroy();
2469 	}
2470 
2471 	return mstruct;
2472 
2473 }
calculate(const MathStructure & mstruct_to_calculate,const EvaluationOptions & eo,string to_str)2474 MathStructure Calculator::calculate(const MathStructure &mstruct_to_calculate, const EvaluationOptions &eo, string to_str) {
2475 
2476 	remove_blank_ends(to_str);
2477 	MathStructure mstruct(mstruct_to_calculate);
2478 	current_stage = MESSAGE_STAGE_CALCULATION;
2479 	size_t n_messages = messages.size();
2480 	mstruct.eval(eo);
2481 
2482 	current_stage = MESSAGE_STAGE_CONVERSION;
2483 	if(!to_str.empty()) {
2484 		mstruct.set(convert(mstruct, to_str, eo));
2485 	} else {
2486 		switch(eo.auto_post_conversion) {
2487 			case POST_CONVERSION_OPTIMAL: {
2488 				mstruct.set(convertToOptimalUnit(mstruct, eo, false));
2489 				break;
2490 			}
2491 			case POST_CONVERSION_BASE: {
2492 				mstruct.set(convertToBaseUnits(mstruct, eo));
2493 				break;
2494 			}
2495 			case POST_CONVERSION_OPTIMAL_SI: {
2496 				mstruct.set(convertToOptimalUnit(mstruct, eo, true));
2497 				break;
2498 			}
2499 			default: {}
2500 		}
2501 		if(eo.mixed_units_conversion != MIXED_UNITS_CONVERSION_NONE) mstruct.set(convertToMixedUnits(mstruct, eo));
2502 	}
2503 
2504 	cleanMessages(mstruct, n_messages + 1);
2505 
2506 	current_stage = MESSAGE_STAGE_UNSET;
2507 	return mstruct;
2508 }
2509 
print(const MathStructure & mstruct,int msecs,const PrintOptions & po)2510 string Calculator::print(const MathStructure &mstruct, int msecs, const PrintOptions &po) {
2511 	startControl(msecs);
2512 	MathStructure mstruct2(mstruct);
2513 	mstruct2.format(po);
2514 	string print_result = mstruct2.print(po);
2515 	stopControl();
2516 	return print_result;
2517 }
printMathStructureTimeOut(const MathStructure & mstruct,int msecs,const PrintOptions & po)2518 string Calculator::printMathStructureTimeOut(const MathStructure &mstruct, int msecs, const PrintOptions &po) {
2519 	return print(mstruct, msecs, po);
2520 }
testCondition(string expression)2521 int Calculator::testCondition(string expression) {
2522 	MathStructure mstruct = calculate(expression);
2523 	if(mstruct.isNumber()) {
2524 		if(mstruct.number().isPositive()) {
2525 			return 1;
2526 		} else {
2527 			return 0;
2528 		}
2529 	}
2530 	return -1;
2531 }
2532 
startPrintControl(int milli_timeout)2533 void Calculator::startPrintControl(int milli_timeout) {
2534 	startControl(milli_timeout);
2535 }
abortPrint()2536 void Calculator::abortPrint() {
2537 	abort();
2538 }
printingAborted()2539 bool Calculator::printingAborted() {
2540 	return aborted();
2541 }
printingAbortedMessage() const2542 string Calculator::printingAbortedMessage() const {
2543 	return abortedMessage();
2544 }
timedOutString() const2545 string Calculator::timedOutString() const {
2546 	return _("timed out");
2547 }
printingControlled() const2548 bool Calculator::printingControlled() const {
2549 	return isControlled();
2550 }
stopPrintControl()2551 void Calculator::stopPrintControl() {
2552 	stopControl();
2553 }
2554 
startControl(int milli_timeout)2555 void Calculator::startControl(int milli_timeout) {
2556 	b_controlled = true;
2557 	i_aborted = 0;
2558 	i_timeout = milli_timeout;
2559 	if(i_timeout > 0) {
2560 #ifndef CLOCK_MONOTONIC
2561 		gettimeofday(&t_end, NULL);
2562 #else
2563 		struct timespec ts;
2564 		clock_gettime(CLOCK_MONOTONIC, &ts);
2565 		t_end.tv_sec = ts.tv_sec;
2566 		t_end.tv_usec = ts.tv_nsec / 1000;
2567 #endif
2568 		long int usecs = t_end.tv_usec + (long int) milli_timeout * 1000;
2569 		t_end.tv_usec = usecs % 1000000;
2570 		t_end.tv_sec += usecs / 1000000;
2571 	}
2572 }
aborted()2573 bool Calculator::aborted() {
2574 	if(!b_controlled) return false;
2575 	if(i_aborted > 0) return true;
2576 	if(i_timeout > 0) {
2577 #ifndef CLOCK_MONOTONIC
2578 		struct timeval tv;
2579 		gettimeofday(&tv, NULL);
2580 		if(tv.tv_sec > t_end.tv_sec || (tv.tv_sec == t_end.tv_sec && tv.tv_usec > t_end.tv_usec)) {
2581 #else
2582 		struct timespec tv;
2583 		clock_gettime(CLOCK_MONOTONIC, &tv);
2584 		if(tv.tv_sec > t_end.tv_sec || (tv.tv_sec == t_end.tv_sec && tv.tv_nsec / 1000 > t_end.tv_usec)) {
2585 #endif
2586 			i_aborted = 2;
2587 			return true;
2588 		}
2589 	}
2590 	return false;
2591 }
2592 string Calculator::abortedMessage() const {
2593 	if(i_aborted == 2) return _("timed out");
2594 	return _("aborted");
2595 }
2596 bool Calculator::isControlled() const {
2597 	return b_controlled;
2598 }
2599 void Calculator::stopControl() {
2600 	b_controlled = false;
2601 	i_aborted = 0;
2602 	i_timeout = 0;
2603 }
2604 
2605