9#include "alkimia/alkvalue.h"
14#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
15#include <QRegularExpression>
40static QString mpqToString(
const mpq_class &val)
44 gmp_asprintf(&p,
"%Qd", val.get_mpq_t());
50 void (*freefunc)(
void *, size_t);
51 mp_get_memory_functions(NULL, NULL, &freefunc);
52 (*freefunc)(p, std::strlen(p) + 1);
68static QString mpzToString(
const mpz_class &val)
72 gmp_asprintf(&p,
"%Zd", val.get_mpz_t());
78 __gmp_freefunc_t freefunc;
79 mp_get_memory_functions(NULL, NULL, &freefunc);
80 (*freefunc)(p, std::strlen(p) + 1);
91 return sharedZeroPointer;
99AlkValue::AlkValue(
const AlkValue &val)
104AlkValue::AlkValue(
const int num,
const unsigned int denom)
107 d->m_val = mpq_class(num, denom);
108 d->m_val.canonicalize();
111AlkValue::AlkValue(
const mpz_class &num,
const mpz_class &denom)
114 mpz_set(d->m_val.get_num_mpz_t(), num.get_mpz_t());
115 mpz_set(d->m_val.get_den_mpz_t(), denom.get_mpz_t());
116 d->m_val.canonicalize();
119AlkValue::AlkValue(
const mpq_class &val)
123 d->m_val.canonicalize();
126AlkValue::AlkValue(
const double &dAmount,
const unsigned int denom)
130 d->m_val.canonicalize();
132 *
this = convertDenominator(denom);
136AlkValue::AlkValue(
const QString &str,
const QChar &decimalSymbol)
146#
if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
150 auto match = regExp.match(str);
151 if (
match.hasMatch()) {
152 d->m_val = qPrintable(str.mid(match.capturedStart(3)));
153 d->m_val.canonicalize();
154 const QString &part1 = match.captured(1);
156 QRegExp regExp(QLatin1String(
"^((\\d+)\\s+|-)?(\\d+/\\d+)"));
160 if (regExp.indexIn(str) > -1) {
161 d->m_val = qPrintable(str.mid(regExp.pos(3)));
162 d->m_val.canonicalize();
163 const QString &part1 = regExp.cap(1);
165 if (!part1.isEmpty()) {
166 if (part1 == QLatin1String(
"-")) {
167 mpq_neg(d->m_val.get_mpq_t(), d->m_val.get_mpq_t());
169 mpq_class summand(qPrintable(part1));
170 mpq_add(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), summand.get_mpq_t());
171 d->m_val.canonicalize();
181#
if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
191 res.remove(invCharSet);
195 bool isNegative =
false;
196 if (res.indexOf(negCharSet) != -1) {
198 res.remove(negCharSet);
205 while (res.count(decimalSymbol) > 1) {
206 pos = res.indexOf(decimalSymbol);
211 pos = res.indexOf(decimalSymbol);
212 int len = res.length();
214 if ((pos != -1) && (pos < len)) {
221 len = res.length() - 1;
222 while (res.size() > cnt && res[cnt] ==
QLatin1Char(
'0') && cnt < len) {
241 d->m_val = mpq_class(qPrintable(res));
242 }
catch (
const std::invalid_argument &) {
243 qWarning(
"Invalid argument '%s' to mpq_class() in AlkValue. Arguments to ctor: '%s', '%c'", qPrintable(
244 res), qPrintable(str), decimalSymbol.
toLatin1());
245 d->m_val = mpq_class(0);
247 d->m_val.canonicalize();
251 d->m_val = -d->m_val;
259QString AlkValue::toString()
const
261 return mpqToString(d->m_val);
264double AlkValue::toDouble()
const
266 return d->m_val.get_d();
269AlkValue AlkValue::convertDenominator(
const int _denom,
const AlkValue::RoundingMethod how)
const
271 mpz_class denom(_denom);
272 return convertDenominator(denom, how);
275AlkValue AlkValue::convertDenominator(
const mpz_class _denom,
const AlkValue::RoundingMethod how)
const
278 mpz_class in_num(mpq_numref(in.d->m_val.get_mpq_t()));
282 int sign = sgn(in_num);
287 mpz_class denom(_denom);
289 if (mpz_cmpabs(denom.get_mpz_t(), mpq_denref(d->m_val.get_mpq_t())) != 0) {
290 mpz_class in_denom(mpq_denref(in.d->m_val.get_mpq_t()));
291 mpz_class out_num, out_denom;
293 if (sgn(in_denom) == -1) {
294 in_num = in_num * (-in_denom);
303 if (sgn(denom) < 0) {
308 temp_a = ::abs(in_num);
309 temp_bc = in_denom * denom;
310 remainder = temp_a % temp_bc;
311 out_num = temp_a / temp_bc;
314 temp = AlkValue(denom, in_denom);
318 out_num = ::abs(in_num * temp.d->m_val.get_num());
319 remainder = out_num % temp.d->m_val.get_den();
320 out_num = out_num / temp.d->m_val.get_den();
324 if (remainder != 0) {
328 out_num = out_num + 1;
334 out_num = out_num + 1;
342 out_num = out_num + 1;
347 if ((2 * remainder) > (in_denom * denom)) {
348 out_num = out_num + 1;
350 }
else if ((2 * remainder) > (temp.d->m_val.get_den())) {
351 out_num = out_num + 1;
357 if ((2 * remainder) >= (in_denom * denom)) {
358 out_num = out_num + 1;
360 }
else if ((2 * remainder) >= temp.d->m_val.get_den()) {
361 out_num = out_num + 1;
367 if ((remainder * 2) > (in_denom * denom)) {
368 out_num = out_num + 1;
369 }
else if ((2 * remainder) == (in_denom * denom)) {
370 if ((out_num % 2) != 0) {
371 out_num = out_num + 1;
375 if ((remainder * 2) > temp.d->m_val.get_den()) {
376 out_num = out_num + 1;
377 }
else if ((2 * remainder) == temp.d->m_val.get_den()) {
378 if ((out_num % 2) != 0) {
379 out_num = out_num + 1;
386 qWarning(
"AlkValue: have remainder \"%s\"->convert(%s, %d)",
387 qPrintable(
toString()), denom.get_str().c_str(), how);
393 out = AlkValue(out_num * sign, out_denom);
401AlkValue AlkValue::convertPrecision(
const int prec,
const RoundingMethod how)
const
403 return convertDenominator(precisionToDenominator(prec).get_si(), how);
406mpz_class AlkValue::denominatorToPrecision(mpz_class denom)
416mpz_class AlkValue::precisionToDenominator(mpz_class prec)
419 while ((prec--) > 0) {
425const AlkValue &AlkValue::canonicalize()
427 d->m_val.canonicalize();
431AlkValue AlkValue::operator+(
const AlkValue &right)
const
434 mpq_add(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();
439AlkValue AlkValue::operator-(
const AlkValue &right)
const
442 mpq_sub(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();
447AlkValue AlkValue::operator*(
const AlkValue &right)
const
450 mpq_mul(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(),
right.d->m_val.get_mpq_t());
451 result.d->m_val.canonicalize();
455AlkValue AlkValue::operator/(
const AlkValue &right)
const
458 mpq_div(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(),
right.d->m_val.get_mpq_t());
459 result.d->m_val.canonicalize();
463AlkValue AlkValue::operator%(
int operand)
const
465 mpz_class num(mpq_numref(d->m_val.get_mpq_t()));
467 result.d->m_val = num % operand;
471AlkValue AlkValue::operator*(
int factor)
const
474 mpq_class
right(factor);
475 mpq_mul(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(),
right.get_mpq_t());
476 result.d->m_val.canonicalize();
480const AlkValue &AlkValue::operator=(
const AlkValue &right)
486const AlkValue &AlkValue::operator=(
int right)
489 d->m_val.canonicalize();
493const AlkValue &AlkValue::operator=(
double right)
496 d->m_val.canonicalize();
500const AlkValue &AlkValue::operator=(
const QString &right)
503 d->m_val = other.d->m_val;
507AlkValue AlkValue::abs()
const
510 mpq_abs(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t());
511 result.d->m_val.canonicalize();
515bool AlkValue::operator==(
const AlkValue &val)
const
520 return mpq_equal(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t());
523bool AlkValue::operator!=(
const AlkValue &val)
const
528 return !mpq_equal(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t());
531bool AlkValue::operator<(
const AlkValue &val)
const
533 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) < 0 ? true :
false;
536bool AlkValue::operator>(
const AlkValue &val)
const
538 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) > 0 ? true :
false;
541bool AlkValue::operator<=(
const AlkValue &val)
const
543 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) <= 0 ? true :
false;
546bool AlkValue::operator>=(
const AlkValue &val)
const
548 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) >= 0 ? true :
false;
551AlkValue AlkValue::operator-()
const
554 mpq_neg(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t());
555 result.d->m_val.canonicalize();
559AlkValue &AlkValue::operator+=(
const AlkValue &right)
561 mpq_add(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(),
right.d->m_val.get_mpq_t());
562 d->m_val.canonicalize();
566AlkValue &AlkValue::operator-=(
const AlkValue &right)
568 mpq_sub(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(),
right.d->m_val.get_mpq_t());
569 d->m_val.canonicalize();
573AlkValue &AlkValue::operator*=(
const AlkValue &right)
575 mpq_mul(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(),
right.d->m_val.get_mpq_t());
576 d->m_val.canonicalize();
580AlkValue &AlkValue::operator/=(
const AlkValue &right)
582 mpq_div(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(),
right.d->m_val.get_mpq_t());
583 d->m_val.canonicalize();
587const mpq_class &AlkValue::valueRef()
const
592mpq_class &AlkValue::valueRef()
char * toString(const EngineQuery &query)
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
char toLatin1() const const
QString arg(Args &&... args) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
QTextStream & right(QTextStream &stream)