1 /*
2     Qalculate (libary)
3 
4     Copyright (C) 2003-2007, 2008, 2016  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 "Unit.h"
15 #include "util.h"
16 #include "Calculator.h"
17 #include "MathStructure.h"
18 #include "MathStructure-support.h"
19 #include "Prefix.h"
20 #include "Variable.h"
21 #include "BuiltinFunctions.h"
22 
23 using std::string;
24 using std::vector;
25 using std::cout;
26 using std::endl;
27 
Unit(string cat_,string name_,string plural_,string singular_,string title_,bool is_local,bool is_builtin,bool is_active)28 Unit::Unit(string cat_, string name_, string plural_, string singular_, string title_, bool is_local, bool is_builtin, bool is_active) : ExpressionItem(cat_, "", title_, "", is_local, is_builtin, is_active) {
29 	remove_blank_ends(plural_);
30 	remove_blank_ends(singular_);
31 	if(!name_.empty()) {
32 		names.resize(1);
33 		names[0].name = name_;
34 		names[0].unicode = false;
35 		names[0].abbreviation = true;
36 		names[0].case_sensitive = true;
37 		size_t i = name_.find('_');
38 		if(i != string::npos && i > 0 && i < name_.length() - 1 && name_.find('_', i + 1) == string::npos) names[0].suffix = true;
39 		else names[0].suffix = false;
40 		names[0].avoid_input = false;
41 		names[0].reference = true;
42 		names[0].plural = false;
43 	}
44 	if(!singular_.empty()) {
45 		names.resize(names.size() + 1);
46 		names[names.size() - 1].name = singular_;
47 		names[names.size() - 1].unicode = false;
48 		names[names.size() - 1].abbreviation = false;
49 		names[names.size() - 1].case_sensitive = text_length_is_one(names[names.size() - 1].name);
50 		names[names.size() - 1].suffix = false;
51 		names[names.size() - 1].avoid_input = false;
52 		names[names.size() - 1].reference = false;
53 		names[names.size() - 1].plural = false;
54 	}
55 	if(!plural_.empty()) {
56 		names.resize(names.size() + 1);
57 		names[names.size() - 1].name = plural_;
58 		names[names.size() - 1].unicode = false;
59 		names[names.size() - 1].abbreviation = false;
60 		names[names.size() - 1].case_sensitive = text_length_is_one(names[names.size() - 1].name);
61 		names[names.size() - 1].suffix = false;
62 		names[names.size() - 1].avoid_input = false;
63 		names[names.size() - 1].reference = false;
64 		names[names.size() - 1].plural = true;
65 	}
66 	b_si = false;
67 	b_use_with_prefixes = false;
68 }
Unit()69 Unit::Unit() {
70 	b_si = false;
71 	b_use_with_prefixes = false;
72 }
Unit(const Unit * unit)73 Unit::Unit(const Unit *unit) {
74 	set(unit);
75 }
~Unit()76 Unit::~Unit() {}
copy() const77 ExpressionItem *Unit::copy() const {
78 	return new Unit(this);
79 }
set(const ExpressionItem * item)80 void Unit::set(const ExpressionItem *item) {
81 	if(item->type() == TYPE_UNIT) {
82 		b_si = ((Unit*) item)->isSIUnit();
83 		ssystem = ((Unit*) item)->system();
84 		scountries = ((Unit*) item)->countries();
85 	}
86 	ExpressionItem::set(item);
87 }
isSIUnit() const88 bool Unit::isSIUnit() const {
89 	return b_si;
90 }
setAsSIUnit()91 void Unit::setAsSIUnit() {
92 	if(!b_si) {
93 		b_si = true;
94 		b_use_with_prefixes = true;
95 		ssystem = "SI";
96 		setChanged(true);
97 	}
98 }
setSystem(string s_system)99 void Unit::setSystem(string s_system) {
100 	if(s_system != ssystem) {
101 		ssystem = s_system;
102 		if(ssystem == "SI" || ssystem == "si" || ssystem == "Si") {
103 			b_si = true;
104 			b_use_with_prefixes = true;
105 		} else {
106 			b_si = false;
107 		}
108 		setChanged(true);
109 	}
110 }
system() const111 const string &Unit::system() const {
112 	return ssystem;
113 }
useWithPrefixesByDefault() const114 bool Unit::useWithPrefixesByDefault() const {
115 	return b_use_with_prefixes;
116 }
setUseWithPrefixesByDefault(bool use_with_prefixes)117 void Unit::setUseWithPrefixesByDefault(bool use_with_prefixes) {
118 	b_use_with_prefixes = use_with_prefixes;
119 }
isCurrency() const120 bool Unit::isCurrency() const {
121 	return baseUnit() == CALCULATOR->getUnitById(UNIT_ID_EURO);
122 }
countries() const123 const string &Unit::countries() const {return scountries;}
setCountries(string country_names)124 void Unit::setCountries(string country_names) {
125 	remove_blank_ends(country_names);
126 	if(scountries != country_names) {
127 		scountries = country_names;
128 		setChanged(true);
129 	}
130 }
isUsedByOtherUnits() const131 bool Unit::isUsedByOtherUnits() const {
132 	return CALCULATOR->unitIsUsedByOtherUnits(this);
133 }
print(bool plural_,bool short_,bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const134 string Unit::print(bool plural_, bool short_, bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
135 	return preferredName(short_, use_unicode, plural_, false, can_display_unicode_string_function, can_display_unicode_string_arg).name;
136 }
plural(bool return_singular_if_no_plural,bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const137 const string &Unit::plural(bool return_singular_if_no_plural, bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
138 	const ExpressionName *ename = &preferredName(false, use_unicode, true, false, can_display_unicode_string_function, can_display_unicode_string_arg);
139 	if(!return_singular_if_no_plural && !ename->plural) return empty_string;
140 	return ename->name;
141 }
singular(bool return_abbreviation_if_no_singular,bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const142 const string &Unit::singular(bool return_abbreviation_if_no_singular, bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
143 	const ExpressionName *ename = &preferredName(false, use_unicode, false, false, can_display_unicode_string_function, can_display_unicode_string_arg);
144 	if(!return_abbreviation_if_no_singular && ename->abbreviation) return empty_string;
145 	return ename->name;
146 }
abbreviation(bool return_singular_if_no_abbreviation,bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const147 const string &Unit::abbreviation(bool return_singular_if_no_abbreviation, bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
148 	const ExpressionName *ename = &preferredName(true, use_unicode, false, false, can_display_unicode_string_function, can_display_unicode_string_arg);
149 	if(!return_singular_if_no_abbreviation && !ename->abbreviation) return empty_string;
150 	return ename->name;
151 }
baseUnit() const152 Unit* Unit::baseUnit() const {
153 	return (Unit*) this;
154 }
convertToBaseUnit(MathStructure & mvalue,MathStructure &) const155 MathStructure &Unit::convertToBaseUnit(MathStructure &mvalue, MathStructure&) const {
156 	return mvalue;
157 }
convertFromBaseUnit(MathStructure & mvalue,MathStructure &) const158 MathStructure &Unit::convertFromBaseUnit(MathStructure &mvalue, MathStructure&) const {
159 	return mvalue;
160 }
convertToBaseUnit(MathStructure & mvalue) const161 MathStructure &Unit::convertToBaseUnit(MathStructure &mvalue) const {
162 	return mvalue;
163 }
convertFromBaseUnit(MathStructure & mvalue) const164 MathStructure &Unit::convertFromBaseUnit(MathStructure &mvalue) const {
165 	return mvalue;
166 }
convertToBaseUnit() const167 MathStructure Unit::convertToBaseUnit() const {
168 	return MathStructure(1, 1);
169 }
convertFromBaseUnit() const170 MathStructure Unit::convertFromBaseUnit() const {
171 	return MathStructure(1, 1);
172 }
baseExponent(int exp) const173 int Unit::baseExponent(int exp) const {
174 	return exp;
175 }
type() const176 int Unit::type() const {
177 	return TYPE_UNIT;
178 }
subtype() const179 int Unit::subtype() const {
180 	return SUBTYPE_BASE_UNIT;
181 }
isChildOf(Unit *) const182 bool Unit::isChildOf(Unit*) const {
183 	return false;
184 }
isParentOf(Unit * u) const185 bool Unit::isParentOf(Unit *u) const {
186 	return u != this && u->baseUnit() == this;
187 }
hasNonlinearRelationTo(Unit * u) const188 bool Unit::hasNonlinearRelationTo(Unit *u) const {
189 	if(u == this) return false;
190 	Unit *ub2 = u->baseUnit();
191 	if(ub2 != this) {
192 		if(subtype() == SUBTYPE_COMPOSITE_UNIT) {
193 			const CompositeUnit *cu = (CompositeUnit*) this;
194 			for(size_t i = 1; i <= cu->countUnits(); i++) {
195 				if(cu->get(i)->hasNonlinearRelationTo(u)) {
196 					return true;
197 				}
198 			}
199 			return false;
200 		}
201 		if(ub2->subtype() == SUBTYPE_COMPOSITE_UNIT) {
202 			if(u->hasNonlinearRelationTo(ub2) && (((CompositeUnit*) ub2))->containsRelativeTo(baseUnit())) {
203 				return true;
204 			}
205 		}
206 		return false;
207 	}
208 	Unit *fbu = u;
209 	while(true) {
210 		if(fbu == this) return false;
211 		if(fbu->subtype() != SUBTYPE_ALIAS_UNIT) return false;
212 		if(((AliasUnit*) fbu)->hasNonlinearExpression()) return true;
213 		fbu = (Unit*) ((AliasUnit*) fbu)->firstBaseUnit();
214 	}
215 }
hasApproximateRelationTo(Unit * u,bool check_variables,bool ignore_high_precision_intervals) const216 bool Unit::hasApproximateRelationTo(Unit *u, bool check_variables, bool ignore_high_precision_intervals) const {
217 	if(u == this) return false;
218 	Unit *ub2 = u->baseUnit();
219 	if(ub2 != this) {
220 		if(subtype() == SUBTYPE_COMPOSITE_UNIT) {
221 			const CompositeUnit *cu = (CompositeUnit*) this;
222 			for(size_t i = 1; i <= cu->countUnits(); i++) {
223 				if(cu->get(i)->hasApproximateRelationTo(u, check_variables, ignore_high_precision_intervals)) return true;
224 			}
225 			return false;
226 		}
227 		if(ub2->subtype() == SUBTYPE_COMPOSITE_UNIT) {
228 			if((((CompositeUnit*) ub2))->containsRelativeTo(baseUnit()) && u->hasApproximateRelationTo(ub2, check_variables, ignore_high_precision_intervals)) return true;
229 		}
230 		return false;
231 	}
232 	Unit *fbu = u;
233 	while(true) {
234 		if(fbu == this) return false;
235 		if(fbu->subtype() != SUBTYPE_ALIAS_UNIT) return false;
236 		if(((AliasUnit*) fbu)->hasApproximateExpression(check_variables, ignore_high_precision_intervals)) return true;
237 		fbu = (Unit*) ((AliasUnit*) fbu)->firstBaseUnit();
238 	}
239 }
containsRelativeTo(Unit * u) const240 bool Unit::containsRelativeTo(Unit *u) const {return false;}
hasNonlinearRelationToBase() const241 bool Unit::hasNonlinearRelationToBase() const {return false;}
hasApproximateRelationToBase(bool,bool) const242 bool Unit::hasApproximateRelationToBase(bool, bool) const {return false;}
243 
convert(Unit * u,bool * converted) const244 MathStructure Unit::convert(Unit *u, bool *converted) const {
245 	MathStructure mexp(1, 1);
246 	MathStructure mvalue(1, 1);
247 	bool b = convert(u, mvalue, mexp);
248 	if(converted) *converted = b;
249 	return mvalue;
250 }
convert(Unit * u,MathStructure & mvalue) const251 bool Unit::convert(Unit *u, MathStructure &mvalue) const {
252 	MathStructure mexp(1, 1);
253 	return convert(u, mvalue, mexp);
254 }
convert(Unit * u,MathStructure & mvalue,MathStructure & mexp) const255 bool Unit::convert(Unit *u, MathStructure &mvalue, MathStructure &mexp) const {
256 	if(u == this) {
257 		return true;
258 	} else if(u->baseUnit() == baseUnit()) {
259 		u->convertToBaseUnit(mvalue, mexp);
260 		convertFromBaseUnit(mvalue, mexp);
261 		if(isCurrency() && u->isCurrency() && ((isBuiltin() && this != CALCULATOR->getUnitById(UNIT_ID_EURO)) || (u->isBuiltin() && u != CALCULATOR->getUnitById(UNIT_ID_EURO)))) {
262 			int i = 1;
263 			if(i < 4 && (u == CALCULATOR->getUnitById(UNIT_ID_BYN) || this == CALCULATOR->getUnitById(UNIT_ID_BYN))) i = (i == 3 ? 5 : 4);
264 			if(i < 2 && (u == CALCULATOR->getUnitById(UNIT_ID_BTC) || this == CALCULATOR->getUnitById(UNIT_ID_BTC))) i = 2;
265 			if(i < 5 && u->subtype() == SUBTYPE_ALIAS_UNIT) {
266 				if(i < 2 && ((AliasUnit*) u)->firstBaseUnit() == CALCULATOR->getUnitById(UNIT_ID_BTC)) i = 2;
267 				else if(i < 5 && ((AliasUnit*) u)->firstBaseUnit() != CALCULATOR->getUnitById(UNIT_ID_EURO)) i = (i == 4 ? 5 : 3);
268 				else if(i < 4 && ((AliasUnit*) u)->firstBaseUnit() == CALCULATOR->getUnitById(UNIT_ID_BYN)) i = (i == 3 ? 5 : 4);
269 			}
270 			if(i < 5 && subtype() == SUBTYPE_ALIAS_UNIT) {
271 				if(i < 2 && ((AliasUnit*) this)->firstBaseUnit() == CALCULATOR->getUnitById(UNIT_ID_BTC)) i = 2;
272 				else if(i < 5 && ((AliasUnit*) this)->firstBaseUnit() != CALCULATOR->getUnitById(UNIT_ID_EURO)) i = (i == 4 ? 5 : 3);
273 				else if(i < 4 && ((AliasUnit*) this)->firstBaseUnit() == CALCULATOR->getUnitById(UNIT_ID_BYN)) i = (i == 3 ? 5 : 4);
274 			}
275 			CALCULATOR->setExchangeRatesUsed(i);
276 		}
277 		return true;
278 	}
279 	return false;
280 }
281 
AliasUnit(string cat_,string name_,string plural_,string short_name_,string title_,Unit * alias,string relation,int exp,string inverse,bool is_local,bool is_builtin,bool is_active)282 AliasUnit::AliasUnit(string cat_, string name_, string plural_, string short_name_, string title_, Unit *alias, string relation, int exp, string inverse, bool is_local, bool is_builtin, bool is_active) : Unit(cat_, name_, plural_, short_name_, title_, is_local, is_builtin, is_active) {
283 	o_unit = (Unit*) alias;
284 	remove_blank_ends(relation);
285 	remove_blank_ends(inverse);
286 	svalue = relation;
287 	sinverse = inverse;
288 	suncertainty = "";
289 	b_relative_uncertainty = false;
290 	i_exp = exp;
291 	i_mix = 0;
292 	i_mix_min = 0;
293 }
AliasUnit()294 AliasUnit::AliasUnit() {
295 	o_unit = NULL;
296 	svalue = "";
297 	sinverse = "";
298 	suncertainty = "";
299 	b_relative_uncertainty = false;
300 	i_exp = 1;
301 	i_mix = 0;
302 	i_mix_min = 0;
303 }
AliasUnit(const AliasUnit * unit)304 AliasUnit::AliasUnit(const AliasUnit *unit) {
305 	set(unit);
306 }
~AliasUnit()307 AliasUnit::~AliasUnit() {}
copy() const308 ExpressionItem *AliasUnit::copy() const {
309 	return new AliasUnit(this);
310 }
set(const ExpressionItem * item)311 void AliasUnit::set(const ExpressionItem *item) {
312 	if(item->type() == TYPE_UNIT) {
313 		Unit::set(item);
314 		if(((Unit*) item)->subtype() == SUBTYPE_ALIAS_UNIT) {
315 			AliasUnit *u = (AliasUnit*) item;
316 			o_unit = (Unit*) u->firstBaseUnit();
317 			i_exp = u->firstBaseExponent();
318 			svalue = u->expression();
319 			sinverse = u->inverseExpression();
320 			suncertainty = u->uncertainty(&b_relative_uncertainty);
321 			i_mix = u->mixWithBase();
322 			i_mix_min = u->mixWithBaseMinimum();
323 		}
324 	} else {
325 		ExpressionItem::set(item);
326 	}
327 }
baseUnit() const328 Unit* AliasUnit::baseUnit() const {
329 	return o_unit->baseUnit();
330 }
firstBaseUnit() const331 Unit* AliasUnit::firstBaseUnit() const {
332 	return o_unit;
333 }
setBaseUnit(Unit * alias)334 void AliasUnit::setBaseUnit(Unit *alias) {
335 	o_unit = (Unit*) alias;
336 	setChanged(true);
337 }
expression() const338 string AliasUnit::expression() const {
339 	return svalue;
340 }
inverseExpression() const341 string AliasUnit::inverseExpression() const {
342 	return sinverse;
343 }
uncertainty(bool * is_relative) const344 string AliasUnit::uncertainty(bool *is_relative) const {
345 	if(is_relative) *is_relative = b_relative_uncertainty;
346 	return suncertainty;
347 }
setExpression(string relation)348 void AliasUnit::setExpression(string relation) {
349 	remove_blank_ends(relation);
350 	if(relation.empty()) {
351 		svalue = "1";
352 	} else {
353 		svalue = relation;
354 	}
355 	setChanged(true);
356 }
setInverseExpression(string inverse)357 void AliasUnit::setInverseExpression(string inverse) {
358 	remove_blank_ends(inverse);
359 	sinverse = inverse;
360 	setChanged(true);
361 }
setUncertainty(string standard_uncertainty,bool is_relative)362 void AliasUnit::setUncertainty(string standard_uncertainty, bool is_relative) {
363 	remove_blank_ends(standard_uncertainty);
364 	suncertainty = standard_uncertainty;
365 	b_relative_uncertainty = is_relative;
366 	if(!suncertainty.empty()) setApproximate(true);
367 	setChanged(true);
368 }
convertToBaseUnit(MathStructure & mvalue,MathStructure & mexp) const369 MathStructure &AliasUnit::convertToBaseUnit(MathStructure &mvalue, MathStructure &mexp) const {
370 	convertToFirstBaseUnit(mvalue, mexp);
371 	return o_unit->convertToBaseUnit(mvalue, mexp);
372 }
convertFromBaseUnit(MathStructure & mvalue,MathStructure & mexp) const373 MathStructure &AliasUnit::convertFromBaseUnit(MathStructure &mvalue, MathStructure &mexp) const {
374 	Unit *u = (Unit*) baseUnit();
375 	AliasUnit *u2;
376 	while(true) {
377 		u2 = (AliasUnit*) this;
378 		while(true) {
379 			if(u2->firstBaseUnit() == u) {
380 				break;
381 			} else {
382 				u2 = (AliasUnit*) u2->firstBaseUnit();
383 			}
384 		}
385 		u = u2;
386 		u2->convertFromFirstBaseUnit(mvalue, mexp);
387 		if(u == this) break;
388 	}
389 	return mvalue;
390 }
convertToBaseUnit(MathStructure & mvalue) const391 MathStructure &AliasUnit::convertToBaseUnit(MathStructure &mvalue) const {
392 	MathStructure mexp(1, 1);
393 	return convertToBaseUnit(mvalue, mexp);
394 }
convertFromBaseUnit(MathStructure & mvalue) const395 MathStructure &AliasUnit::convertFromBaseUnit(MathStructure &mvalue) const {
396 	MathStructure mexp(1, 1);
397 	return convertFromBaseUnit(mvalue, mexp);
398 }
convertToBaseUnit() const399 MathStructure AliasUnit::convertToBaseUnit() const {
400 	MathStructure mexp(1, 1);
401 	MathStructure mvalue(1, 1);
402 	return convertToBaseUnit(mvalue, mexp);
403 }
convertFromBaseUnit() const404 MathStructure AliasUnit::convertFromBaseUnit() const {
405 	MathStructure mexp(1, 1);
406 	MathStructure mvalue(1, 1);
407 	return convertFromBaseUnit(mvalue, mexp);
408 }
409 
baseExponent(int exp) const410 int AliasUnit::baseExponent(int exp) const {
411 	return o_unit->baseExponent(exp * i_exp);
412 }
413 
convertFromFirstBaseUnit(MathStructure & mvalue,MathStructure & mexp) const414 MathStructure &AliasUnit::convertFromFirstBaseUnit(MathStructure &mvalue, MathStructure &mexp) const {
415 	if(i_exp != 1) mexp /= i_exp;
416 	ParseOptions po;
417 	if(isApproximate() && suncertainty.empty() && precision() == -1) {
418 		if(sinverse.find(DOT) != string::npos || svalue.find(DOT) != string::npos) po.read_precision = READ_PRECISION_WHEN_DECIMALS;
419 		else po.read_precision = ALWAYS_READ_PRECISION;
420 	}
421 	if(sinverse.empty()) {
422 		if(svalue.find("\\x") != string::npos) {
423 			string stmp = svalue;
424 			string stmp2 = LEFT_PARENTHESIS ID_WRAP_LEFT;
425 			int x_id = CALCULATOR->addId(new MathStructure(mvalue), true);
426 			stmp2 += i2s(x_id);
427 			stmp2 += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
428 			gsub("\\x", stmp2, stmp);
429 			stmp2 = LEFT_PARENTHESIS ID_WRAP_LEFT;
430 			int y_id = -1;
431 			if(svalue.find("\\y") != string::npos) {
432 				stmp2 = LEFT_PARENTHESIS ID_WRAP_LEFT;
433 				y_id = CALCULATOR->addId(new MathStructure(mexp), true);
434 				stmp2 += i2s(y_id);
435 				stmp2 += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
436 				gsub("\\y", stmp2, stmp);
437 			}
438 			CALCULATOR->parse(&mvalue, stmp, po);
439 			CALCULATOR->delId(x_id);
440 			if(y_id < 0) {
441 				if(!mexp.isOne()) mvalue.raise(mexp);
442 			} else {
443 				CALCULATOR->delId(y_id);
444 			}
445 			if(precision() > 0 && (mvalue.precision() < 0 || precision() < mvalue.precision())) mvalue.setPrecision(precision(), true);
446 			if(isApproximate()) mvalue.setApproximate(true, true);
447 		} else {
448 			MathStructure *mstruct = new MathStructure();
449 			bool b_number = false;
450 			if(!suncertainty.empty()) {
451 				b_number = true;
452 			} else {
453 				size_t i = svalue.rfind(')');
454 				if(i != string::npos && i > 2 && (i == svalue.length() - 1 || (i < svalue.length() - 2 && (svalue[i + 1] == 'E' || svalue[i + 1] == 'e')))) {
455 					size_t i2 = svalue.rfind('(');
456 					if(i2 != string::npos && i2 < i - 1) {
457 						if(svalue.find_first_not_of(NUMBER_ELEMENTS SPACES, svalue[0] == '-' || svalue[0] == '+' ? 1 : 0) == i2 && svalue.find_first_not_of(NUMBERS SPACES, i2 + 1) == i && (i == svalue.length() - 1 || svalue.find_first_not_of(NUMBER_ELEMENTS SPACES, svalue[i + 2] == '-' || svalue[i + 2] == '+' ? i + 3 : i + 2) == string::npos)) {
458 							b_number = true;
459 						}
460 					}
461 				}
462 			}
463 			if(b_number) {
464 				mstruct->number().set(svalue, po);
465 				mstruct->numberUpdated();
466 			} else {
467 				CALCULATOR->parse(mstruct, svalue, po);
468 				if(mstruct->containsType(STRUCT_UNIT, false, true, true)) {
469 					mstruct->transformById(FUNCTION_ID_STRIP_UNITS);
470 				}
471 			}
472 			if(!suncertainty.empty()) {
473 				Number nr_u(suncertainty);
474 				if(mstruct->isNumber()) {
475 					if(b_relative_uncertainty) mstruct->number().setRelativeUncertainty(nr_u);
476 					else mstruct->number().setUncertainty(nr_u);
477 					mstruct->numberUpdated();
478 				} else if(mstruct->isMultiplication() && mstruct->size() > 0 && (*mstruct)[0].isNumber()) {
479 					if(b_relative_uncertainty) (*mstruct)[0].number().setRelativeUncertainty(nr_u);
480 					else (*mstruct)[0].number().setUncertainty(nr_u);
481 					(*mstruct)[0].numberUpdated();
482 					mstruct->childUpdated(1);
483 				}
484 			} else if(precision() > 0) {
485 				if(mstruct->isNumber()) {
486 					if(mstruct->number().precision() < 1 || precision() < mstruct->number().precision()) {
487 						mstruct->number().setPrecision(precision());
488 						mstruct->numberUpdated();
489 					}
490 				} else if(mstruct->isMultiplication() && mstruct->getChild(1)->isNumber()) {
491 					if(mstruct->getChild(1)->number().precision() < 0 || precision() < mstruct->getChild(1)->number().precision()) {
492 						mstruct->getChild(1)->number().setPrecision(precision());
493 						mstruct->getChild(1)->numberUpdated();
494 						mstruct->childUpdated(1);
495 					}
496 				} else if(mstruct->precision() < 0 || precision() < mstruct->precision()) {
497 					mstruct->setPrecision(precision(), true);
498 				}
499 			} else if(isApproximate() && !mstruct->isApproximate()) {
500 				mstruct->setApproximate(true, true);
501 			}
502 			if(!mexp.isOne()) mstruct->raise(mexp);
503 			mvalue.divide_nocopy(mstruct, true);
504 		}
505 	} else {
506 		if(sinverse.find("\\x") != string::npos) {
507 			string stmp = sinverse;
508 			string stmp2 = LEFT_PARENTHESIS ID_WRAP_LEFT;
509 			int x_id = CALCULATOR->addId(new MathStructure(mvalue), true);
510 			stmp2 += i2s(x_id);
511 			stmp2 += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
512 			gsub("\\x", stmp2, stmp);
513 			int y_id = -1;
514 			if(svalue.find("\\y") != string::npos) {
515 				stmp2 = LEFT_PARENTHESIS ID_WRAP_LEFT;
516 				y_id = CALCULATOR->addId(new MathStructure(mexp), true);
517 				stmp2 += i2s(y_id);
518 				stmp2 += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
519 				gsub("\\y", stmp2, stmp);
520 			}
521 			CALCULATOR->parse(&mvalue, stmp, po);
522 			CALCULATOR->delId(x_id);
523 			if(y_id < 0) {
524 				if(!mexp.isOne()) mvalue.raise(mexp);
525 			} else {
526 				CALCULATOR->delId(y_id);
527 			}
528 			if(precision() > 0 && (mvalue.precision() < 0|| precision() < mvalue.precision())) mvalue.setPrecision(precision(), true);
529 			if(isApproximate()) mvalue.setApproximate(true, true);
530 		} else {
531 			MathStructure *mstruct = new MathStructure();
532 			CALCULATOR->parse(mstruct, sinverse, po);
533 			if(precision() > 0) {
534 				if(mstruct->isNumber()) {
535 					if(mstruct->number().precision() < 0 || precision() < mstruct->number().precision()) {
536 						mstruct->number().setPrecision(precision());
537 						mstruct->numberUpdated();
538 					}
539 				} else if(mstruct->isMultiplication() && mstruct->getChild(1)->isNumber()) {
540 					if(mstruct->getChild(1)->number().precision() < 0 || precision() < mstruct->getChild(1)->number().precision()) {
541 						mstruct->getChild(1)->number().setPrecision(precision());
542 						mstruct->getChild(1)->numberUpdated();
543 						mstruct->childUpdated(1);
544 					}
545 				} else if(mstruct->precision() < 0 || precision() < mstruct->precision()) {
546 					mstruct->setPrecision(precision(), true);
547 				}
548 			} else if(isApproximate() && !mstruct->isApproximate()) {
549 				mstruct->setApproximate(true, true);
550 			}
551 			if(!mexp.isOne()) mstruct->raise(mexp);
552 			mvalue.multiply_nocopy(mstruct, true);
553 		}
554 	}
555 	return mvalue;
556 }
convertToFirstBaseUnit(MathStructure & mvalue,MathStructure & mexp) const557 MathStructure &AliasUnit::convertToFirstBaseUnit(MathStructure &mvalue, MathStructure &mexp) const {
558 	ParseOptions po;
559 	if(isApproximate() && suncertainty.empty() && precision() == -1) {
560 		if(svalue.find(DOT) != string::npos) po.read_precision = READ_PRECISION_WHEN_DECIMALS;
561 		else po.read_precision = ALWAYS_READ_PRECISION;
562 	}
563 	if(svalue.find("\\x") != string::npos) {
564 		string stmp = svalue;
565 		string stmp2 = LEFT_PARENTHESIS ID_WRAP_LEFT;
566 		int x_id = CALCULATOR->addId(new MathStructure(mvalue), true);
567 		int y_id = -1;
568 		stmp2 += i2s(x_id);
569 		stmp2 += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
570 		gsub("\\x", stmp2, stmp);
571 		if(svalue.find("\\y") != string::npos) {
572 			stmp2 = LEFT_PARENTHESIS ID_WRAP_LEFT;
573 			y_id = CALCULATOR->addId(new MathStructure(mexp), true);
574 			stmp2 += i2s(y_id);
575 			stmp2 += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
576 			gsub("\\y", stmp2, stmp);
577 		}
578 		CALCULATOR->parse(&mvalue, stmp, po);
579 		CALCULATOR->delId(x_id);
580 		if(y_id < 0) {
581 			if(!mexp.isOne()) mvalue.raise(mexp);
582 		} else {
583 			CALCULATOR->delId(y_id);
584 		}
585 		if(precision() >= 0 && (mvalue.precision() < 0 || precision() < mvalue.precision())) mvalue.setPrecision(precision(), true);
586 		if(isApproximate()) mvalue.setApproximate(true, true);
587 	} else {
588 		MathStructure *mstruct = new MathStructure();
589 		bool b_number = false;
590 		if(!suncertainty.empty()) {
591 			b_number = true;
592 		} else {
593 			size_t i = svalue.rfind(')');
594 			if(i != string::npos && i > 2 && (i == svalue.length() - 1 || (i < svalue.length() - 2 && (svalue[i + 1] == 'E' || svalue[i + 1] == 'e')))) {
595 				size_t i2 = svalue.rfind('(');
596 				if(i2 != string::npos && i2 < i - 1) {
597 					if(svalue.find_first_not_of(NUMBER_ELEMENTS SPACES, svalue[0] == '-' || svalue[0] == '+' ? 1 : 0) == i2 && svalue.find_first_not_of(NUMBERS SPACES, i2 + 1) == i && (i == svalue.length() - 1 || svalue.find_first_not_of(NUMBER_ELEMENTS SPACES, svalue[i + 2] == '-' || svalue[i + 2] == '+' ? i + 3 : i + 2) == string::npos)) {
598 						b_number = true;
599 					}
600 				}
601 			}
602 		}
603 		if(b_number) {
604 			mstruct->number().set(svalue, po);
605 			mstruct->numberUpdated();
606 		} else {
607 			CALCULATOR->parse(mstruct, svalue, po);
608 			if(mstruct->containsType(STRUCT_UNIT, false, true, true) > 0) {
609 				mstruct->transformById(FUNCTION_ID_STRIP_UNITS);
610 			}
611 		}
612 		if(!suncertainty.empty()) {
613 			Number nr_u(suncertainty);
614 			if(mstruct->isNumber()) {
615 				if(b_relative_uncertainty) mstruct->number().setRelativeUncertainty(nr_u);
616 				else mstruct->number().setUncertainty(nr_u);
617 				mstruct->numberUpdated();
618 			} else if(mstruct->isMultiplication() && mstruct->size() > 0 && (*mstruct)[0].isNumber()) {
619 				if(b_relative_uncertainty) (*mstruct)[0].number().setRelativeUncertainty(nr_u);
620 				else (*mstruct)[0].number().setUncertainty(nr_u);
621 				(*mstruct)[0].numberUpdated();
622 				mstruct->childUpdated(1);
623 			}
624 		} else if(precision() >= 0) {
625 			if(mstruct->isNumber()) {
626 				if(mstruct->number().precision() < 0 || precision() < mstruct->number().precision()) {
627 					mstruct->number().setPrecision(precision());
628 					mstruct->numberUpdated();
629 				}
630 			} else if(mstruct->isMultiplication() && mstruct->getChild(1)->isNumber()) {
631 				if(mstruct->getChild(1)->number().precision() < 0 || precision() < mstruct->getChild(1)->number().precision()) {
632 					mstruct->getChild(1)->number().setPrecision(precision());
633 					mstruct->getChild(1)->numberUpdated();
634 					mstruct->childUpdated(1);
635 				}
636 			} else if(mstruct->precision() < 0 || precision() < mstruct->precision()) {
637 				mstruct->setPrecision(precision(), true);
638 			}
639 		} else if(isApproximate() && !mstruct->isApproximate()) {
640 			mstruct->setApproximate(true, true);
641 		}
642 		if(!mexp.isOne()) mstruct->raise(mexp);
643 		mvalue.multiply_nocopy(mstruct, true);
644 	}
645 	if(i_exp != 1) mexp.multiply(i_exp);
646 	return mvalue;
647 }
setExponent(int exp)648 void AliasUnit::setExponent(int exp) {
649 	i_exp = exp;
650 	setChanged(true);
651 }
firstBaseExponent() const652 int AliasUnit::firstBaseExponent() const {
653 	return i_exp;
654 }
mixWithBase() const655 int AliasUnit::mixWithBase() const {return i_mix;}
mixWithBaseMinimum() const656 int AliasUnit::mixWithBaseMinimum() const {return i_mix_min;}
setMixWithBase(int mix_priority)657 void AliasUnit::setMixWithBase(int mix_priority) {i_mix = mix_priority;}
setMixWithBaseMinimum(int mix_minimum)658 void AliasUnit::setMixWithBaseMinimum(int mix_minimum) {i_mix_min = mix_minimum;}
subtype() const659 int AliasUnit::subtype() const {
660 	return SUBTYPE_ALIAS_UNIT;
661 }
isChildOf(Unit * u) const662 bool AliasUnit::isChildOf(Unit *u) const {
663 	if(u == this) return false;
664 	if(baseUnit() == u) return true;
665 	if(u->baseUnit() != baseUnit()) return false;
666 	Unit *u2 = (Unit*) this;
667 	while(1) {
668 		u2 = (Unit*) ((AliasUnit*) u2)->firstBaseUnit();
669 		if(u == u2) return true;
670 		if(u2->subtype() != SUBTYPE_ALIAS_UNIT) return false;
671 	}
672 	return false;
673 }
isParentOf(Unit * u) const674 bool AliasUnit::isParentOf(Unit *u) const {
675 	if(u == this) return false;
676 	if(u->baseUnit() != baseUnit()) return false;
677 	while(1) {
678 		if(u->subtype() != SUBTYPE_ALIAS_UNIT) return false;
679 		u = ((AliasUnit*) u)->firstBaseUnit();
680 		if(u == this) return true;
681 	}
682 	return false;
683 }
hasNonlinearExpression() const684 bool AliasUnit::hasNonlinearExpression() const {
685 	return svalue.find("\\x") != string::npos;
686 }
hasNonlinearRelationTo(Unit * u) const687 bool AliasUnit::hasNonlinearRelationTo(Unit *u) const {
688 	if(u == this) return false;
689 	Unit *ub = baseUnit();
690 	Unit *ub2 = u->baseUnit();
691 	if(ub2 != ub) {
692 		if(ub->subtype() == SUBTYPE_COMPOSITE_UNIT) {
693 			if(hasNonlinearRelationTo(ub)) return ((CompositeUnit*) ub)->containsRelativeTo(u);
694 			for(size_t i = 1; i <= ((CompositeUnit*) ub)->countUnits(); i++) {
695 				if(((CompositeUnit*) ub)->get(i)->hasNonlinearRelationTo(u)) return true;
696 			}
697 			return false;
698 		}
699 		if(ub2->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
700 			if(((CompositeUnit*) ub2)->containsRelativeTo(baseUnit()) && (u->hasNonlinearRelationTo(ub2) || hasNonlinearRelationTo(ub))) return true;
701 		}
702 		return false;
703 	}
704 	if(isParentOf(u)) {
705 		Unit *fbu = u;
706 		while(true) {
707 			if((const Unit*) fbu == this) return false;
708 			if(fbu->subtype() != SUBTYPE_ALIAS_UNIT) return false;
709 			if(((AliasUnit*) fbu)->hasNonlinearExpression()) return true;
710 			fbu = (Unit*) ((AliasUnit*) fbu)->firstBaseUnit();
711 		}
712 	} else if(isChildOf(u)) {
713 		Unit *fbu = (Unit*) this;
714 		while(true) {
715 			if((const Unit*) fbu == u) return false;
716 			if(fbu->subtype() != SUBTYPE_ALIAS_UNIT) return false;
717 			if(((AliasUnit*) fbu)->hasNonlinearExpression()) return true;
718 			fbu = (Unit*) ((AliasUnit*) fbu)->firstBaseUnit();
719 		}
720 	} else {
721 		return hasNonlinearRelationTo(baseUnit()) || u->hasNonlinearRelationTo(u->baseUnit());
722 	}
723 }
hasApproximateExpression(bool check_variables,bool ignore_high_precision_intervals) const724 bool AliasUnit::hasApproximateExpression(bool check_variables, bool ignore_high_precision_intervals) const {
725 	if(isApproximate()) return true;
726 	if(svalue.find_first_not_of(NUMBER_ELEMENTS EXPS) == string::npos) return false;
727 	MathStructure m(1, 1, 0), mexp(1, 1, 0);
728 	convertToFirstBaseUnit(m, mexp);
729 	return m.containsInterval(true, check_variables, false, ignore_high_precision_intervals ? 1 : 0, true);
730 }
hasApproximateRelationTo(Unit * u,bool check_variables,bool ignore_high_precision_intervals) const731 bool AliasUnit::hasApproximateRelationTo(Unit *u, bool check_variables, bool ignore_high_precision_intervals) const {
732 	if(u == this) return false;
733 	Unit *ub = baseUnit();
734 	Unit *ub2 = u->baseUnit();
735 	if(ub2 != ub) {
736 		if(ub->subtype() == SUBTYPE_COMPOSITE_UNIT) {
737 			if(((CompositeUnit*) ub)->containsRelativeTo(u) && hasApproximateRelationTo(ub, check_variables, ignore_high_precision_intervals)) return true;
738 			for(size_t i = 1; i <= ((CompositeUnit*) ub)->countUnits(); i++) {
739 				if(((CompositeUnit*) ub)->get(i)->hasApproximateRelationTo(u, check_variables, ignore_high_precision_intervals)) return true;
740 			}
741 			return false;
742 		}
743 		if(ub2->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
744 			if(((CompositeUnit*) ub2)->containsRelativeTo(baseUnit()) && (u->hasApproximateRelationTo(ub2, check_variables, ignore_high_precision_intervals) || hasApproximateRelationTo(ub, check_variables, ignore_high_precision_intervals))) return true;
745 		}
746 		return false;
747 	}
748 	if(isParentOf(u)) {
749 		Unit *fbu = u;
750 		if(fbu->subtype() != SUBTYPE_ALIAS_UNIT) return false;
751 		while(true) {
752 			if((const Unit*) fbu == this) return false;
753 			if(((AliasUnit*) fbu)->hasApproximateExpression(check_variables)) return true;
754 			if(fbu->subtype() != SUBTYPE_ALIAS_UNIT) return false;
755 			fbu = (Unit*) ((AliasUnit*) fbu)->firstBaseUnit();
756 		}
757 	} else if(isChildOf(u)) {
758 		Unit *fbu = (Unit*) this;
759 		if(fbu->subtype() != SUBTYPE_ALIAS_UNIT) return false;
760 		while(true) {
761 			if((const Unit*) fbu == u) return false;
762 			if(((AliasUnit*) fbu)->hasApproximateExpression(check_variables)) return true;
763 			if(fbu->subtype() != SUBTYPE_ALIAS_UNIT) return false;
764 			fbu = (Unit*) ((AliasUnit*) fbu)->firstBaseUnit();
765 		}
766 	} else {
767 		return hasApproximateRelationTo(baseUnit(), check_variables, ignore_high_precision_intervals) || u->hasApproximateRelationTo(u->baseUnit(), check_variables, ignore_high_precision_intervals);
768 	}
769 }
containsRelativeTo(Unit * u) const770 bool AliasUnit::containsRelativeTo(Unit *u) const {
771 	if(!u || u == this) return false;
772 	return baseUnit() == u->baseUnit() || baseUnit()->containsRelativeTo(u->baseUnit());
773 }
hasNonlinearRelationToBase() const774 bool AliasUnit::hasNonlinearRelationToBase() const {return hasNonlinearRelationTo(baseUnit()) || baseUnit()->hasNonlinearRelationToBase();}
hasApproximateRelationToBase(bool check_variables,bool ignore_high_precision_intervals) const775 bool AliasUnit::hasApproximateRelationToBase(bool check_variables, bool ignore_high_precision_intervals) const {return hasApproximateRelationTo(baseUnit(), check_variables, ignore_high_precision_intervals) || baseUnit()->hasApproximateRelationToBase(check_variables, ignore_high_precision_intervals);}
776 
AliasUnit_Composite(Unit * alias,int exp,Prefix * prefix_)777 AliasUnit_Composite::AliasUnit_Composite(Unit *alias, int exp, Prefix *prefix_) : AliasUnit("", alias->referenceName(), "", "", "", alias, "", exp, "") {
778 	prefixv = (Prefix*) prefix_;
779 }
AliasUnit_Composite(const AliasUnit_Composite * unit)780 AliasUnit_Composite::AliasUnit_Composite(const AliasUnit_Composite *unit) {
781 	set(unit);
782 }
~AliasUnit_Composite()783 AliasUnit_Composite::~AliasUnit_Composite() {}
copy() const784 ExpressionItem *AliasUnit_Composite::copy() const {
785 	return new AliasUnit_Composite(this);
786 }
set(const ExpressionItem * item)787 void AliasUnit_Composite::set(const ExpressionItem *item) {
788 	if(item->type() == TYPE_UNIT) {
789 		if(((Unit*) item)->subtype() == SUBTYPE_ALIAS_UNIT) {
790 			AliasUnit::set(item);
791 			prefixv = (Prefix*) ((AliasUnit_Composite*) item)->prefix();
792 		} else {
793 			Unit::set(item);
794 		}
795 	} else {
796 		ExpressionItem::set(item);
797 	}
798 }
print(bool plural_,bool short_,bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const799 string AliasUnit_Composite::print(bool plural_, bool short_, bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
800 	string str = "";
801 	const ExpressionName *ename = &o_unit->preferredName(short_, use_unicode, plural_, false, can_display_unicode_string_function, can_display_unicode_string_arg);
802 	if(prefixv) {
803 		str += prefixv->name(ename->abbreviation, use_unicode, can_display_unicode_string_function, can_display_unicode_string_arg);
804 	}
805 	str += ename->name;
806 	return str;
807 }
prefix() const808 Prefix *AliasUnit_Composite::prefix() const {
809 	return prefixv;
810 }
prefixExponent() const811 int AliasUnit_Composite::prefixExponent() const {
812 	if(prefixv && prefixv->type() == PREFIX_DECIMAL) return ((DecimalPrefix*) prefixv)->exponent();
813 	if(prefixv && prefixv->type() == PREFIX_BINARY) return ((BinaryPrefix*) prefixv)->exponent();
814 	return 0;
815 }
set(Unit * u,int exp,Prefix * prefix_)816 void AliasUnit_Composite::set(Unit *u, int exp, Prefix *prefix_) {
817 	setBaseUnit(u);
818 	setExponent(exp);
819 	prefixv = (Prefix*) prefix_;
820 }
convertToFirstBaseUnit(MathStructure & mvalue,MathStructure & mexp) const821 MathStructure &AliasUnit_Composite::convertToFirstBaseUnit(MathStructure &mvalue, MathStructure &mexp) const {
822 	if(prefixv) {
823 		MathStructure *mstruct = new MathStructure(prefixv->value());
824 		if(!mexp.isOne()) mstruct->raise(mexp);
825 		mvalue.multiply_nocopy(mstruct, true);
826 	}
827 	if(i_exp != 1) mexp.multiply(i_exp);
828 	return mvalue;
829 }
convertFromFirstBaseUnit(MathStructure & mvalue,MathStructure & mexp) const830 MathStructure &AliasUnit_Composite::convertFromFirstBaseUnit(MathStructure &mvalue, MathStructure &mexp) const {
831 	if(i_exp != 1) mexp /= i_exp;
832 	if(prefixv) {
833 		MathStructure *mstruct = new MathStructure(prefixv->value());
834 		if(!mexp.isOne()) mstruct->raise(mexp);
835 		mvalue.divide_nocopy(mstruct, true);
836 	}
837 	return mvalue;
838 }
839 
CompositeUnit(string cat_,string name_,string title_,string base_expression_,bool is_local,bool is_builtin,bool is_active)840 CompositeUnit::CompositeUnit(string cat_, string name_, string title_, string base_expression_, bool is_local, bool is_builtin, bool is_active) : Unit(cat_, name_, "", "", title_, is_local, is_builtin, is_active) {
841 	setBaseExpression(base_expression_);
842 	setChanged(false);
843 }
CompositeUnit(const CompositeUnit * unit)844 CompositeUnit::CompositeUnit(const CompositeUnit *unit) {
845 	set(unit);
846 }
~CompositeUnit()847 CompositeUnit::~CompositeUnit() {
848 	clear();
849 }
copy() const850 ExpressionItem *CompositeUnit::copy() const {
851 	return new CompositeUnit(this);
852 }
set(const ExpressionItem * item)853 void CompositeUnit::set(const ExpressionItem *item) {
854 	if(item->type() == TYPE_UNIT) {
855 		Unit::set(item);
856 		if(((Unit*) item)->subtype() == SUBTYPE_COMPOSITE_UNIT) {
857 			CompositeUnit *cu = (CompositeUnit*) item;
858 			for(size_t i = 1; i <= cu->countUnits(); i++) {
859 				int exp = 1; Prefix *p = NULL;
860 				Unit *u = cu->get(i, &exp, &p);
861 				units.push_back(new AliasUnit_Composite(u, exp, p));
862 			}
863 		}
864 	} else {
865 		ExpressionItem::set(item);
866 	}
867 }
add(Unit * u,int exp,Prefix * prefix)868 void CompositeUnit::add(Unit *u, int exp, Prefix *prefix) {
869 	bool b = false;
870 	for(size_t i = 0; i < units.size(); i++) {
871 		if(exp > units[i]->firstBaseExponent()) {
872 			units.insert(units.begin() + i, new AliasUnit_Composite(u, exp, prefix));
873 			b = true;
874 			break;
875 		}
876 	}
877 	if(!b) {
878 		units.push_back(new AliasUnit_Composite(u, exp, prefix));
879 	}
880 }
get(size_t index,int * exp,Prefix ** prefix) const881 Unit *CompositeUnit::get(size_t index, int *exp, Prefix **prefix) const {
882 	if(index > 0 && index <= units.size()) {
883 		if(exp) *exp = units[index - 1]->firstBaseExponent();
884 		if(prefix) *prefix = (Prefix*) units[index - 1]->prefix();
885 		return (Unit*) units[index - 1]->firstBaseUnit();
886 	}
887 	return NULL;
888 }
setExponent(size_t index,int exp)889 void CompositeUnit::setExponent(size_t index, int exp) {
890 	if(index > 0 && index <= units.size()) {
891 		bool b = exp > units[index - 1]->firstBaseExponent();
892 		units[index - 1]->setExponent(exp);
893 		if(b) {
894 			for(size_t i = 0; i < index - 1; i++) {
895 				if(exp > units[i]->firstBaseExponent()) {
896 					AliasUnit_Composite *u = units[index - 1];
897 					units.erase(units.begin() + (index - 1));
898 					units.insert(units.begin() + i, u);
899 					break;
900 				}
901 			}
902 		} else {
903 			for(size_t i = units.size() - 1; i > index - 1; i--) {
904 				if(exp < units[i]->firstBaseExponent()) {
905 					AliasUnit_Composite *u = units[index - 1];
906 					units.insert(units.begin() + i, u);
907 					units.erase(units.begin() + (index - 1));
908 					break;
909 				}
910 			}
911 		}
912 	}
913 }
setPrefix(size_t index,Prefix * prefix)914 void CompositeUnit::setPrefix(size_t index, Prefix *prefix) {
915 	if(index > 0 && index <= units.size()) {
916 		units[index - 1]->set(units[index - 1]->firstBaseUnit(), units[index - 1]->firstBaseExponent(), prefix);
917 	}
918 }
countUnits() const919 size_t CompositeUnit::countUnits() const {
920 	return units.size();
921 }
find(Unit * u) const922 size_t CompositeUnit::find(Unit *u) const {
923 	for(size_t i = 0; i < units.size(); i++) {
924 		if(units[i]->firstBaseUnit() == u) {
925 			return i + 1;
926 		}
927 	}
928 	return 0;
929 }
del(size_t index)930 void CompositeUnit::del(size_t index) {
931 	if(index > 0 && index <= units.size()) {
932 		delete units[index - 1];
933 		units.erase(units.begin() + (index - 1));
934 	}
935 }
print(bool plural_,bool short_,bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const936 string CompositeUnit::print(bool plural_, bool short_, bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
937 	string str = "";
938 	bool b = false, b2 = false;
939 	for(size_t i = 0; i < units.size(); i++) {
940 		if(units[i]->firstBaseExponent() != 0) {
941 			if(!b && units[i]->firstBaseExponent() < 0 && i > 0) {
942 				str += "/";
943 				b = true;
944 				if(i < units.size() - 1) {
945 					b2 = true;
946 					str += "(";
947 				}
948 			} else {
949 				if(i > 0) {
950 					if(use_unicode && (!can_display_unicode_string_function || (*can_display_unicode_string_function) (SIGN_MIDDLEDOT, can_display_unicode_string_arg))) str += SIGN_MIDDLEDOT;
951 					else str += " ";
952 				}
953 			}
954 			if(plural_ && i == 0 && units[i]->firstBaseExponent() > 0) {
955 				str += units[i]->print(true, short_, use_unicode, can_display_unicode_string_function, can_display_unicode_string_arg);
956 			} else {
957 				str += units[i]->print(false, short_, use_unicode, can_display_unicode_string_function, can_display_unicode_string_arg);
958 			}
959 			if(short_ && use_unicode && units[i]->firstBaseExponent() != (b ? -1 : 1) && str.length() >= 2 && str[str.length() - 1] == -80 && str[str.length() - 2] == -62) {
960 				str.erase(str.length() - 2, 2);
961 				str += units[i]->print(plural_ && i == 0 && units[i]->firstBaseExponent() > 0, short_, false, can_display_unicode_string_function, can_display_unicode_string_arg);
962 			}
963 			if(b) {
964 				if(units[i]->firstBaseExponent() != -1) {
965 					if(use_unicode && units[i]->firstBaseExponent() == -2 && (!can_display_unicode_string_function || (*can_display_unicode_string_function) (SIGN_POWER_2, can_display_unicode_string_arg))) str += SIGN_POWER_2;
966 					else if(use_unicode && units[i]->firstBaseExponent() == -3 && (!can_display_unicode_string_function || (*can_display_unicode_string_function) (SIGN_POWER_3, can_display_unicode_string_arg))) str += SIGN_POWER_3;
967 					else {
968 						str += "^";
969 						str += i2s(-units[i]->firstBaseExponent());
970 					}
971 				}
972 			} else {
973 				if(units[i]->firstBaseExponent() != 1) {
974 					if(use_unicode && units[i]->firstBaseExponent() == 2 && (!can_display_unicode_string_function || (*can_display_unicode_string_function) (SIGN_POWER_2, can_display_unicode_string_arg))) str += SIGN_POWER_2;
975 					else if(use_unicode && units[i]->firstBaseExponent() == 3 && (!can_display_unicode_string_function || (*can_display_unicode_string_function) (SIGN_POWER_3, can_display_unicode_string_arg))) str += SIGN_POWER_3;
976 					else {
977 						str += "^";
978 						if(units[i]->firstBaseExponent() < 0 && (!can_display_unicode_string_function || (*can_display_unicode_string_function) (SIGN_MINUS, can_display_unicode_string_arg))) {
979 							str += SIGN_MINUS;
980 							str += i2s(-units[i]->firstBaseExponent());
981 						} else {
982 							str += i2s(units[i]->firstBaseExponent());
983 						}
984 					}
985 				}
986 			}
987 		}
988 	}
989 	if(b2) str += ")";
990 	return str;
991 }
subtype() const992 int CompositeUnit::subtype() const {
993 	return SUBTYPE_COMPOSITE_UNIT;
994 }
containsRelativeTo(Unit * u) const995 bool CompositeUnit::containsRelativeTo(Unit *u) const {
996 	if(!u || u == this) return false;
997 	CompositeUnit *cu;
998 	for(size_t i = 0; i < units.size(); i++) {
999 		if(u == units[i] || u->baseUnit() == units[i]->baseUnit()) return true;
1000 		if(units[i]->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
1001 			cu = (CompositeUnit*) units[i]->baseUnit();
1002 			if(cu->containsRelativeTo(u)) return true;
1003 		}
1004 	}
1005 	if(u->baseUnit()->subtype() == SUBTYPE_COMPOSITE_UNIT) {
1006 		cu = (CompositeUnit*) u->baseUnit();
1007 		for(size_t i = 1; i <= cu->countUnits(); i++) {
1008 			if(containsRelativeTo(cu->get(i)->baseUnit())) return true;
1009 		}
1010 		return false;
1011 	}
1012 	return false;
1013 }
hasNonlinearRelationToBase() const1014 bool CompositeUnit::hasNonlinearRelationToBase() const {
1015 	for(size_t i = 0; i < units.size(); i++) {
1016 		if(units[i]->hasNonlinearRelationToBase()) return true;
1017 	}
1018 	return false;
1019 }
hasApproximateRelationToBase(bool check_variables,bool ignore_high_precision_intervals) const1020 bool CompositeUnit::hasApproximateRelationToBase(bool check_variables, bool ignore_high_precision_intervals) const {
1021 	for(size_t i = 0; i < units.size(); i++) {
1022 		if(units[i]->hasApproximateRelationToBase(check_variables, ignore_high_precision_intervals)) return true;
1023 	}
1024 	return false;
1025 }
generateMathStructure(bool make_division,bool set_null_prefixes) const1026 MathStructure CompositeUnit::generateMathStructure(bool make_division, bool set_null_prefixes) const {
1027 	MathStructure mstruct;
1028 	bool has_p = set_null_prefixes;
1029 	if(!set_null_prefixes) {
1030 		for(size_t i = 0; i < units.size(); i++) {
1031 			if(units[i]->prefix()) {
1032 				has_p = true;
1033 				break;
1034 			}
1035 		}
1036 	}
1037 	MathStructure mden;
1038 	for(size_t i = 0; i < units.size(); i++) {
1039 		MathStructure mstruct2;
1040 		if(!has_p || units[i]->prefix()) {
1041 			mstruct2.set(units[i]->firstBaseUnit(), units[i]->prefix());
1042 		} else {
1043 			mstruct2.set(units[i]->firstBaseUnit(), CALCULATOR->getDecimalNullPrefix());
1044 		}
1045 		if(make_division && units[i]->firstBaseExponent() < 0) {
1046 			if(units[i]->firstBaseExponent() != -1) {
1047 				mstruct2 ^= -units[i]->firstBaseExponent();
1048 			}
1049 		} else if(units[i]->firstBaseExponent() != 1) {
1050 			mstruct2 ^= units[i]->firstBaseExponent();
1051 		}
1052 		if(i == 0) {
1053 			if(make_division && units[i]->firstBaseExponent() < 0) {
1054 				mstruct = 1;
1055 				mden = mstruct2;
1056 			} else {
1057 				mstruct = mstruct2;
1058 			}
1059 		} else if(make_division && units[i]->firstBaseExponent() < 0) {
1060 			if(mden.isZero()) {
1061 				mden = mstruct2;
1062 			} else {
1063 				mden.multiply(mstruct2, true);
1064 			}
1065 		} else {
1066 			mstruct.multiply(mstruct2, true);
1067 		}
1068 	}
1069 	if(make_division && !mden.isZero()) {
1070 		mstruct.transform(STRUCT_DIVISION, mden);
1071 	}
1072 	return mstruct;
1073 }
remove_times_one(MathStructure & m)1074 void remove_times_one(MathStructure &m) {
1075 	if(m.isMultiplication() && m.size() >= 2) {
1076 		for(size_t i = 0; i < m.size();) {
1077 			remove_times_one(m[i]);
1078 			if(m[i].isOne()) {
1079 				m.delChild(i + 1);
1080 				if(m.size() == 1) {
1081 					m.setToChild(1, true);
1082 					break;
1083 				}
1084 			} else {
1085 				i++;
1086 			}
1087 		}
1088 	} else {
1089 		for(size_t i = 0; i < m.size(); i++) {
1090 			remove_times_one(m[i]);
1091 		}
1092 	}
1093 }
fix_division(MathStructure & m,const EvaluationOptions & eo)1094 bool fix_division(MathStructure &m, const EvaluationOptions &eo) {
1095 	bool b_ret = false;
1096 	for(size_t i = 0; i < m.size(); i++) {
1097 		if(fix_division(m[i], eo)) {
1098 			m.childUpdated(i + 1);
1099 			b_ret = true;
1100 		}
1101 	}
1102 	if(m.isPower() && !m[0].isUnit()) {
1103 		if(m.calculatesub(eo, eo, false)) b_ret = true;
1104 	}
1105 	return b_ret;
1106 }
replace_variables(MathStructure & m)1107 bool replace_variables(MathStructure &m) {
1108 	bool b_ret = false;
1109 	for(size_t i = 0; i < m.size(); i++) {
1110 		if(replace_variables(m[i])) {
1111 			m.childUpdated(i + 1);
1112 			b_ret = true;
1113 		}
1114 	}
1115 	if(m.isVariable() && m.variable()->isKnown()) {
1116 		Unit *u = CALCULATOR->getActiveUnit(m.variable()->referenceName() + "_unit");
1117 		if(!u) {
1118 			if(m.variable()->referenceName() == "bohr_radius") u = CALCULATOR->getActiveUnit("bohr_unit");
1119 			else if(m.variable()->referenceName() == "elementary_charge") u = CALCULATOR->getActiveUnit("e_unit");
1120 			else if(m.variable()->referenceName() == "electron_mass") u = CALCULATOR->getActiveUnit("electron_unit");
1121 		}
1122 		if(u) {
1123 			m.set(u, true);
1124 			b_ret = true;
1125 		}
1126 	}
1127 	return b_ret;
1128 }
setBaseExpression(string base_expression_)1129 void CompositeUnit::setBaseExpression(string base_expression_) {
1130 	clear();
1131 	if(base_expression_.empty()) {
1132 		setChanged(true);
1133 		return;
1134 	}
1135 	EvaluationOptions eo;
1136 	eo.approximation = APPROXIMATION_EXACT;
1137 	eo.sync_units = false;
1138 	eo.keep_prefixes = true;
1139 	eo.structuring = STRUCTURING_NONE;
1140 	eo.reduce_divisions = false;
1141 	eo.do_polynomial_division = false;
1142 	eo.isolate_x = false;
1143 	ParseOptions po;
1144 	po.variables_enabled = true;
1145 	po.functions_enabled = false;
1146 	po.unknowns_enabled = true;
1147 	MathStructure mstruct;
1148 	bool had_errors = false;
1149 	CALCULATOR->beginTemporaryStopMessages();
1150 	CALCULATOR->parse(&mstruct, base_expression_, po);
1151 	replace_variables(mstruct);
1152 	if(mstruct.containsType(STRUCT_VARIABLE, true)) {
1153 		po.variables_enabled = false;
1154 		CALCULATOR->parse(&mstruct, base_expression_, po);
1155 	}
1156 	remove_times_one(mstruct);
1157 	fix_division(mstruct, eo);
1158 	bool b_eval = !is_unit_multiexp(mstruct);
1159 	while(true) {
1160 		if(b_eval) mstruct.eval(eo);
1161 		if(mstruct.isUnit()) {
1162 			add(mstruct.unit(), 1, mstruct.prefix());
1163 		} else if(mstruct.isPower() && mstruct[0].isUnit() && mstruct[1].isInteger()) {
1164 			add(mstruct[0].unit(), mstruct[1].number().intValue(), mstruct[0].prefix());
1165 		} else if(mstruct.isMultiplication()) {
1166 			for(size_t i = 0; i < mstruct.size(); i++) {
1167 				if(mstruct[i].isUnit()) {
1168 					add(mstruct[i].unit(), 1, mstruct[i].prefix());
1169 				} else if(mstruct[i].isPower() && mstruct[i][0].isUnit() && mstruct[i][1].isInteger()) {
1170 					add(mstruct[i][0].unit(), mstruct[i][1].number().intValue(), mstruct[i][0].prefix());
1171 				} else if(mstruct[i].isMultiplication()) {
1172 					for(size_t i2 = 0; i2 < mstruct.size(); i2++) {
1173 						if(mstruct[i][i2].isUnit()) {
1174 							add(mstruct[i][i2].unit(), 1, mstruct[i][i2].prefix());
1175 						} else if(mstruct[i][i2].isPower() && mstruct[i][i2][0].isUnit() && mstruct[i][i2][1].isInteger()) {
1176 							add(mstruct[i][i2][0].unit(), mstruct[i][i2][1].number().intValue(), mstruct[i][i2][0].prefix());
1177 						} else {
1178 							had_errors = true;
1179 						}
1180 					}
1181 				} else {
1182 					had_errors = true;
1183 				}
1184 			}
1185 		} else {
1186 			had_errors = true;
1187 		}
1188 		if(had_errors && !b_eval) {
1189 			had_errors = false;
1190 			b_eval = true;
1191 			clear();
1192 		} else {
1193 			break;
1194 		}
1195 	}
1196 	if(CALCULATOR->endTemporaryStopMessages() > 0) had_errors = true;
1197 	if(had_errors) CALCULATOR->error(false, _("Error(s) in unitexpression."), NULL);
1198 	setChanged(true);
1199 }
clear()1200 void CompositeUnit::clear() {
1201 	for(size_t i = 0; i < units.size(); i++) {
1202 		delete units[i];
1203 	}
1204 	units.clear();
1205 }
1206