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