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 }