File indexing completed on 2024-05-12 17:21:05

0001 // SPDX-FileCopyrightText: 2001-2013 Evan Teran <evan.teran@gmail.com>
0002 // SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 #include <config-kcalc.h>
0005 #include "knumber_integer.h"
0006 #include "knumber_float.h"
0007 #include "knumber_fraction.h"
0008 #include "knumber_error.h"
0009 #include <QScopedArrayPointer>
0010 
0011 namespace detail {
0012 
0013 bool knumber_fraction::default_fractional_input              = false;
0014 bool knumber_fraction::default_fractional_output             = true;
0015 bool knumber_fraction::split_off_integer_for_fraction_output = false;
0016 
0017 //------------------------------------------------------------------------------
0018 // Name:
0019 //------------------------------------------------------------------------------
0020 void knumber_fraction::set_default_fractional_input(bool value) {
0021     default_fractional_input = value;
0022 }
0023 
0024 //------------------------------------------------------------------------------
0025 // Name:
0026 //------------------------------------------------------------------------------
0027 void knumber_fraction::set_default_fractional_output(bool value) {
0028     default_fractional_output = value;
0029 }
0030 
0031 //------------------------------------------------------------------------------
0032 // Name:
0033 //------------------------------------------------------------------------------
0034 void knumber_fraction::set_split_off_integer_for_fraction_output(bool value) {
0035     split_off_integer_for_fraction_output = value;
0036 }
0037 
0038 //------------------------------------------------------------------------------
0039 // Name:
0040 //------------------------------------------------------------------------------
0041 knumber_fraction::knumber_fraction(const QString &s) {
0042     mpq_init(mpq_);
0043         mpq_set_str(mpq_, s.toLatin1().constData(), 10);
0044     mpq_canonicalize(mpq_);
0045 }
0046 
0047 //------------------------------------------------------------------------------
0048 // Name:
0049 //------------------------------------------------------------------------------
0050 knumber_fraction::knumber_fraction(qint64 num, quint64 den) {
0051     mpq_init(mpq_);
0052     mpq_set_si(mpq_, num, den);
0053     mpq_canonicalize(mpq_);
0054 }
0055 
0056 //------------------------------------------------------------------------------
0057 // Name:
0058 //------------------------------------------------------------------------------
0059 knumber_fraction::knumber_fraction(quint64 num, quint64 den) {
0060     mpq_init(mpq_);
0061     mpq_set_ui(mpq_, num, den);
0062     mpq_canonicalize(mpq_);
0063 }
0064 
0065 //------------------------------------------------------------------------------
0066 // Name:
0067 //------------------------------------------------------------------------------
0068 knumber_fraction::knumber_fraction(mpq_t mpq) {
0069     mpq_init(mpq_);
0070     mpq_set(mpq_, mpq);
0071 }
0072 
0073 //------------------------------------------------------------------------------
0074 // Name:
0075 //------------------------------------------------------------------------------
0076 knumber_fraction::knumber_fraction(const knumber_fraction *value) {
0077     mpq_init(mpq_);
0078     mpq_set(mpq_, value->mpq_);
0079 }
0080 
0081 //------------------------------------------------------------------------------
0082 // Name:
0083 //------------------------------------------------------------------------------
0084 knumber_fraction::knumber_fraction(const knumber_integer *value) {
0085     mpq_init(mpq_);
0086     mpq_set_z(mpq_, value->mpz_);
0087 }
0088 
0089 #if 0
0090 //------------------------------------------------------------------------------
0091 // Name:
0092 //------------------------------------------------------------------------------
0093 knumber_fraction::knumber_fraction(const knumber_float *value) {
0094     mpq_init(mpq_);
0095     mpq_set_f(mpq_, value->mpf_);
0096 }
0097 #endif
0098 
0099 //------------------------------------------------------------------------------
0100 // Name:
0101 //------------------------------------------------------------------------------
0102 knumber_base *knumber_fraction::clone() {
0103     return new knumber_fraction(this);
0104 }
0105 
0106 //------------------------------------------------------------------------------
0107 // Name:
0108 //------------------------------------------------------------------------------
0109 knumber_fraction::~knumber_fraction() {
0110     mpq_clear(mpq_);
0111 }
0112 
0113 //------------------------------------------------------------------------------
0114 // Name:
0115 //------------------------------------------------------------------------------
0116 bool knumber_fraction::is_integer() const {
0117     return (mpz_cmp_ui(mpq_denref(mpq_), 1) == 0);
0118 }
0119 
0120 //------------------------------------------------------------------------------
0121 // Name:
0122 //------------------------------------------------------------------------------
0123 knumber_base *knumber_fraction::add(knumber_base *rhs) {
0124 
0125     if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
0126         knumber_fraction q(p);
0127         mpq_add(mpq_, mpq_, q.mpq_);
0128         return this;
0129     } else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
0130         knumber_float *f = new knumber_float(this);
0131         delete this;
0132         return f->add(p);
0133     } else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
0134         mpq_add(mpq_, mpq_, p->mpq_);
0135         return this;
0136     } else if(knumber_error *const p = dynamic_cast<knumber_error *>(rhs)) {
0137         knumber_error *e = new knumber_error(p);
0138         delete this;
0139         return e;
0140     }
0141 
0142     Q_ASSERT(0);
0143     return nullptr;
0144 }
0145 
0146 //------------------------------------------------------------------------------
0147 // Name:
0148 //------------------------------------------------------------------------------
0149 knumber_base *knumber_fraction::sub(knumber_base *rhs) {
0150 
0151     if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
0152         knumber_fraction q(p);
0153         mpq_sub(mpq_, mpq_, q.mpq_);
0154         return this;
0155     } else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
0156         knumber_float *f = new knumber_float(this);
0157         delete this;
0158         return f->sub(p);
0159     } else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
0160         mpq_sub(mpq_, mpq_, p->mpq_);
0161         return this;
0162     } else if(knumber_error *const p = dynamic_cast<knumber_error *>(rhs)) {
0163         knumber_error *e = new knumber_error(p);
0164         delete this;
0165         return e->neg();
0166     }
0167 
0168     Q_ASSERT(0);
0169     return nullptr;
0170 }
0171 
0172 //------------------------------------------------------------------------------
0173 // Name:
0174 //------------------------------------------------------------------------------
0175 knumber_base *knumber_fraction::mul(knumber_base *rhs) {
0176 
0177     if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
0178         knumber_fraction q(p);
0179         mpq_mul(mpq_, mpq_, q.mpq_);
0180         return this;
0181     } else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
0182         knumber_float *q = new knumber_float(this);
0183         delete this;
0184         return q->mul(p);
0185     } else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
0186         mpq_mul(mpq_, mpq_, p->mpq_);
0187         return this;
0188     } else if(knumber_error *const p = dynamic_cast<knumber_error *>(rhs)) {
0189         if(is_zero()) {
0190             delete this;
0191             knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
0192             return e;
0193         }
0194 
0195         if(sign() < 0) {
0196             delete this;
0197             knumber_error *e = new knumber_error(p);
0198             return e->neg();
0199         } else {
0200             delete this;
0201             knumber_error *e = new knumber_error(p);
0202             return e;
0203         }
0204     }
0205 
0206     Q_ASSERT(0);
0207     return nullptr;
0208 }
0209 
0210 //------------------------------------------------------------------------------
0211 // Name:
0212 //------------------------------------------------------------------------------
0213 knumber_base *knumber_fraction::div(knumber_base *rhs) {
0214 
0215     if(rhs->is_zero()) {
0216         if(sign() < 0) {
0217             delete this;
0218             return new knumber_error(knumber_error::ERROR_NEG_INFINITY);
0219         } else {
0220             delete this;
0221             return new knumber_error(knumber_error::ERROR_POS_INFINITY);
0222         }
0223     }
0224 
0225     if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
0226         knumber_fraction f(p);
0227         return div(&f);
0228     } else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
0229         knumber_float *f = new knumber_float(this);
0230         delete this;
0231         return f->div(p);
0232     } else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
0233         mpq_div(mpq_, mpq_, p->mpq_);
0234         return this;
0235     } else if(knumber_error *const p = dynamic_cast<knumber_error *>(rhs)) {
0236 
0237         if(p->sign() > 0) {
0238             delete this;
0239             return new knumber_integer(0);
0240         } else if(p->sign() < 0) {
0241             delete this;
0242             return new knumber_integer(0);
0243         }
0244 
0245         knumber_error *e = new knumber_error(p);
0246         delete this;
0247         return e;
0248     }
0249 
0250     Q_ASSERT(0);
0251     return nullptr;
0252 }
0253 
0254 //------------------------------------------------------------------------------
0255 // Name:
0256 //------------------------------------------------------------------------------
0257 knumber_base *knumber_fraction::mod(knumber_base *rhs) {
0258 
0259     if(rhs->is_zero()) {
0260         delete this;
0261         return new knumber_error(knumber_error::ERROR_UNDEFINED);
0262     }
0263 
0264     // NOTE: we don't support modulus operations with non-integer operands
0265     mpq_set_d(mpq_, 0);
0266     return this;
0267 }
0268 
0269 //------------------------------------------------------------------------------
0270 // Name:
0271 //------------------------------------------------------------------------------
0272 knumber_base *knumber_fraction::bitwise_and(knumber_base *rhs) {
0273 
0274     Q_UNUSED(rhs);
0275     delete this;
0276     // NOTE: we don't support bitwise operations with non-integer operands
0277     return new knumber_integer(0);
0278 }
0279 
0280 //------------------------------------------------------------------------------
0281 // Name:
0282 //------------------------------------------------------------------------------
0283 knumber_base *knumber_fraction::bitwise_xor(knumber_base *rhs) {
0284 
0285     Q_UNUSED(rhs);
0286     delete this;
0287     // NOTE: we don't support bitwise operations with non-integer operands
0288     return new knumber_integer(0);
0289 }
0290 
0291 //------------------------------------------------------------------------------
0292 // Name:
0293 //------------------------------------------------------------------------------
0294 knumber_base *knumber_fraction::bitwise_or(knumber_base *rhs) {
0295 
0296     Q_UNUSED(rhs);
0297     delete this;
0298     // NOTE: we don't support bitwise operations with non-integer operands
0299     return new knumber_integer(0);
0300 }
0301 
0302 //------------------------------------------------------------------------------
0303 // Name:
0304 //------------------------------------------------------------------------------
0305 knumber_base *knumber_fraction::bitwise_shift(knumber_base *rhs) {
0306 
0307     Q_UNUSED(rhs);
0308     delete this;
0309     // NOTE: we don't support bitwise operations with non-integer operands
0310     return new knumber_error(knumber_error::ERROR_UNDEFINED);
0311 }
0312 
0313 //------------------------------------------------------------------------------
0314 // Name:
0315 //------------------------------------------------------------------------------
0316 knumber_base *knumber_fraction::neg() {
0317     mpq_neg(mpq_, mpq_);
0318     return this;
0319 }
0320 
0321 //------------------------------------------------------------------------------
0322 // Name:
0323 //------------------------------------------------------------------------------
0324 knumber_base *knumber_fraction::abs() {
0325     mpq_abs(mpq_, mpq_);
0326     return this;
0327 }
0328 
0329 //------------------------------------------------------------------------------
0330 // Name:
0331 //------------------------------------------------------------------------------
0332 knumber_base *knumber_fraction::cmp() {
0333 
0334     delete this;
0335     return new knumber_error(knumber_error::ERROR_UNDEFINED);
0336 }
0337 
0338 //------------------------------------------------------------------------------
0339 // Name:
0340 //------------------------------------------------------------------------------
0341 knumber_base *knumber_fraction::sqrt() {
0342 
0343     if(sign() < 0) {
0344         delete this;
0345         return new knumber_error(knumber_error::ERROR_UNDEFINED);
0346     }
0347 
0348     if(mpz_perfect_square_p(mpq_numref(mpq_)) && mpz_perfect_square_p(mpq_denref(mpq_))) {
0349         mpz_t num;
0350         mpz_t den;
0351         mpz_init(num);
0352         mpz_init(den);
0353         mpq_get_num(num, mpq_);
0354         mpq_get_den(den, mpq_);
0355         mpz_sqrt(num, num);
0356         mpz_sqrt(den, den);
0357         mpq_set_num(mpq_, num);
0358         mpq_set_den(mpq_, den);
0359         mpq_canonicalize(mpq_);
0360         mpz_clear(num);
0361         mpz_clear(den);
0362         return this;
0363     } else {
0364         knumber_float *f = new knumber_float(this);
0365         delete this;
0366         return f->sqrt();
0367     }
0368 }
0369 
0370 //------------------------------------------------------------------------------
0371 // Name:
0372 //------------------------------------------------------------------------------
0373 knumber_base *knumber_fraction::cbrt() {
0374 
0375     // TODO: figure out how to properly use mpq_numref/mpq_denref here
0376     mpz_t num;
0377     mpz_t den;
0378 
0379     mpz_init(num);
0380     mpz_init(den);
0381 
0382     mpq_get_num(num, mpq_);
0383     mpq_get_den(den, mpq_);
0384 
0385     if(mpz_root(num, num, 3) && mpz_root(den, den, 3)) {
0386         mpq_set_num(mpq_, num);
0387         mpq_set_den(mpq_, den);
0388         mpq_canonicalize(mpq_);
0389         mpz_clear(num);
0390         mpz_clear(den);
0391         return this;
0392     } else {
0393         mpz_clear(num);
0394         mpz_clear(den);
0395         knumber_float *f = new knumber_float(this);
0396         delete this;
0397         return f->cbrt();
0398     }
0399 }
0400 
0401 //------------------------------------------------------------------------------
0402 // Name:
0403 //------------------------------------------------------------------------------
0404 knumber_base *knumber_fraction::factorial() {
0405 
0406     if(sign() < 0) {
0407         delete this;
0408         return new knumber_error(knumber_error::ERROR_UNDEFINED);
0409     }
0410 
0411     knumber_integer *i = new knumber_integer(this);
0412     delete this;
0413     return i->factorial();
0414 }
0415 
0416 //------------------------------------------------------------------------------
0417 // Name:
0418 //------------------------------------------------------------------------------
0419 knumber_base *knumber_fraction::pow(knumber_base *rhs) {
0420 
0421     // TODO: figure out how to properly use mpq_numref/mpq_denref here
0422     if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
0423 
0424         mpz_t num;
0425         mpz_t den;
0426 
0427         mpz_init(num);
0428         mpz_init(den);
0429 
0430         mpq_get_num(num, mpq_);
0431         mpq_get_den(den, mpq_);
0432 
0433         mpz_pow_ui(num, num, mpz_get_ui(p->mpz_));
0434         mpz_pow_ui(den, den, mpz_get_ui(p->mpz_));
0435         mpq_set_num(mpq_, num);
0436         mpq_set_den(mpq_, den);
0437         mpq_canonicalize(mpq_);
0438         mpz_clear(num);
0439         mpz_clear(den);
0440 
0441         if(p->sign() < 0) {
0442             return reciprocal();
0443         } else {
0444             return this;
0445         }
0446     } else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
0447         Q_UNUSED(p);
0448         knumber_float *f = new knumber_float(this);
0449         delete this;
0450         return f->pow(rhs);
0451     } else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
0452 
0453         // ok, so if any part of the number is > 1,000,000, then we risk
0454         // the pow function overflowing... so we'll just convert to float to be safe
0455         // TODO: at some point, we should figure out exactly what the threshold is
0456         //       and if there is a better way to determine if the pow function will
0457         //       overflow.
0458         if(mpz_cmpabs_ui(mpq_numref(mpq_), 1000000) > 0 || mpz_cmpabs_ui(mpq_denref(mpq_), 1000000) > 0 || mpz_cmpabs_ui(mpq_numref(p->mpq_), 1000000) > 0 || mpz_cmpabs_ui(mpq_denref(p->mpq_), 1000000) > 0) {
0459             knumber_float *f = new knumber_float(this);
0460             delete this;
0461             return f->pow(rhs);
0462         }
0463 
0464         mpz_t lhs_num;
0465         mpz_t lhs_den;
0466         mpz_t rhs_num;
0467         mpz_t rhs_den;
0468 
0469         mpz_init(lhs_num);
0470         mpz_init(lhs_den);
0471         mpz_init(rhs_num);
0472         mpz_init(rhs_den);
0473 
0474         mpq_get_num(lhs_num, mpq_);
0475         mpq_get_den(lhs_den, mpq_);
0476         mpq_get_num(rhs_num, p->mpq_);
0477         mpq_get_den(rhs_den, p->mpq_);
0478 
0479         mpz_pow_ui(lhs_num, lhs_num, mpz_get_ui(rhs_num));
0480         mpz_pow_ui(lhs_den, lhs_den, mpz_get_ui(rhs_num));
0481 
0482         if(mpz_sgn(lhs_num) < 0 && mpz_even_p(rhs_den)) {
0483             mpz_clear(lhs_num);
0484             mpz_clear(lhs_den);
0485             mpz_clear(rhs_num);
0486             mpz_clear(rhs_den);
0487             delete this;
0488             return new knumber_error(knumber_error::ERROR_UNDEFINED);
0489         }
0490 
0491         if(mpz_sgn(lhs_den) < 0 && mpz_even_p(rhs_den)) {
0492             mpz_clear(lhs_num);
0493             mpz_clear(lhs_den);
0494             mpz_clear(rhs_num);
0495             mpz_clear(rhs_den);
0496             delete this;
0497             return new knumber_error(knumber_error::ERROR_UNDEFINED);
0498         }
0499 
0500         const int n1 = mpz_root(lhs_num, lhs_num, mpz_get_ui(rhs_den));
0501         const int n2 = mpz_root(lhs_den, lhs_den, mpz_get_ui(rhs_den));
0502 
0503         if(n1 && n2) {
0504 
0505             mpq_set_num(mpq_, lhs_num);
0506             mpq_set_den(mpq_, lhs_den);
0507             mpq_canonicalize(mpq_);
0508             mpz_clear(lhs_num);
0509             mpz_clear(lhs_den);
0510             mpz_clear(rhs_num);
0511             mpz_clear(rhs_den);
0512 
0513             if(p->sign() < 0) {
0514                 return reciprocal();
0515             } else {
0516                 return this;
0517             }
0518         } else {
0519             mpz_clear(lhs_num);
0520             mpz_clear(lhs_den);
0521             mpz_clear(rhs_num);
0522             mpz_clear(rhs_den);
0523             knumber_float *f = new knumber_float(this);
0524             delete this;
0525 
0526             return f->pow(rhs);
0527         }
0528 
0529     } else if(knumber_error *const p = dynamic_cast<knumber_error *>(rhs)) {
0530         if(p->sign() > 0) {
0531             knumber_error *e = new knumber_error(knumber_error::ERROR_POS_INFINITY);
0532             delete this;
0533             return e;
0534         } else if(p->sign() < 0) {
0535             knumber_integer *n = new knumber_integer(0);
0536             delete this;
0537             return n;
0538         } else {
0539             knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
0540             delete this;
0541             return e;
0542         }
0543     }
0544 
0545     Q_ASSERT(0);
0546     return nullptr;
0547 }
0548 
0549 //------------------------------------------------------------------------------
0550 // Name:
0551 //------------------------------------------------------------------------------
0552 knumber_base *knumber_fraction::sin() {
0553 
0554     knumber_float *f = new knumber_float(this);
0555     delete this;
0556     return f->sin();
0557 }
0558 
0559 //------------------------------------------------------------------------------
0560 // Name:
0561 //------------------------------------------------------------------------------
0562 knumber_base *knumber_fraction::floor() {
0563     knumber_float *f = new knumber_float(this);
0564     delete this;
0565     return f->floor();
0566 }
0567 
0568 //------------------------------------------------------------------------------
0569 // Name:
0570 //------------------------------------------------------------------------------
0571 knumber_base *knumber_fraction::ceil() {
0572     knumber_float *f = new knumber_float(this);
0573     delete this;
0574     return f->ceil();
0575 }
0576 
0577 //------------------------------------------------------------------------------
0578 // Name:
0579 //------------------------------------------------------------------------------
0580 knumber_base *knumber_fraction::cos() {
0581 
0582     knumber_float *f = new knumber_float(this);
0583     delete this;
0584     return f->cos();
0585 }
0586 
0587 //------------------------------------------------------------------------------
0588 // Name:
0589 //------------------------------------------------------------------------------
0590 knumber_base *knumber_fraction::tgamma() {
0591 
0592     knumber_float *f = new knumber_float(this);
0593     delete this;
0594     return f->tgamma();
0595 }
0596 
0597 //------------------------------------------------------------------------------
0598 // Name:
0599 //------------------------------------------------------------------------------
0600 knumber_base *knumber_fraction::tan() {
0601 
0602     knumber_float *f = new knumber_float(this);
0603     delete this;
0604     return f->tan();
0605 }
0606 
0607 //------------------------------------------------------------------------------
0608 // Name:
0609 //------------------------------------------------------------------------------
0610 knumber_base *knumber_fraction::asin() {
0611 
0612     knumber_float *f = new knumber_float(this);
0613     delete this;
0614     return f->asin();
0615 }
0616 
0617 //------------------------------------------------------------------------------
0618 // Name:
0619 //------------------------------------------------------------------------------
0620 knumber_base *knumber_fraction::acos() {
0621 
0622     knumber_float *f = new knumber_float(this);
0623     delete this;
0624     return f->acos();
0625 }
0626 
0627 //------------------------------------------------------------------------------
0628 // Name:
0629 //------------------------------------------------------------------------------
0630 knumber_base *knumber_fraction::atan() {
0631 
0632     knumber_float *f = new knumber_float(this);
0633     delete this;
0634     return f->atan();
0635 }
0636 
0637 //------------------------------------------------------------------------------
0638 // Name:
0639 //------------------------------------------------------------------------------
0640 knumber_base *knumber_fraction::sinh() {
0641     knumber_float *f = new knumber_float(this);
0642     delete this;
0643     return f->sinh();
0644 }
0645 
0646 //------------------------------------------------------------------------------
0647 // Name:
0648 //------------------------------------------------------------------------------
0649 knumber_base *knumber_fraction::cosh() {
0650     knumber_float *f = new knumber_float(this);
0651     delete this;
0652     return f->cosh();
0653 }
0654 
0655 //------------------------------------------------------------------------------
0656 // Name:
0657 //------------------------------------------------------------------------------
0658 knumber_base *knumber_fraction::tanh() {
0659     knumber_float *f = new knumber_float(this);
0660     delete this;
0661     return f->tanh();
0662 }
0663 
0664 //------------------------------------------------------------------------------
0665 // Name:
0666 //------------------------------------------------------------------------------
0667 knumber_base *knumber_fraction::asinh() {
0668     knumber_float *f = new knumber_float(this);
0669     delete this;
0670     return f->asinh();
0671 }
0672 
0673 //------------------------------------------------------------------------------
0674 // Name:
0675 //------------------------------------------------------------------------------
0676 knumber_base *knumber_fraction::acosh() {
0677     knumber_float *f = new knumber_float(this);
0678     delete this;
0679     return f->acosh();
0680 }
0681 
0682 //------------------------------------------------------------------------------
0683 // Name:
0684 //------------------------------------------------------------------------------
0685 knumber_base *knumber_fraction::atanh() {
0686     knumber_float *f = new knumber_float(this);
0687     delete this;
0688     return f->atanh();
0689 }
0690 
0691 //------------------------------------------------------------------------------
0692 // Name:
0693 //------------------------------------------------------------------------------
0694 int knumber_fraction::compare(knumber_base *rhs) {
0695 
0696     if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
0697         knumber_fraction f(p);
0698         return mpq_cmp(mpq_, f.mpq_);
0699     } else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
0700         knumber_float f(this);
0701         return f.compare(p);
0702     } else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
0703         return mpq_cmp(mpq_, p->mpq_);
0704     } else if(knumber_error *const p = dynamic_cast<knumber_error *>(rhs)) {
0705         // NOTE: any number compared to NaN/Inf/-Inf always compares less
0706         //       at the moment
0707         return -1;
0708     }
0709 
0710     Q_ASSERT(0);
0711     return 0;
0712 }
0713 
0714 //------------------------------------------------------------------------------
0715 // Name:
0716 //------------------------------------------------------------------------------
0717 QString knumber_fraction::toString(int precision) const {
0718 
0719 
0720     if(knumber_fraction::default_fractional_output) {
0721 
0722         // TODO: figure out how to properly use mpq_numref/mpq_denref here
0723 
0724         knumber_integer integer_part(this);
0725         if(split_off_integer_for_fraction_output && !integer_part.is_zero()) {
0726 
0727             mpz_t num;
0728             mpz_init(num);
0729             mpq_get_num(num, mpq_);
0730 
0731             knumber_integer integer_part_1(this);
0732 
0733             mpz_mul(integer_part.mpz_, integer_part.mpz_, mpq_denref(mpq_));
0734             mpz_sub(num, num, integer_part.mpz_);
0735 
0736             if(mpz_sgn(num) < 0) {
0737                 mpz_neg(num, num);
0738             }
0739 
0740             const size_t size = gmp_snprintf(nullptr, 0, "%Zd %Zd/%Zd", integer_part_1.mpz_, num, mpq_denref(mpq_)) + 1;
0741             QScopedArrayPointer<char> buf(new char[size]);
0742             gmp_snprintf(&buf[0], size, "%Zd %Zd/%Zd", integer_part_1.mpz_, num, mpq_denref(mpq_));
0743 
0744             mpz_clear(num);
0745 
0746             return QLatin1String(&buf[0]);
0747         } else {
0748 
0749             mpz_t num;
0750             mpz_init(num);
0751             mpq_get_num(num, mpq_);
0752 
0753             const size_t size = gmp_snprintf(nullptr, 0, "%Zd/%Zd", num, mpq_denref(mpq_)) + 1;
0754             QScopedArrayPointer<char> buf(new char[size]);
0755             gmp_snprintf(&buf[0], size, "%Zd/%Zd", num, mpq_denref(mpq_));
0756 
0757             mpz_clear(num);
0758 
0759             return QLatin1String(&buf[0]);
0760         }
0761     } else {
0762         return knumber_float(this).toString(precision);
0763     }
0764 }
0765 QString knumber_fraction::toBinaryString(int precision) const {
0766 
0767 
0768     if(knumber_fraction::default_fractional_output) {
0769 
0770         // TODO: figure out how to properly use mpq_numref/mpq_denref here
0771 
0772         knumber_integer integer_part(this);
0773         if(split_off_integer_for_fraction_output && !integer_part.is_zero()) {
0774 
0775             mpz_t num;
0776             mpz_init(num);
0777             mpq_get_num(num, mpq_);
0778 
0779             knumber_integer integer_part_1(this);
0780 
0781             mpz_mul(integer_part.mpz_, integer_part.mpz_, mpq_denref(mpq_));
0782             mpz_sub(num, num, integer_part.mpz_);
0783 
0784             if(mpz_sgn(num) < 0) {
0785                 mpz_neg(num, num);
0786             }
0787 
0788             const size_t size = gmp_snprintf(nullptr, 0, "%Zb %Zb/%Zb", integer_part_1.mpz_, num, mpq_denref(mpq_)) + 1;
0789             QScopedArrayPointer<char> buf(new char[size]);
0790             gmp_snprintf(&buf[0], size, "%Zb %Zb/%Zb", integer_part_1.mpz_, num, mpq_denref(mpq_));
0791 
0792             mpz_clear(num);
0793 
0794             return QLatin1String(&buf[0]);
0795         } else {
0796 
0797             mpz_t num;
0798             mpz_init(num);
0799             mpq_get_num(num, mpq_);
0800 
0801             const size_t size = gmp_snprintf(nullptr, 0, "%Zb/%Zb", num, mpq_denref(mpq_)) + 1;
0802             QScopedArrayPointer<char> buf(new char[size]);
0803             gmp_snprintf(&buf[0], size, "%Zb/%Zb", num, mpq_denref(mpq_));
0804 
0805             mpz_clear(num);
0806 
0807             return QLatin1String(&buf[0]);
0808         }
0809     } else {
0810         return knumber_float(this).toString(precision);
0811     }
0812 }
0813 QString knumber_fraction::toHexString(int precision) const {
0814     if(knumber_fraction::default_fractional_output) {
0815 
0816         // TODO: figure out how to properly use mpq_numref/mpq_denref here
0817 
0818         knumber_integer integer_part(this);
0819         if(split_off_integer_for_fraction_output && !integer_part.is_zero()) {
0820 
0821             mpz_t num;
0822             mpz_init(num);
0823             mpq_get_num(num, mpq_);
0824 
0825             knumber_integer integer_part_1(this);
0826 
0827             mpz_mul(integer_part.mpz_, integer_part.mpz_, mpq_denref(mpq_));
0828             mpz_sub(num, num, integer_part.mpz_);
0829 
0830             if(mpz_sgn(num) < 0) {
0831                 mpz_neg(num, num);
0832             }
0833 
0834             const size_t size = gmp_snprintf(nullptr, 0, "%Zh %Zh/%Zh", integer_part_1.mpz_, num, mpq_denref(mpq_)) + 1;
0835             QScopedArrayPointer<char> buf(new char[size]);
0836             gmp_snprintf(&buf[0], size, "%Zh %Zh/%Zh", integer_part_1.mpz_, num, mpq_denref(mpq_));
0837 
0838             mpz_clear(num);
0839 
0840             return QLatin1String(&buf[0]);
0841         } else {
0842 
0843             mpz_t num;
0844             mpz_init(num);
0845             mpq_get_num(num, mpq_);
0846 
0847             const size_t size = gmp_snprintf(nullptr, 0, "%Zh/%Zh", num, mpq_denref(mpq_)) + 1;
0848             QScopedArrayPointer<char> buf(new char[size]);
0849             gmp_snprintf(&buf[0], size, "%Zh/%Zh", num, mpq_denref(mpq_));
0850 
0851             mpz_clear(num);
0852 
0853             return QLatin1String(&buf[0]);
0854         }
0855     } else {
0856         return knumber_float(this).toString(precision);
0857     }
0858 }
0859 //------------------------------------------------------------------------------
0860 // Name:
0861 //------------------------------------------------------------------------------
0862 bool knumber_fraction::is_zero() const {
0863     return mpq_sgn(mpq_) == 0;
0864 }
0865 
0866 //------------------------------------------------------------------------------
0867 // Name:
0868 //------------------------------------------------------------------------------
0869 int knumber_fraction::sign() const {
0870     return mpq_sgn(mpq_);
0871 }
0872 
0873 //------------------------------------------------------------------------------
0874 // Name:
0875 //------------------------------------------------------------------------------
0876 knumber_base *knumber_fraction::reciprocal() {
0877 
0878     mpq_inv(mpq_, mpq_);
0879     return this;
0880 }
0881 
0882 //------------------------------------------------------------------------------
0883 // Name:
0884 //------------------------------------------------------------------------------
0885 knumber_integer *knumber_fraction::numerator() const {
0886 
0887     mpz_t num;
0888     mpz_init(num);
0889     mpq_get_num(num, mpq_);
0890     knumber_integer *n = new knumber_integer(num);
0891     mpz_clear(num);
0892     return n;
0893 }
0894 
0895 //------------------------------------------------------------------------------
0896 // Name:
0897 //------------------------------------------------------------------------------
0898 knumber_integer *knumber_fraction::denominator() const {
0899 
0900     mpz_t den;
0901     mpz_init(den);
0902     mpq_get_den(den, mpq_);
0903     knumber_integer *n = new knumber_integer(den);
0904     mpz_clear(den);
0905     return n;
0906 }
0907 
0908 //------------------------------------------------------------------------------
0909 // Name:
0910 //------------------------------------------------------------------------------
0911 knumber_base *knumber_fraction::log2() {
0912     knumber_float *f = new knumber_float(this);
0913     delete this;
0914     return f->log2();
0915 }
0916 
0917 //------------------------------------------------------------------------------
0918 // Name:
0919 //------------------------------------------------------------------------------
0920 knumber_base *knumber_fraction::log10() {
0921     knumber_float *f = new knumber_float(this);
0922     delete this;
0923     return f->log10();
0924 }
0925 
0926 //------------------------------------------------------------------------------
0927 // Name:
0928 //------------------------------------------------------------------------------
0929 knumber_base *knumber_fraction::ln() {
0930     knumber_float *f = new knumber_float(this);
0931     delete this;
0932     return f->ln();
0933 }
0934 
0935 //------------------------------------------------------------------------------
0936 // Name:
0937 //------------------------------------------------------------------------------
0938 knumber_base *knumber_fraction::exp2() {
0939     knumber_float *f = new knumber_float(this);
0940     delete this;
0941     return f->exp2();
0942 }
0943 
0944 //------------------------------------------------------------------------------
0945 // Name:
0946 //------------------------------------------------------------------------------
0947 knumber_base *knumber_fraction::exp10() {
0948     knumber_float *f = new knumber_float(this);
0949     delete this;
0950     return f->exp10();
0951 }
0952 
0953 //------------------------------------------------------------------------------
0954 // Name:
0955 //------------------------------------------------------------------------------
0956 knumber_base *knumber_fraction::exp() {
0957     knumber_float *f = new knumber_float(this);
0958     delete this;
0959     return f->exp();
0960 }
0961 
0962 //------------------------------------------------------------------------------
0963 // Name:
0964 //------------------------------------------------------------------------------
0965 quint64 knumber_fraction::toUint64() const {
0966     return knumber_integer(this).toUint64();
0967 }
0968 
0969 //------------------------------------------------------------------------------
0970 // Name:
0971 //------------------------------------------------------------------------------
0972 qint64 knumber_fraction::toInt64() const {
0973     return knumber_integer(this).toInt64();
0974 }
0975 
0976 //------------------------------------------------------------------------------
0977 // Name:
0978 //------------------------------------------------------------------------------
0979 knumber_base *knumber_fraction::bin(knumber_base *rhs) {
0980     Q_UNUSED(rhs);
0981     delete this;
0982     return new knumber_error(knumber_error::ERROR_UNDEFINED);
0983 
0984 }
0985 
0986 }