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 }