25 #include <QSharedData> 44 gmp_asprintf(&p,
"%Qd", val.get_mpq_t());
47 QString result = QString::fromLatin1(p);
50 void (*freefunc) (
void *, size_t);
51 mp_get_memory_functions(NULL, NULL, &freefunc);
52 (*freefunc)(p, std::strlen(p) + 1);
54 if (!result.contains(QLatin1Char(
'/'))) {
55 result += QString::fromLatin1(
"/1");
68 static QString mpzToString(
const mpz_class & val)
72 gmp_asprintf(&p,
"%Zd", val.get_mpz_t());
75 QString result(QString::fromLatin1(p));
78 __gmp_freefunc_t freefunc;
79 mp_get_memory_functions(NULL, NULL, &freefunc);
80 (*freefunc)(p, std::strlen(p) + 1);
87 QSharedDataPointer<AlkValue::Private>& AlkValue::sharedZero()
89 static QSharedDataPointer<AlkValue::Private> sharedZeroPointer(
new AlkValue::Private);
90 return sharedZeroPointer;
93 AlkValue::AlkValue() :
98 AlkValue::AlkValue(
const AlkValue &val) :
103 AlkValue::AlkValue(
const int num,
const unsigned int denom) :
106 d->m_val = mpq_class(num, denom);
107 d->m_val.canonicalize();
110 AlkValue::AlkValue(
const mpz_class &num,
const mpz_class &denom) :
113 mpz_set(d->m_val.get_num_mpz_t(), num.get_mpz_t());
114 mpz_set(d->m_val.get_den_mpz_t(), denom.get_mpz_t());
115 d->m_val.canonicalize();
118 AlkValue::AlkValue(
const mpq_class &val) :
122 d->m_val.canonicalize();
125 AlkValue::AlkValue(
const double &dAmount,
const unsigned int denom) :
129 d->m_val.canonicalize();
131 *
this = convertDenominator(denom);
135 AlkValue::AlkValue(
const QString & str,
const QChar & decimalSymbol) :
145 QRegExp regExp(QLatin1String(
"^((\\d+)\\s+|-)?(\\d+/\\d+)"));
148 if (regExp.indexIn(str) > -1) {
149 d->m_val = qPrintable(str.mid(regExp.pos(3)));
150 d->m_val.canonicalize();
151 const QString &part1 = regExp.cap(1);
152 if (!part1.isEmpty()) {
153 if (part1 == QLatin1String(
"-")) {
154 mpq_neg(d->m_val.get_mpq_t(), d->m_val.get_mpq_t());
157 mpq_class summand(qPrintable(part1));
158 mpq_add(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), summand.get_mpq_t());
159 d->m_val.canonicalize();
167 const QString negChars = QString::fromLatin1(
"\\-\\(\\)");
168 const QString validChars = QString::fromLatin1(
"\\d\\%1%2").arg(decimalSymbol, negChars);
169 QRegExp invCharSet(QString::fromLatin1(
"[^%1]").arg(validChars));
170 QRegExp negCharSet(QString::fromLatin1(
"[%1]").arg(negChars));
174 res.remove(invCharSet);
178 bool isNegative =
false;
179 if (res.indexOf(negCharSet) != -1) {
181 res.remove(negCharSet);
188 while (res.count(decimalSymbol) > 1) {
189 pos = res.indexOf(decimalSymbol);
194 pos = res.indexOf(decimalSymbol);
195 int len = res.length();
196 QString fraction = QString::fromLatin1(
"/1");
197 if ((pos != -1) && (pos < len)) {
198 fraction += QString(len - pos - 1, QLatin1Char(
'0'));
204 len = res.length() - 1;
205 while (res[cnt] == QLatin1Char(
'0') && cnt < len) {
216 res = QLatin1Char(
'0');
224 d->m_val = mpq_class(qPrintable(res));
225 }
catch (
const std::invalid_argument &) {
226 qWarning(
"Invalid argument '%s' to mpq_class() in AlkValue. Arguments to ctor: '%s', '%c'", qPrintable(res), qPrintable(str), decimalSymbol.toLatin1());
227 d->m_val = mpq_class(0);
229 d->m_val.canonicalize();
233 d->m_val = -d->m_val;
237 AlkValue::~AlkValue()
241 QString AlkValue::toString()
const 246 AlkValue AlkValue::convertDenominator(
int _denom,
const RoundingMethod how)
const 249 mpz_class in_num(mpq_numref(in.d->m_val.get_mpq_t()));
253 int sign = sgn(in_num);
258 mpz_class denom = _denom;
260 if (mpz_cmpabs(denom.get_mpz_t(), mpq_denref(d->m_val.get_mpq_t())) != 0) {
261 mpz_class in_denom(mpq_denref(in.d->m_val.get_mpq_t()));
262 mpz_class out_num, out_denom;
264 if (sgn(in_denom) == -1) {
265 in_num = in_num * (- in_denom);
274 if (sgn(denom) < 0) {
279 temp_a = ::abs(in_num);
280 temp_bc = in_denom * denom;
281 remainder = temp_a % temp_bc;
282 out_num = temp_a / temp_bc;
289 out_num = ::abs(in_num * temp.d->m_val.get_num());
290 remainder = out_num % temp.d->m_val.get_den();
291 out_num = out_num / temp.d->m_val.get_den();
295 if (remainder != 0) {
299 out_num = out_num + 1;
305 out_num = out_num + 1;
313 out_num = out_num + 1;
318 if ((2 * remainder) > (in_denom * denom)) {
319 out_num = out_num + 1;
321 }
else if ((2 * remainder) > (temp.d->m_val.get_den())) {
322 out_num = out_num + 1;
328 if ((2 * remainder) >= (in_denom * denom)) {
329 out_num = out_num + 1;
331 }
else if ((2 * remainder) >= temp.d->m_val.get_den()) {
332 out_num = out_num + 1;
338 if ((remainder * 2) > (in_denom * denom)) {
339 out_num = out_num + 1;
340 }
else if ((2 * remainder) == (in_denom * denom)) {
341 if ((out_num % 2) != 0) {
342 out_num = out_num + 1;
346 if ((remainder * 2) > temp.d->m_val.get_den()) {
347 out_num = out_num + 1;
348 }
else if ((2 * remainder) == temp.d->m_val.get_den()) {
349 if ((out_num % 2) != 0) {
350 out_num = out_num + 1;
357 qWarning(
"AlkValue: have remainder \"%s\"->convert(%d, %d)",
358 qPrintable(toString()), _denom, how);
364 out =
AlkValue(out_num * sign, out_denom);
373 AlkValue AlkValue::convertPrecision(
int prec,
const RoundingMethod how)
const 375 return convertDenominator(precisionToDenominator(prec).get_si(), how);
378 mpz_class AlkValue::denominatorToPrecision(mpz_class denom)
388 mpz_class AlkValue::precisionToDenominator(mpz_class prec)
391 while ((prec--) > 0) {
397 const AlkValue & AlkValue::canonicalize()
399 d->m_val.canonicalize();
406 mpq_add(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
407 result.d->m_val.canonicalize();
414 mpq_sub(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
415 result.d->m_val.canonicalize();
422 mpq_mul(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
423 result.d->m_val.canonicalize();
430 mpq_div(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
431 result.d->m_val.canonicalize();
435 AlkValue AlkValue::operator*(
int factor)
const 438 mpq_class right(factor);
439 mpq_mul(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.get_mpq_t());
440 result.d->m_val.canonicalize();
450 const AlkValue & AlkValue::operator=(
int right)
453 d->m_val.canonicalize();
457 const AlkValue & AlkValue::operator=(
double right)
460 d->m_val.canonicalize();
464 const AlkValue & AlkValue::operator=(
const QString & right)
466 AlkValue other(right, QLatin1Char(
'.'));
467 d->m_val = other.d->m_val;
474 mpq_abs(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t());
475 result.d->m_val.canonicalize();
479 bool AlkValue::operator==(
const AlkValue &val)
const 483 return mpq_equal(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t());
486 bool AlkValue::operator!=(
const AlkValue &val)
const 490 return !mpq_equal(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t());
493 bool AlkValue::operator<(
const AlkValue &val)
const 495 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) < 0 ?
true :
false;
498 bool AlkValue::operator>(
const AlkValue &val)
const 500 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) > 0 ?
true :
false;
503 bool AlkValue::operator<=(
const AlkValue &val)
const 505 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) <= 0 ?
true :
false;
508 bool AlkValue::operator>=(
const AlkValue &val)
const 510 return mpq_cmp(d->m_val.get_mpq_t(), val.d->m_val.get_mpq_t()) >= 0 ?
true :
false;
513 AlkValue AlkValue::operator-()
const 516 mpq_neg(result.d->m_val.get_mpq_t(), d->m_val.get_mpq_t());
517 result.d->m_val.canonicalize();
523 mpq_add(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
524 d->m_val.canonicalize();
530 mpq_sub(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
531 d->m_val.canonicalize();
537 mpq_mul(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
538 d->m_val.canonicalize();
544 mpq_div(d->m_val.get_mpq_t(), d->m_val.get_mpq_t(), right.d->m_val.get_mpq_t());
545 d->m_val.canonicalize();
549 const mpq_class & AlkValue::valueRef()
const 554 mpq_class & AlkValue::valueRef()
Private(const Private &other)
static QString mpqToString(const mpq_class &val)