21 #include "alkimia/alkvalue.h" 25 #include <QSharedData> 51 gmp_asprintf(&p,
"%Qd", val.get_mpq_t());
54 QString result = QString::fromLatin1(p);
57 void (*freefunc)(
void *, size_t);
58 mp_get_memory_functions(NULL, NULL, &freefunc);
59 (*freefunc)(p, std::strlen(p) + 1);
61 if (!result.contains(QLatin1Char(
'/'))) {
62 result += QString::fromLatin1(
"/1");
75 static QString mpzToString(
const mpz_class &val)
79 gmp_asprintf(&p,
"%Zd", val.get_mpz_t());
82 QString result(QString::fromLatin1(p));
85 __gmp_freefunc_t freefunc;
86 mp_get_memory_functions(NULL, NULL, &freefunc);
87 (*freefunc)(p, std::strlen(p) + 1);
95 QSharedDataPointer<AlkValue::Private> &AlkValue::sharedZero()
97 static QSharedDataPointer<AlkValue::Private> sharedZeroPointer(
new AlkValue::Private);
98 return sharedZeroPointer;
106 AlkValue::AlkValue(
const AlkValue &val)
111 AlkValue::AlkValue(
const int num,
const unsigned int denom)
114 d->m_val = mpq_class(num, denom);
115 d->m_val.canonicalize();
118 AlkValue::AlkValue(
const mpz_class &num,
const mpz_class &denom)
121 mpz_set(d->m_val.get_num_mpz_t(), num.get_mpz_t());
122 mpz_set(d->m_val.get_den_mpz_t(), denom.get_mpz_t());
123 d->m_val.canonicalize();
126 AlkValue::AlkValue(
const mpq_class &val)
130 d->m_val.canonicalize();
133 AlkValue::AlkValue(
const double &dAmount,
const unsigned int denom)
137 d->m_val.canonicalize();
139 *
this = convertDenominator(denom);
143 AlkValue::AlkValue(
const QString &str,
const QChar &decimalSymbol)
153 QRegExp regExp(QLatin1String(
"^((\\d+)\\s+|-)?(\\d+/\\d+)"));
156 if (regExp.indexIn(str) > -1) {
157 d->m_val = qPrintable(str.mid(regExp.pos(3)));
158 d->m_val.canonicalize();
159 const QString &part1 = regExp.cap(1);
160 if (!part1.isEmpty()) {
161 if (part1 == QLatin1String(
"-")) {
162 mpq_neg(d->m_val.get_mpq_t(), d->m_val.get_mpq_t());
164 mpq_class summand(qPrintable(part1));
165 mpq_add(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), summand.get_mpq_t());
166 d->m_val.canonicalize();
174 const QString negChars = QString::fromLatin1(
"\\-\\(\\)");
175 const QString validChars = QString::fromLatin1(
"\\d\\%1%2").arg(decimalSymbol, negChars);
176 QRegExp invCharSet(QString::fromLatin1(
"[^%1]").arg(validChars));
177 QRegExp negCharSet(QString::fromLatin1(
"[%1]").arg(negChars));
181 res.remove(invCharSet);
185 bool isNegative =
false;
186 if (res.indexOf(negCharSet) != -1) {
188 res.remove(negCharSet);
195 while (res.count(decimalSymbol) > 1) {
196 pos = res.indexOf(decimalSymbol);
201 pos = res.indexOf(decimalSymbol);
202 int len = res.length();
203 QString fraction = QString::fromLatin1(
"/1");
204 if ((pos != -1) && (pos < len)) {
205 fraction += QString(len - pos - 1, QLatin1Char(
'0'));
211 len = res.length() - 1;
212 while (res[cnt] == QLatin1Char(
'0') && cnt < len) {
223 res = QLatin1Char(
'0');
231 d->m_val = mpq_class(qPrintable(res));
232 }
catch (
const std::invalid_argument &) {
233 qWarning(
"Invalid argument '%s' to mpq_class() in AlkValue. Arguments to ctor: '%s', '%c'", qPrintable(
234 res), qPrintable(str), decimalSymbol.toLatin1());
235 d->m_val = mpq_class(0);
237 d->m_val.canonicalize();
241 d->m_val = -d->m_val;
245 AlkValue::~AlkValue()
249 QString AlkValue::toString()
const 254 double AlkValue::toDouble()
const 256 return d->m_val.get_d();
259 AlkValue AlkValue::convertDenominator(
int _denom,
const RoundingMethod how)
const 262 mpz_class in_num(mpq_numref(in.d->m_val.get_mpq_t()));
266 int sign = sgn(in_num);
271 mpz_class denom = _denom;
273 if (mpz_cmpabs(denom.get_mpz_t(), mpq_denref(d->m_val.get_mpq_t())) != 0) {
274 mpz_class in_denom(mpq_denref(in.d->m_val.get_mpq_t()));
275 mpz_class out_num, out_denom;
277 if (sgn(in_denom) == -1) {
278 in_num = in_num * (-in_denom);
287 if (sgn(denom) < 0) {
292 temp_a = ::abs(in_num);
293 temp_bc = in_denom * denom;
294 remainder = temp_a % temp_bc;
295 out_num = temp_a / temp_bc;
302 out_num = ::abs(in_num * temp.d->m_val.get_num());
303 remainder = out_num % temp.d->m_val.get_den();
304 out_num = out_num / temp.d->m_val.get_den();
308 if (remainder != 0) {
312 out_num = out_num + 1;
318 out_num = out_num + 1;
326 out_num = out_num + 1;
331 if ((2 * remainder) > (in_denom * denom)) {
332 out_num = out_num + 1;
334 }
else if ((2 * remainder) > (temp.d->m_val.get_den())) {
335 out_num = out_num + 1;
341 if ((2 * remainder) >= (in_denom * denom)) {
342 out_num = out_num + 1;
344 }
else if ((2 * remainder) >= temp.d->m_val.get_den()) {
345 out_num = out_num + 1;
351 if ((remainder * 2) > (in_denom * denom)) {
352 out_num = out_num + 1;
353 }
else if ((2 * remainder) == (in_denom * denom)) {
354 if ((out_num % 2) != 0) {
355 out_num = out_num + 1;
359 if ((remainder * 2) > temp.d->m_val.get_den()) {
360 out_num = out_num + 1;
361 }
else if ((2 * remainder) == temp.d->m_val.get_den()) {
362 if ((out_num % 2) != 0) {
363 out_num = out_num + 1;
370 qWarning(
"AlkValue: have remainder \"%s\"->convert(%d, %d)",
371 qPrintable(toString()), _denom, how);
377 out =
AlkValue(out_num * sign, out_denom);
385 AlkValue AlkValue::convertPrecision(
int prec,
const RoundingMethod how)
const 387 return convertDenominator(precisionToDenominator(prec).get_si(), how);
390 mpz_class AlkValue::denominatorToPrecision(mpz_class denom)
400 mpz_class AlkValue::precisionToDenominator(mpz_class prec)
403 while ((prec--) > 0) {
409 const AlkValue &AlkValue::canonicalize()
411 d->m_val.canonicalize();
418 mpq_add(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();
426 mpq_sub(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();
434 mpq_mul(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();
442 mpq_div(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
443 result.d->m_val.canonicalize();
447 AlkValue AlkValue::operator%(
int operand)
const 449 mpz_class num(mpq_numref(d->m_val.get_mpq_t()));
451 result.d->m_val = num % operand;
455 AlkValue AlkValue::operator*(
int factor)
const 458 mpq_class right(factor);
459 mpq_mul(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.get_mpq_t());
460 result.d->m_val.canonicalize();
470 const AlkValue &AlkValue::operator=(
int right)
473 d->m_val.canonicalize();
477 const AlkValue &AlkValue::operator=(
double right)
480 d->m_val.canonicalize();
484 const AlkValue &AlkValue::operator=(
const QString &right)
486 AlkValue other(right, QLatin1Char(
'.'));
487 d->m_val = other.d->m_val;
494 mpq_abs(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t());
495 result.d->m_val.canonicalize();
499 bool AlkValue::operator==(
const AlkValue &val)
const 504 return mpq_equal(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t());
507 bool AlkValue::operator!=(
const AlkValue &val)
const 512 return !mpq_equal(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t());
515 bool AlkValue::operator<(
const AlkValue &val)
const 517 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) < 0 ?
true :
false;
520 bool AlkValue::operator>(
const AlkValue &val)
const 522 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) > 0 ?
true :
false;
525 bool AlkValue::operator<=(
const AlkValue &val)
const 527 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) <= 0 ?
true :
false;
530 bool AlkValue::operator>=(
const AlkValue &val)
const 532 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) >= 0 ?
true :
false;
535 AlkValue AlkValue::operator-()
const 538 mpq_neg(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t());
539 result.d->m_val.canonicalize();
545 mpq_add(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
546 d->m_val.canonicalize();
552 mpq_sub(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
553 d->m_val.canonicalize();
559 mpq_mul(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
560 d->m_val.canonicalize();
566 mpq_div(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
567 d->m_val.canonicalize();
571 const mpq_class &AlkValue::valueRef()
const 576 mpq_class &AlkValue::valueRef()
Private(const Private &other)
static QString mpqToString(const mpq_class &val)