File indexing completed on 2024-04-21 05:50:03

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