Changeset View
Changeset View
Standalone View
Standalone View
kmymoney/alkimia/alkvalue.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * Copyright 2010-2018 Thomas Baumgart <tbaumgart@kde.org> | ||||
3 | * | ||||
4 | * This program is free software; you can redistribute it and/or | ||||
5 | * modify it under the terms of the GNU General Public License as | ||||
6 | * published by the Free Software Foundation; either version 2 of | ||||
7 | * the License, or (at your option) any later version. | ||||
8 | * | ||||
9 | * This program is distributed in the hope that it will be useful, | ||||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
12 | * GNU General Public License for more details. | ||||
13 | * | ||||
14 | * You should have received a copy of the GNU General Public License | ||||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
16 | */ | ||||
17 | | ||||
18 | #include "alkvalue.h" | ||||
19 | | ||||
20 | #include <iostream> | ||||
21 | #include <QRegExp> | ||||
22 | #include <QSharedData> | ||||
23 | | ||||
24 | class AlkValue::Private : public QSharedData | ||||
25 | { | ||||
26 | public: | ||||
27 | Private() | ||||
28 | { | ||||
29 | } | ||||
30 | | ||||
31 | Private(const Private &other) : QSharedData(other) | ||||
32 | , m_val(other.m_val) | ||||
33 | { | ||||
34 | } | ||||
35 | | ||||
36 | mpq_class m_val; | ||||
37 | }; | ||||
38 | | ||||
39 | /** | ||||
40 | * Helper function to convert an mpq_class object into | ||||
41 | * its internal QString representation. Mainly used for | ||||
42 | * debugging. | ||||
43 | */ | ||||
44 | static QString mpqToString(const mpq_class &val) | ||||
45 | { | ||||
46 | char *p = 0; | ||||
47 | // use the gmp provided conversion routine | ||||
48 | gmp_asprintf(&p, "%Qd", val.get_mpq_t()); | ||||
49 | | ||||
50 | // convert it into a QString | ||||
51 | QString result = QString::fromLatin1(p); | ||||
52 | | ||||
53 | // and free up the resources allocated by gmp_asprintf | ||||
54 | void (*freefunc)(void *, size_t); | ||||
55 | mp_get_memory_functions(NULL, NULL, &freefunc); | ||||
56 | (*freefunc)(p, std::strlen(p) + 1); | ||||
57 | | ||||
58 | if (!result.contains(QLatin1Char('/'))) { | ||||
59 | result += QString::fromLatin1("/1"); | ||||
60 | } | ||||
61 | | ||||
62 | // done | ||||
63 | return result; | ||||
64 | } | ||||
65 | | ||||
66 | #if 0 | ||||
67 | /** | ||||
68 | * Helper function to convert an mpz_class object into | ||||
69 | * its internal QString representation. Mainly used for | ||||
70 | * debugging. | ||||
71 | */ | ||||
72 | static QString mpzToString(const mpz_class &val) | ||||
73 | { | ||||
74 | char *p = 0; | ||||
75 | // use the gmp provided conversion routine | ||||
76 | gmp_asprintf(&p, "%Zd", val.get_mpz_t()); | ||||
77 | | ||||
78 | // convert it into a QString | ||||
79 | QString result(QString::fromLatin1(p)); | ||||
80 | | ||||
81 | // and free up the resources allocated by gmp_asprintf | ||||
82 | __gmp_freefunc_t freefunc; | ||||
83 | mp_get_memory_functions(NULL, NULL, &freefunc); | ||||
84 | (*freefunc)(p, std::strlen(p) + 1); | ||||
85 | | ||||
86 | // done | ||||
87 | return result; | ||||
88 | } | ||||
89 | | ||||
90 | #endif | ||||
91 | | ||||
92 | QSharedDataPointer<AlkValue::Private> &AlkValue::sharedZero() | ||||
93 | { | ||||
94 | static QSharedDataPointer<AlkValue::Private> sharedZeroPointer(new AlkValue::Private); | ||||
95 | return sharedZeroPointer; | ||||
96 | } | ||||
97 | | ||||
98 | AlkValue::AlkValue() | ||||
99 | : d(sharedZero()) | ||||
100 | { | ||||
101 | } | ||||
102 | | ||||
103 | AlkValue::AlkValue(const AlkValue &val) | ||||
104 | : d(val.d) | ||||
105 | { | ||||
106 | } | ||||
107 | | ||||
108 | AlkValue::AlkValue(const int num, const unsigned int denom) | ||||
109 | : d(new Private) | ||||
110 | { | ||||
111 | d->m_val = mpq_class(num, denom); | ||||
112 | d->m_val.canonicalize(); | ||||
113 | } | ||||
114 | | ||||
115 | AlkValue::AlkValue(const mpz_class &num, const mpz_class &denom) | ||||
116 | : d(new Private) | ||||
117 | { | ||||
118 | mpz_set(d->m_val.get_num_mpz_t(), num.get_mpz_t()); | ||||
119 | mpz_set(d->m_val.get_den_mpz_t(), denom.get_mpz_t()); | ||||
120 | d->m_val.canonicalize(); | ||||
121 | } | ||||
122 | | ||||
123 | AlkValue::AlkValue(const mpq_class &val) | ||||
124 | : d(new Private) | ||||
125 | { | ||||
126 | d->m_val = val; | ||||
127 | d->m_val.canonicalize(); | ||||
128 | } | ||||
129 | | ||||
130 | AlkValue::AlkValue(const double &dAmount, const unsigned int denom) | ||||
131 | : d(new Private) | ||||
132 | { | ||||
133 | d->m_val = dAmount; | ||||
134 | d->m_val.canonicalize(); | ||||
135 | if (denom != 0) { | ||||
136 | *this = convertDenominator(denom); | ||||
137 | } | ||||
138 | } | ||||
139 | | ||||
140 | AlkValue::AlkValue(const QString &str, const QChar &decimalSymbol) | ||||
141 | : d(new Private) | ||||
142 | { | ||||
143 | // empty strings are easy | ||||
144 | if (str.isEmpty()) { | ||||
145 | return; | ||||
146 | } | ||||
147 | | ||||
148 | // take care of mixed prices of the form "5 8/16" as well | ||||
149 | // as own internal string representation | ||||
150 | QRegExp regExp(QLatin1String("^((\\d+)\\s+|-)?(\\d+/\\d+)")); | ||||
151 | // +-#2-+ +---#3----+ | ||||
152 | // +-----#1-----+ | ||||
153 | if (regExp.indexIn(str) > -1) { | ||||
154 | d->m_val = qPrintable(str.mid(regExp.pos(3))); | ||||
155 | d->m_val.canonicalize(); | ||||
156 | const QString &part1 = regExp.cap(1); | ||||
157 | if (!part1.isEmpty()) { | ||||
158 | if (part1 == QLatin1String("-")) { | ||||
159 | mpq_neg(d->m_val.get_mpq_t(), d->m_val.get_mpq_t()); | ||||
160 | } else { | ||||
161 | mpq_class summand(qPrintable(part1)); | ||||
162 | mpq_add(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), summand.get_mpq_t()); | ||||
163 | d->m_val.canonicalize(); | ||||
164 | } | ||||
165 | } | ||||
166 | return; | ||||
167 | } | ||||
168 | | ||||
169 | // qDebug("we got '%s' to convert", qPrintable(str)); | ||||
170 | // everything else gets down here | ||||
171 | const QString negChars = QString::fromLatin1("\\-\\(\\)"); | ||||
172 | const QString validChars = QString::fromLatin1("\\d\\%1%2").arg(decimalSymbol, negChars); | ||||
173 | QRegExp invCharSet(QString::fromLatin1("[^%1]").arg(validChars)); | ||||
174 | QRegExp negCharSet(QString::fromLatin1("[%1]").arg(negChars)); | ||||
175 | | ||||
176 | QString res(str); | ||||
177 | // get rid of any character that is not allowed. | ||||
178 | res.remove(invCharSet); | ||||
179 | | ||||
180 | // qDebug("we reduced it to '%s'", qPrintable(res)); | ||||
181 | // check if number is negative | ||||
182 | bool isNegative = false; | ||||
183 | if (res.indexOf(negCharSet) != -1) { | ||||
184 | isNegative = true; | ||||
185 | res.remove(negCharSet); | ||||
186 | } | ||||
187 | | ||||
188 | // qDebug("and modified it to '%s'", qPrintable(res)); | ||||
189 | // if someone uses the decimal symbol more than once, we get | ||||
190 | // rid of them except the right most one | ||||
191 | int pos; | ||||
192 | while (res.count(decimalSymbol) > 1) { | ||||
193 | pos = res.indexOf(decimalSymbol); | ||||
194 | res.remove(pos, 1); | ||||
195 | } | ||||
196 | | ||||
197 | // take care of any fractional part | ||||
198 | pos = res.indexOf(decimalSymbol); | ||||
199 | int len = res.length(); | ||||
200 | QString fraction = QString::fromLatin1("/1"); | ||||
201 | if ((pos != -1) && (pos < len)) { | ||||
202 | fraction += QString(len - pos - 1, QLatin1Char('0')); | ||||
203 | res.remove(pos, 1); | ||||
204 | } | ||||
205 | | ||||
206 | // check if the resulting numerator contains any leading zeros ... | ||||
207 | int cnt = 0; | ||||
208 | len = res.length() - 1; | ||||
209 | while (res[cnt] == QLatin1Char('0') && cnt < len) { | ||||
210 | ++cnt; | ||||
211 | } | ||||
212 | | ||||
213 | // ... and remove them | ||||
214 | if (cnt) { | ||||
215 | res.remove(0, cnt); | ||||
216 | } | ||||
217 | | ||||
218 | // in case the numerator is empty, we convert it to "0" | ||||
219 | if (res.isEmpty()) { | ||||
220 | res = QLatin1Char('0'); | ||||
221 | } | ||||
222 | res += fraction; | ||||
223 | | ||||
224 | // looks like we now have a pretty normalized string that we | ||||
225 | // can convert right away | ||||
226 | // qDebug("and try to convert '%s'", qPrintable(res)); | ||||
227 | try { | ||||
228 | d->m_val = mpq_class(qPrintable(res)); | ||||
229 | } catch (const std::invalid_argument &) { | ||||
230 | qWarning("Invalid argument '%s' to mpq_class() in AlkValue. Arguments to ctor: '%s', '%c'", qPrintable( | ||||
231 | res), qPrintable(str), decimalSymbol.toLatin1()); | ||||
232 | d->m_val = mpq_class(0); | ||||
233 | } | ||||
234 | d->m_val.canonicalize(); | ||||
235 | | ||||
236 | // now we make sure that we use the right sign | ||||
237 | if (isNegative) { | ||||
238 | d->m_val = -d->m_val; | ||||
239 | } | ||||
240 | } | ||||
241 | | ||||
242 | AlkValue::~AlkValue() | ||||
243 | { | ||||
244 | } | ||||
245 | | ||||
246 | QString AlkValue::toString() const | ||||
247 | { | ||||
248 | return mpqToString(d->m_val); | ||||
249 | } | ||||
250 | | ||||
251 | AlkValue AlkValue::convertDenominator(int _denom, const RoundingMethod how) const | ||||
252 | { | ||||
253 | AlkValue in(*this); | ||||
254 | mpz_class in_num(mpq_numref(in.d->m_val.get_mpq_t())); | ||||
255 | | ||||
256 | AlkValue out; // initialize to zero | ||||
257 | | ||||
258 | int sign = sgn(in_num); | ||||
259 | if (sign != 0) { | ||||
260 | // sign is either -1 for negative numbers or +1 in all other cases | ||||
261 | | ||||
262 | AlkValue temp; | ||||
263 | mpz_class denom = _denom; | ||||
264 | // only process in case the denominators are different | ||||
265 | if (mpz_cmpabs(denom.get_mpz_t(), mpq_denref(d->m_val.get_mpq_t())) != 0) { | ||||
266 | mpz_class in_denom(mpq_denref(in.d->m_val.get_mpq_t())); | ||||
267 | mpz_class out_num, out_denom; | ||||
268 | | ||||
269 | if (sgn(in_denom) == -1) { // my denom is negative | ||||
270 | in_num = in_num * (-in_denom); | ||||
271 | in_num = 1; | ||||
272 | } | ||||
273 | | ||||
274 | mpz_class remainder; | ||||
275 | int denom_neg = 0; | ||||
276 | | ||||
277 | // if the denominator is less than zero, we are to interpret it as | ||||
278 | // the reciprocal of its magnitude. | ||||
279 | if (sgn(denom) < 0) { | ||||
280 | mpz_class temp_a; | ||||
281 | mpz_class temp_bc; | ||||
282 | denom = -denom; | ||||
283 | denom_neg = 1; | ||||
284 | temp_a = ::abs(in_num); | ||||
285 | temp_bc = in_denom * denom; | ||||
286 | remainder = temp_a % temp_bc; | ||||
287 | out_num = temp_a / temp_bc; | ||||
288 | out_denom = denom; | ||||
289 | } else { | ||||
290 | temp = AlkValue(denom, in_denom); | ||||
291 | // the canonicalization required here is part of the ctor | ||||
292 | // temp.d->m_val.canonicalize(); | ||||
293 | | ||||
294 | out_num = ::abs(in_num * temp.d->m_val.get_num()); | ||||
295 | remainder = out_num % temp.d->m_val.get_den(); | ||||
296 | out_num = out_num / temp.d->m_val.get_den(); | ||||
297 | out_denom = denom; | ||||
298 | } | ||||
299 | | ||||
300 | if (remainder != 0) { | ||||
301 | switch (how) { | ||||
302 | case RoundFloor: | ||||
303 | if (sign < 0) { | ||||
304 | out_num = out_num + 1; | ||||
305 | } | ||||
306 | break; | ||||
307 | | ||||
308 | case RoundCeil: | ||||
309 | if (sign > 0) { | ||||
310 | out_num = out_num + 1; | ||||
311 | } | ||||
312 | break; | ||||
313 | | ||||
314 | case RoundTruncate: | ||||
315 | break; | ||||
316 | | ||||
317 | case RoundPromote: | ||||
318 | out_num = out_num + 1; | ||||
319 | break; | ||||
320 | | ||||
321 | case RoundHalfDown: | ||||
322 | if (denom_neg) { | ||||
323 | if ((2 * remainder) > (in_denom * denom)) { | ||||
324 | out_num = out_num + 1; | ||||
325 | } | ||||
326 | } else if ((2 * remainder) > (temp.d->m_val.get_den())) { | ||||
327 | out_num = out_num + 1; | ||||
328 | } | ||||
329 | break; | ||||
330 | | ||||
331 | case RoundHalfUp: | ||||
332 | if (denom_neg) { | ||||
333 | if ((2 * remainder) >= (in_denom * denom)) { | ||||
334 | out_num = out_num + 1; | ||||
335 | } | ||||
336 | } else if ((2 * remainder) >= temp.d->m_val.get_den()) { | ||||
337 | out_num = out_num + 1; | ||||
338 | } | ||||
339 | break; | ||||
340 | | ||||
341 | case RoundRound: | ||||
342 | if (denom_neg) { | ||||
343 | if ((remainder * 2) > (in_denom * denom)) { | ||||
344 | out_num = out_num + 1; | ||||
345 | } else if ((2 * remainder) == (in_denom * denom)) { | ||||
346 | if ((out_num % 2) != 0) { | ||||
347 | out_num = out_num + 1; | ||||
348 | } | ||||
349 | } | ||||
350 | } else { | ||||
351 | if ((remainder * 2) > temp.d->m_val.get_den()) { | ||||
352 | out_num = out_num + 1; | ||||
353 | } else if ((2 * remainder) == temp.d->m_val.get_den()) { | ||||
354 | if ((out_num % 2) != 0) { | ||||
355 | out_num = out_num + 1; | ||||
356 | } | ||||
357 | } | ||||
358 | } | ||||
359 | break; | ||||
360 | | ||||
361 | case RoundNever: | ||||
362 | qWarning("AlkValue: have remainder \"%s\"->convert(%d, %d)", | ||||
363 | qPrintable(toString()), _denom, how); | ||||
364 | break; | ||||
365 | } | ||||
366 | } | ||||
367 | | ||||
368 | // construct the new output value | ||||
369 | out = AlkValue(out_num * sign, out_denom); | ||||
370 | } else { | ||||
371 | out = *this; | ||||
372 | } | ||||
373 | } | ||||
374 | return out; | ||||
375 | } | ||||
376 | | ||||
377 | AlkValue AlkValue::convertPrecision(int prec, const RoundingMethod how) const | ||||
378 | { | ||||
379 | return convertDenominator(precisionToDenominator(prec).get_si(), how); | ||||
380 | } | ||||
381 | | ||||
382 | mpz_class AlkValue::denominatorToPrecision(mpz_class denom) | ||||
383 | { | ||||
384 | mpz_class rc = 0; | ||||
385 | while (denom > 1) { | ||||
386 | ++rc; | ||||
387 | denom /= 10; | ||||
388 | } | ||||
389 | return rc; | ||||
390 | } | ||||
391 | | ||||
392 | mpz_class AlkValue::precisionToDenominator(mpz_class prec) | ||||
393 | { | ||||
394 | mpz_class denom = 1; | ||||
395 | while ((prec--) > 0) { | ||||
396 | denom *= 10; | ||||
397 | } | ||||
398 | return denom; | ||||
399 | } | ||||
400 | | ||||
401 | const AlkValue &AlkValue::canonicalize() | ||||
402 | { | ||||
403 | d->m_val.canonicalize(); | ||||
404 | return *this; | ||||
405 | } | ||||
406 | | ||||
407 | AlkValue AlkValue::operator+(const AlkValue &right) const | ||||
408 | { | ||||
409 | AlkValue result; | ||||
410 | mpq_add(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t()); | ||||
411 | result.d->m_val.canonicalize(); | ||||
412 | return result; | ||||
413 | } | ||||
414 | | ||||
415 | AlkValue AlkValue::operator-(const AlkValue &right) const | ||||
416 | { | ||||
417 | AlkValue result; | ||||
418 | mpq_sub(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t()); | ||||
419 | result.d->m_val.canonicalize(); | ||||
420 | return result; | ||||
421 | } | ||||
422 | | ||||
423 | AlkValue AlkValue::operator*(const AlkValue &right) const | ||||
424 | { | ||||
425 | AlkValue result; | ||||
426 | mpq_mul(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t()); | ||||
427 | result.d->m_val.canonicalize(); | ||||
428 | return result; | ||||
429 | } | ||||
430 | | ||||
431 | AlkValue AlkValue::operator/(const AlkValue &right) const | ||||
432 | { | ||||
433 | AlkValue result; | ||||
434 | mpq_div(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t()); | ||||
435 | result.d->m_val.canonicalize(); | ||||
436 | return result; | ||||
437 | } | ||||
438 | | ||||
439 | AlkValue AlkValue::operator*(int factor) const | ||||
440 | { | ||||
441 | AlkValue result; | ||||
442 | mpq_class right(factor); | ||||
443 | mpq_mul(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.get_mpq_t()); | ||||
444 | result.d->m_val.canonicalize(); | ||||
445 | return result; | ||||
446 | } | ||||
447 | | ||||
448 | const AlkValue &AlkValue::operator=(const AlkValue &right) | ||||
449 | { | ||||
450 | d = right.d; | ||||
451 | return *this; | ||||
452 | } | ||||
453 | | ||||
454 | const AlkValue &AlkValue::operator=(int right) | ||||
455 | { | ||||
456 | d->m_val = right; | ||||
457 | d->m_val.canonicalize(); | ||||
458 | return *this; | ||||
459 | } | ||||
460 | | ||||
461 | const AlkValue &AlkValue::operator=(double right) | ||||
462 | { | ||||
463 | d->m_val = right; | ||||
464 | d->m_val.canonicalize(); | ||||
465 | return *this; | ||||
466 | } | ||||
467 | | ||||
468 | const AlkValue &AlkValue::operator=(const QString &right) | ||||
469 | { | ||||
470 | AlkValue other(right, QLatin1Char('.')); | ||||
471 | d->m_val = other.d->m_val; | ||||
472 | return *this; | ||||
473 | } | ||||
474 | | ||||
475 | AlkValue AlkValue::abs() const | ||||
476 | { | ||||
477 | AlkValue result; | ||||
478 | mpq_abs(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t()); | ||||
479 | result.d->m_val.canonicalize(); | ||||
480 | return result; | ||||
481 | } | ||||
482 | | ||||
483 | bool AlkValue::operator==(const AlkValue &val) const | ||||
484 | { | ||||
485 | if (d == val.d) { | ||||
486 | return true; | ||||
487 | } | ||||
488 | return mpq_equal(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()); | ||||
489 | } | ||||
490 | | ||||
491 | bool AlkValue::operator!=(const AlkValue &val) const | ||||
492 | { | ||||
493 | if (d == val.d) { | ||||
494 | return false; | ||||
495 | } | ||||
496 | return !mpq_equal(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()); | ||||
497 | } | ||||
498 | | ||||
499 | bool AlkValue::operator<(const AlkValue &val) const | ||||
500 | { | ||||
501 | return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) < 0 ? true : false; | ||||
502 | } | ||||
503 | | ||||
504 | bool AlkValue::operator>(const AlkValue &val) const | ||||
505 | { | ||||
506 | return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) > 0 ? true : false; | ||||
507 | } | ||||
508 | | ||||
509 | bool AlkValue::operator<=(const AlkValue &val) const | ||||
510 | { | ||||
511 | return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) <= 0 ? true : false; | ||||
512 | } | ||||
513 | | ||||
514 | bool AlkValue::operator>=(const AlkValue &val) const | ||||
515 | { | ||||
516 | return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) >= 0 ? true : false; | ||||
517 | } | ||||
518 | | ||||
519 | AlkValue AlkValue::operator-() const | ||||
520 | { | ||||
521 | AlkValue result; | ||||
522 | mpq_neg(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t()); | ||||
523 | result.d->m_val.canonicalize(); | ||||
524 | return result; | ||||
525 | } | ||||
526 | | ||||
527 | AlkValue &AlkValue::operator+=(const AlkValue &right) | ||||
528 | { | ||||
529 | mpq_add(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t()); | ||||
530 | d->m_val.canonicalize(); | ||||
531 | return *this; | ||||
532 | } | ||||
533 | | ||||
534 | AlkValue &AlkValue::operator-=(const AlkValue &right) | ||||
535 | { | ||||
536 | mpq_sub(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t()); | ||||
537 | d->m_val.canonicalize(); | ||||
538 | return *this; | ||||
539 | } | ||||
540 | | ||||
541 | AlkValue &AlkValue::operator*=(const AlkValue &right) | ||||
542 | { | ||||
543 | mpq_mul(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t()); | ||||
544 | d->m_val.canonicalize(); | ||||
545 | return *this; | ||||
546 | } | ||||
547 | | ||||
548 | AlkValue &AlkValue::operator/=(const AlkValue &right) | ||||
549 | { | ||||
550 | mpq_div(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t()); | ||||
551 | d->m_val.canonicalize(); | ||||
552 | return *this; | ||||
553 | } | ||||
554 | | ||||
555 | const mpq_class &AlkValue::valueRef() const | ||||
556 | { | ||||
557 | return d->m_val; | ||||
558 | } | ||||
559 | | ||||
560 | mpq_class &AlkValue::valueRef() | ||||
561 | { | ||||
562 | return d->m_val; | ||||
563 | } |