File indexing completed on 2024-05-12 05:55:09
0001 // cmath.cpp 0002 // Complex number support : type definition and function for complex numbers. 0003 // 0004 // This file is part of the SpeedCrunch project 0005 // Copyright (C) 2013, 2015-2016 Hadrien Theveneau <theveneau@gmail.com>. 0006 // Copyright (C) 2015-2016 Pol Welter. 0007 // Copyright (C) 2016 @heldercorreia 0008 // 0009 // This program is free software; you can redistribute it and/or 0010 // modify it under the terms of the GNU General Public License 0011 // as published by the Free Software Foundation; either version 2 0012 // of the License, or (at your option) any later version. 0013 // 0014 // This program is distributed in the hope that it will be useful, 0015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 // GNU General Public License for more details. 0018 // 0019 // You should have received a copy of the GNU General Public License 0020 // along with this program; see the file COPYING. If not, write to 0021 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0022 // Boston, MA 02110-1301, USA. 0023 0024 #include "cmath.h" 0025 0026 #include "cnumberparser.h" 0027 #include "floatconvert.h" 0028 #include "hmath.h" 0029 0030 #include <QString> 0031 #include <QStringList> 0032 0033 #include <stdlib.h> 0034 #include <string.h> 0035 0036 /** 0037 * Creates a new complex number. 0038 */ 0039 CNumber::CNumber() 0040 : real(0) 0041 , imag(0) 0042 {} 0043 0044 /** 0045 * Creates a new complex number from one real number 0046 */ 0047 CNumber::CNumber(const HNumber& hn) : 0048 real(hn), 0049 imag(0) 0050 { 0051 } 0052 0053 /** 0054 * Creates a new complex number from the real and imaginary parts 0055 */ 0056 CNumber::CNumber(const HNumber& x, const HNumber& y) 0057 : real(x) 0058 , imag(y) 0059 { 0060 } 0061 0062 /** 0063 * Copies from another complex number. 0064 */ 0065 CNumber::CNumber(const CNumber& cn) 0066 : real(cn.real) 0067 , imag(cn.imag) 0068 { 0069 } 0070 0071 /** 0072 * Creates a new number from an integer value. 0073 */ 0074 CNumber::CNumber(int i) 0075 : real(i) 0076 , imag(0) 0077 { 0078 } 0079 0080 /** 0081 * Creates a new number from a string. 0082 */ 0083 CNumber::CNumber(const char* str) 0084 { 0085 CNumberParser parser(str); 0086 parser.parse(this); // FIXME: Exception management. 0087 } 0088 0089 CNumber::CNumber(const QJsonObject& json) 0090 { 0091 *this = deSerialize(json); 0092 } 0093 0094 /** 0095 * Returns true if this number is Not a Number (NaN). 0096 */ 0097 bool CNumber::isNan() const 0098 { 0099 return real.isNan() || imag.isNan(); 0100 } 0101 0102 /** 0103 * Returns true if this number is zero. 0104 */ 0105 bool CNumber::isZero() const 0106 { 0107 return real.isZero() && imag.isZero(); 0108 } 0109 0110 /** 0111 * Returns true if this number is a positive REAL 0112 */ 0113 bool CNumber::isPositive() const 0114 { 0115 return real.isPositive() && imag.isZero(); 0116 } 0117 0118 /** 0119 * Returns true if this number is a negative REAL 0120 */ 0121 bool CNumber::isNegative() const 0122 { 0123 return real.isNegative() && imag.isZero(); 0124 } 0125 0126 /** 0127 * Returns true if this number is integer and REAL 0128 */ 0129 bool CNumber::isInteger() const 0130 { 0131 return real.isInteger() && imag.isZero(); 0132 } 0133 0134 /** 0135 * Returns true if this number is a Gaussian integer 0136 */ 0137 bool CNumber::isGaussian() const 0138 { 0139 return real.isInteger() && imag.isInteger(); 0140 } 0141 0142 /** 0143 * Returns true if this number is a real number 0144 */ 0145 bool CNumber::isReal() const 0146 { 0147 return imag.isZero(); 0148 } 0149 0150 /** 0151 * Returns true if this number is approximately a real number 0152 */ 0153 bool CNumber::isNearReal() const 0154 { 0155 return imag.isNearZero(); 0156 } 0157 0158 void CNumber::serialize(QJsonObject& json) const 0159 { 0160 json["value"] = CMath::format(*this, CNumber::Format::Fixed() + CNumber::Format::Precision(DECPRECISION)); 0161 } 0162 0163 CNumber CNumber::deSerialize(const QJsonObject& json) 0164 { 0165 CNumber result; 0166 if (json.contains("value")) { 0167 QString str = json["value"].toString(); 0168 str.replace(",", "."); 0169 result = CNumber(str.toLatin1().constData()); 0170 } 0171 return result; 0172 } 0173 0174 /** 0175 * Returns a NaN (Not a Number) with error set to 0176 * passed parameter. 0177 */ 0178 CNumber CMath::nan(Error error) 0179 { 0180 // We must always ensure that both numbers have the same NaN error. 0181 CNumber result; 0182 result.real = HMath::nan(error); 0183 result.imag = HMath::nan(error); 0184 return result; 0185 } 0186 0187 /** 0188 * Returns the error code kept with a NaN. 0189 */ 0190 Error CNumber::error() const 0191 { 0192 // real and imag have always the same NaN error. 0193 return real.error(); 0194 } 0195 0196 /** 0197 * Assigns from another complex number. 0198 */ 0199 CNumber& CNumber::operator=(const CNumber& cn) 0200 { 0201 real = cn.real; 0202 imag = cn.imag; 0203 return *this; 0204 } 0205 0206 /** 0207 * Adds another complex number. 0208 */ 0209 CNumber CNumber::operator+(const CNumber& num) const 0210 { 0211 CNumber result; 0212 result.real = real + num.real; 0213 result.imag = imag + num.imag; 0214 return result; 0215 } 0216 0217 /** 0218 * Adds another complex number. 0219 */ 0220 CNumber& CNumber::operator+=(const CNumber& num) 0221 { 0222 return operator=(*this + num); 0223 } 0224 0225 /** 0226 * Subtract from another complex number. 0227 */ 0228 CNumber operator-(const CNumber& n1, const CNumber& n2) 0229 { 0230 CNumber result; 0231 result.real = n1.real - n2.real; 0232 result.imag = n1.imag - n2.imag; 0233 return result; 0234 } 0235 0236 /** 0237 * Subtract from another complex number. 0238 */ 0239 CNumber& CNumber::operator-=(const CNumber& num) 0240 { 0241 return operator=(*this - num); 0242 } 0243 0244 /** 0245 * Multiplies with another complex number. 0246 */ 0247 CNumber CNumber::operator*(const CNumber& num) const 0248 { 0249 CNumber result; 0250 result.real = real*num.real - imag*num.imag; 0251 result.imag = imag*num.real + real*num.imag; 0252 return result; 0253 } 0254 0255 /** 0256 * Multiplies with another REAL number. 0257 */ 0258 CNumber CNumber::operator*(const HNumber& num) const 0259 { 0260 CNumber result; 0261 result.real = real*num; 0262 result.imag = imag*num; 0263 return result; 0264 } 0265 0266 /** 0267 * Multiplies with another number. 0268 */ 0269 CNumber& CNumber::operator*=(const CNumber& num) 0270 { 0271 return operator=(*this * num); 0272 } 0273 0274 /** 0275 * Divides with another complex number. 0276 */ 0277 CNumber CNumber::operator/(const CNumber& num) const 0278 { 0279 if (num.isZero()) 0280 return CMath::nan(ZeroDivide); 0281 else { 0282 CNumber result; 0283 HNumber divider = num.real*num.real + num.imag*num.imag; 0284 result.real = (real*num.real + imag*num.imag) / divider; 0285 result.imag = (imag*num.real - real*num.imag) / divider; 0286 return result; 0287 } 0288 } 0289 0290 /** 0291 * Divides with another REAL number. 0292 */ 0293 CNumber CNumber::operator/(const HNumber& num) const 0294 { 0295 if (num.isZero()) 0296 return CMath::nan(ZeroDivide); 0297 else 0298 return CNumber(real / num, imag / num) ; 0299 } 0300 0301 /** 0302 * Divides with another number. 0303 */ 0304 CNumber& CNumber::operator/=(const CNumber& num) 0305 { 0306 return operator=(*this / num); 0307 } 0308 0309 /** 0310 * Returns -1, 0, 1 if n1 is less than, equal to, or more than n2. 0311 * Only valid for real numbers, since complex ones are not an ordered field. 0312 */ 0313 int CNumber::compare(const CNumber& other) const 0314 { 0315 if (isReal() && other.isReal()) 0316 return real.compare(other.real); 0317 else 0318 return false; // FIXME: Return something better. 0319 } 0320 0321 /** 0322 * Returns true if l is greater than r. 0323 */ 0324 bool operator>(const CNumber& l, const CNumber& r) 0325 { 0326 return l.compare(r) > 0; 0327 } 0328 0329 /** 0330 * Returns true if l is less than r. 0331 */ 0332 bool operator<(const CNumber& l, const CNumber& r) 0333 { 0334 return l.compare(r) < 0; 0335 } 0336 0337 /** 0338 * Returns true if l is greater than or equal to r. 0339 */ 0340 bool operator>=(const CNumber& l, const CNumber& r) 0341 { 0342 return l.compare(r) >= 0; 0343 } 0344 0345 /** 0346 * Returns true if l is less than or equal to r. 0347 */ 0348 bool operator<=(const CNumber& l, const CNumber& r) 0349 { 0350 return l.compare(r) <= 0; 0351 } 0352 0353 /** 0354 * Returns true if l is equal to r. 0355 */ 0356 bool operator==(const CNumber& l, const CNumber& r) 0357 { 0358 return l.compare(r) == 0; 0359 } 0360 0361 /** 0362 * Returns true if l is not equal to r. 0363 */ 0364 bool operator!=(const CNumber& l, const CNumber& r) 0365 { 0366 return l.compare(r) != 0; 0367 } 0368 0369 /** 0370 * Changes the sign. 0371 */ 0372 CNumber operator-(const CNumber& x) 0373 { 0374 return CNumber(-x.real, -x.imag); 0375 } 0376 0377 CNumber::Format::Format() 0378 : HNumber::Format() 0379 , notation(Format::Notation::Null) 0380 { 0381 } 0382 0383 CNumber::Format::Format(const Format& other) 0384 : HNumber::Format(static_cast<const HNumber::Format&>(other)) 0385 , notation(other.notation) 0386 { 0387 } 0388 0389 CNumber::Format::Format(const HNumber::Format& other) 0390 : HNumber::Format(other) 0391 , notation(Notation::Null) 0392 { 0393 } 0394 0395 CNumber::Format CNumber::Format::operator+(const CNumber::Format& other) const 0396 { 0397 Format result(HNumber::Format::operator+(static_cast<const HNumber::Format&>(other))); 0398 result.notation = (this->notation != Notation::Null) ? this->notation : other.notation; 0399 return result; 0400 } 0401 0402 CNumber::Format CNumber::Format::Polar() 0403 { 0404 Format result; 0405 result.notation = Format::Notation::Polar; 0406 return result; 0407 } 0408 0409 CNumber::Format CNumber::Format::Cartesian() 0410 { 0411 Format result; 0412 result.notation = Format::Notation::Cartesian; 0413 return result; 0414 } 0415 0416 /** 0417 * Returns the constant e (Euler's number). 0418 */ 0419 CNumber CMath::e() 0420 { 0421 return CNumber(HMath::e()); 0422 } 0423 0424 /** 0425 * Returns the constant pi. 0426 */ 0427 CNumber CMath::pi() 0428 { 0429 return CNumber(HMath::pi()); 0430 } 0431 0432 /** 0433 * Returns the constant phi (golden number). 0434 */ 0435 CNumber CMath::phi() 0436 { 0437 return CNumber(HMath::phi()); 0438 } 0439 0440 /** 0441 * Returns the constant i. 0442 */ 0443 CNumber CMath::i() 0444 { 0445 return CNumber(0, 1); 0446 } 0447 0448 // TODO: Improve complex number formatting. 0449 0450 /** 0451 * Formats the given number as string. 0452 */ 0453 QString CMath::format(const CNumber& cn, CNumber::Format format) 0454 { 0455 if (cn.isNan()) 0456 return "NaN"; 0457 else if (cn.imag.isNearZero()) // Number is real. 0458 return HMath::format(cn.real, format); 0459 if (format.notation == CNumber::Format::Notation::Polar) { 0460 QString strRadius = HMath::format(CMath::abs(cn).real, format); 0461 HNumber phase = CMath::phase(cn).real; 0462 if (phase.isZero()) 0463 return strRadius; 0464 QString strPhase = HMath::format(phase, format); 0465 return QString("%1 * exp(j*%2)").arg(strRadius, strPhase); 0466 } else { 0467 QString real_part = cn.real.isZero()? "" : HMath::format(cn.real, format); 0468 QString imag_part = ""; 0469 QString separator = ""; 0470 QString prefix = ""; // TODO: Insert two modes, one for a+jb and one for a+bj. 0471 QString postfix = "j"; // TODO: Insert two modes, one for a+bi and one for a+bj. 0472 0473 if (cn.imag.isPositive()) { 0474 separator = cn.real.isZero() ? "": "+"; 0475 imag_part = HMath::format(cn.imag, format); 0476 } else { 0477 separator = "-"; 0478 imag_part = HMath::format(-cn.imag, format); 0479 } 0480 return real_part + separator + prefix + imag_part + postfix; 0481 } 0482 } 0483 0484 /** 0485 * Returns the norm of n. 0486 */ 0487 CNumber CMath::abs(const CNumber& n) 0488 { 0489 return HMath::sqrt(n.real * n.real + n.imag * n.imag); 0490 } 0491 0492 /* 0493 * Returns the complex conjugate of n 0494 */ 0495 CNumber CMath::conj(const CNumber& n) 0496 { 0497 return CNumber(n.real, -n.imag); 0498 } 0499 0500 /** 0501 * Returns the square root of n. 0502 */ 0503 CNumber CMath::sqrt(const CNumber& n) 0504 { 0505 CNumber result; 0506 HNumber s = (n.imag.isPositive() || n.imag.isZero()) ? 1 : -1; 0507 0508 // cf https://en.wikipedia.org/wiki/Square_root#Square_roots_of_negative_and_complex_numbers. 0509 result.real = HMath::sqrt((abs(n).real + n.real) / 2); 0510 result.imag = s * HMath::sqrt((abs(n).real - n.real) / 2); 0511 0512 return result; 0513 } 0514 0515 /** 0516 * Raises n1 to an integer n. 0517 */ 0518 CNumber CMath::raise(const CNumber& n1, int n) 0519 { 0520 return CMath::exp(CMath::ln(n1) * n); 0521 } 0522 0523 /** 0524 * Raises n1 to n2. 0525 */ 0526 CNumber CMath::raise(const CNumber& n1, const CNumber& n2) 0527 { 0528 if (n1.isZero() && (n2.real > 0)) 0529 return CNumber(0); 0530 return CMath::exp(CMath::ln(n1) * n2); 0531 } 0532 0533 /** 0534 * Returns e raised to x. 0535 */ 0536 CNumber CMath::exp(const CNumber& x) 0537 { 0538 HNumber abs = HMath::exp(x.real); 0539 return CNumber(abs*HMath::cos(x.imag), abs*HMath::sin(x.imag)); 0540 } 0541 0542 /** 0543 * Returns the complex natural logarithm of x. 0544 */ 0545 CNumber CMath::ln(const CNumber& x) 0546 { 0547 HNumber abs = CMath::abs(x).real; 0548 CNumber result; 0549 result.real = HMath::ln(abs); 0550 // Principal Value logarithm 0551 // https://en.wikipedia.org/wiki/Complex_logarithm#Definition_of_principal_value 0552 auto imag = HMath::arccos(x.real / abs); 0553 result.imag = (x.imag.isPositive() || x.imag.isZero()) ? imag : -imag; 0554 return result; 0555 } 0556 0557 /** 0558 * Returns the common logarithm of x. 0559 */ 0560 CNumber CMath::lg(const CNumber& x) 0561 { 0562 return CMath::ln(x) / HMath::ln(10); 0563 } 0564 0565 /** 0566 * Returns the binary logarithm of x. 0567 */ 0568 CNumber CMath::lb(const CNumber& x) 0569 { 0570 return CMath::ln(x) / HMath::ln(2); 0571 } 0572 0573 /** 0574 * Returns the logarithm of x to base. 0575 * If x is non positive, returns NaN. 0576 */ 0577 CNumber CMath::log(const CNumber& base, const CNumber& x) 0578 { 0579 return CMath::ln(x) / CMath::ln(base); 0580 } 0581 0582 /** 0583 * Returns the complex sine of x. Note that x must be in radians. 0584 */ 0585 CNumber CMath::sin(const CNumber& x) 0586 { 0587 // cf. https://en.wikipedia.org/wiki/Sine#Sine_with_a_complex_argument. 0588 return CNumber(HMath::sin(x.real) * HMath::cosh(x.imag), HMath::cos(x.real) * HMath::sinh(x.imag)); 0589 } 0590 0591 /** 0592 * Returns the cosine of x. Note that x must be in radians. 0593 */ 0594 CNumber CMath::cos(const CNumber& x) 0595 { 0596 // Expanded using Wolfram Mathematica 9.0. 0597 return CNumber(HMath::cos(x.real) * HMath::cosh(x.imag), -HMath::sin(x.real) * HMath::sinh(x.imag)); 0598 } 0599 0600 /** 0601 * Returns the tangent of x. Note that x must be in radians. 0602 */ 0603 CNumber CMath::tan(const CNumber& x) 0604 { 0605 return CMath::sin(x) / CMath::cos(x); 0606 } 0607 0608 /** 0609 * Returns the hyperbolic sine of x. 0610 */ 0611 CNumber CMath::sinh(const CNumber& x) 0612 { 0613 return (exp(x) - exp(-x)) / HNumber(2); 0614 } 0615 0616 /** 0617 * Returns the hyperbolic cosine of x. 0618 */ 0619 CNumber CMath::cosh(const CNumber& x) 0620 { 0621 return (exp(x) + exp(-x)) / HNumber(2); 0622 } 0623 0624 /** 0625 * Returns the hyperbolic tangent of x. 0626 */ 0627 CNumber CMath::tanh(const CNumber& x) 0628 { 0629 return sinh(x) / cosh(x); 0630 } 0631 0632 /** 0633 * Returns the cotangent of x. Note that x must be in radians. 0634 */ 0635 CNumber CMath::cot(const CNumber& x) 0636 { 0637 return cos(x) / sin(x); 0638 } 0639 0640 /** 0641 * Returns the secant of x. Note that x must be in radians. 0642 */ 0643 CNumber CMath::sec(const CNumber& x) 0644 { 0645 return CNumber(1) / cos(x); 0646 } 0647 0648 /** 0649 * Returns the cosecant of x. Note that x must be in radians. 0650 */ 0651 CNumber CMath::csc(const CNumber& x) 0652 { 0653 return CNumber(1) / sin(x); 0654 } 0655 0656 /** 0657 * Returns the area hyperbolic sine of x. 0658 */ 0659 CNumber CMath::arsinh(const CNumber& x) 0660 { 0661 return CMath::ln(x + CMath::sqrt(x * x + CNumber(1))); 0662 } 0663 0664 /** 0665 * Returns the area hyperbolic cosine of x. 0666 */ 0667 CNumber CMath::arcosh(const CNumber& x) 0668 { 0669 return CMath::ln(x + CMath::sqrt(x + CNumber(1)) * CMath::sqrt(x - CNumber(1))); 0670 } 0671 0672 /** 0673 * Returns the area hyperbolic tangent of x. 0674 */ 0675 CNumber CMath::artanh(const CNumber& x) 0676 { 0677 return (CNumber("0.5") * CMath::ln(CNumber(1) + x)) - (CNumber("0.5") * CMath::ln(CNumber(1) - x)); 0678 } 0679 0680 /** 0681 * Returns the phase of x. 0682 */ 0683 CNumber CMath::phase(const CNumber& x) 0684 { 0685 return HMath::arctan2(x.real, x.imag); 0686 } 0687 0688 /** 0689 * Returns the arc tangent of x. 0690 */ 0691 CNumber CMath::arctan(const CNumber& x) 0692 { 0693 return CMath::i() * (CMath::ln(CNumber(1) - CMath::i() * x) - CMath::ln(CNumber(1) + CMath::i() * x)) / 2; 0694 } 0695 0696 /** 0697 * Returns the arc sine of x. 0698 */ 0699 CNumber CMath::arcsin(const CNumber& x) 0700 { 0701 return -CMath::i() * CMath::ln(CMath::i() * x + sqrt(CNumber(1) - x * x)); 0702 } 0703 0704 /** 0705 * Returns the arc cosine of x. 0706 */ 0707 CNumber CMath::arccos(const CNumber& x) 0708 { 0709 return -CMath::i() * CMath::ln(x + sqrt(x * x - CNumber(1))); 0710 } 0711 0712 /** 0713 * Converts an angle from radians to degrees. 0714 * Also accepts complex arguments. 0715 */ 0716 CNumber CMath::rad2deg(const CNumber& x) 0717 { 0718 return CNumber(HMath::rad2deg(x.real), HMath::rad2deg(x.imag)); 0719 } 0720 0721 /** 0722 * Converts an angle from degrees to radians. 0723 * Also accepts complex arguments. 0724 */ 0725 CNumber CMath::deg2rad(const CNumber& x) 0726 { 0727 return CNumber(HMath::deg2rad(x.real), HMath::deg2rad(x.imag)); 0728 } 0729 0730 /** 0731 * Converts an angle from radians to gons. 0732 * Also accepts complex arguments. 0733 */ 0734 CNumber CMath::rad2gon(const CNumber& x) 0735 { 0736 return CNumber(HMath::rad2gon(x.real), HMath::rad2gon(x.imag)); 0737 } 0738 0739 /** 0740 * Converts an angle from gons to radians. 0741 * Also accepts complex arguments. 0742 */ 0743 CNumber CMath::gon2rad(const CNumber& x) 0744 { 0745 return CNumber(HMath::gon2rad(x.real), HMath::gon2rad(x.imag)); 0746 } 0747 0748 // Wrappers towards functions defined only on real numbers 0749 // ======================================================= 0750 0751 // NaN is treated like real numbers for the purposes of wrappers. 0752 #define ENSURE_REAL(number, error) \ 0753 if((number).isNan() || !(number).isNearReal()) \ 0754 return CMath::nan(error); 0755 0756 #define REAL_WRAPPER_CNUMBER_1(fct, error) \ 0757 CNumber CNumber::fct() const \ 0758 { \ 0759 ENSURE_REAL(*this, error); \ 0760 return CNumber(this->real.fct()); \ 0761 } 0762 0763 #define REAL_WRAPPER_CNUMBER_2(fct, error) \ 0764 CNumber CNumber::fct(const CNumber& x) const \ 0765 { \ 0766 ENSURE_REAL(*this, error); \ 0767 ENSURE_REAL(x, error); \ 0768 return CNumber(this->real.fct(x.real)); \ 0769 } 0770 0771 #define REAL_WRAPPER_CNUMBER_3(fct, error) \ 0772 CNumber& CNumber::fct(const CNumber& x) \ 0773 { \ 0774 if(!this->isReal()) { \ 0775 *this = CMath::nan(error); \ 0776 return *this; \ 0777 } \ 0778 if (!x.isReal()) { \ 0779 *this = CMath::nan(error); \ 0780 return *this; \ 0781 } \ 0782 this->real.fct(x.real); \ 0783 return *this; \ 0784 } 0785 0786 #define REAL_WRAPPER_CNUMBER_4(fct, error) \ 0787 int CNumber::fct() const \ 0788 { \ 0789 if (!this->isNearReal()) \ 0790 return 0; /* FIXME: Better fail value. */ \ 0791 return this->real.fct(); \ 0792 } 0793 0794 #define REAL_WRAPPER_CMATH_NUM(fct, error) \ 0795 CNumber CMath::fct(const CNumber& x) \ 0796 { \ 0797 ENSURE_REAL(x, error); \ 0798 return CNumber(HMath::fct(x.real)); \ 0799 } 0800 0801 #define REAL_WRAPPER_CMATH_NUM_NUM(fct, error) \ 0802 CNumber CMath::fct(const CNumber& x1, const CNumber& x2) \ 0803 { \ 0804 ENSURE_REAL(x1, error); \ 0805 ENSURE_REAL(x2, error); \ 0806 return CNumber(HMath::fct(x1.real, x2.real)); \ 0807 } 0808 0809 #define REAL_WRAPPER_CMATH_NUM_INT(fct, error) \ 0810 CNumber CMath::fct(const CNumber& x1, int n) \ 0811 { \ 0812 ENSURE_REAL(x1, error); \ 0813 return CNumber(HMath::fct(x1.real, n)); \ 0814 } 0815 0816 #define REAL_WRAPPER_CMATH_NUM_NUM_NUM(fct, error) \ 0817 CNumber CMath::fct(const CNumber& x1, const CNumber& x2, const CNumber& x3) \ 0818 { \ 0819 ENSURE_REAL(x1, error); \ 0820 ENSURE_REAL(x2, error); \ 0821 ENSURE_REAL(x3, error); \ 0822 return CNumber(HMath::fct(x1.real, x2.real, x3.real)); \ 0823 } 0824 0825 #define REAL_WRAPPER_CMATH_NUM_NUM_NUM_NUM(fct, error) \ 0826 CNumber CMath::fct(const CNumber& x1, const CNumber& x2, const CNumber& x3, const CNumber& x4) \ 0827 { \ 0828 ENSURE_REAL(x1, error); \ 0829 ENSURE_REAL(x2, error); \ 0830 ENSURE_REAL(x3, error); \ 0831 ENSURE_REAL(x4, error); \ 0832 return CNumber(HMath::fct(x1.real, x2.real, x3.real, x4.real)); \ 0833 } 0834 0835 // CNumber 0836 REAL_WRAPPER_CNUMBER_4(toInt, OutOfDomain) 0837 REAL_WRAPPER_CNUMBER_2(operator%, OutOfDomain) 0838 REAL_WRAPPER_CNUMBER_2(operator&, OutOfLogicRange) 0839 REAL_WRAPPER_CNUMBER_3(operator&=, OutOfLogicRange) 0840 REAL_WRAPPER_CNUMBER_2(operator|, OutOfLogicRange) 0841 REAL_WRAPPER_CNUMBER_3(operator|=, OutOfLogicRange) 0842 REAL_WRAPPER_CNUMBER_2(operator^, OutOfLogicRange) 0843 REAL_WRAPPER_CNUMBER_3(operator^=, OutOfLogicRange) 0844 REAL_WRAPPER_CNUMBER_1(operator~, OutOfLogicRange) 0845 REAL_WRAPPER_CNUMBER_2(operator>>, OutOfLogicRange) 0846 REAL_WRAPPER_CNUMBER_2(operator<<, OutOfLogicRange) 0847 // CMath GENERAL MATH 0848 REAL_WRAPPER_CMATH_NUM(integer, OutOfDomain) 0849 REAL_WRAPPER_CMATH_NUM(frac, OutOfDomain) 0850 REAL_WRAPPER_CMATH_NUM(floor, OutOfDomain) 0851 REAL_WRAPPER_CMATH_NUM(ceil, OutOfDomain) 0852 REAL_WRAPPER_CMATH_NUM_NUM(gcd, OutOfDomain) 0853 REAL_WRAPPER_CMATH_NUM_NUM(idiv, OutOfDomain) 0854 REAL_WRAPPER_CMATH_NUM_INT(round, OutOfDomain) 0855 REAL_WRAPPER_CMATH_NUM_INT(trunc, OutOfDomain) 0856 REAL_WRAPPER_CMATH_NUM(cbrt, OutOfDomain) 0857 REAL_WRAPPER_CMATH_NUM(sgn, OutOfDomain) 0858 // CMath EXPONENTIAL FUNCTION AND RELATED 0859 REAL_WRAPPER_CMATH_NUM_NUM(arctan2, OutOfDomain) 0860 // CMath TRIGONOMETRY 0861 /* All trigonometry functions accept complex numbers */ 0862 // CMath HIGHER MATH FUNCTIONS 0863 REAL_WRAPPER_CMATH_NUM_NUM(factorial, NotImplemented) 0864 REAL_WRAPPER_CMATH_NUM(erf, OutOfDomain) 0865 REAL_WRAPPER_CMATH_NUM(erfc, OutOfDomain) 0866 REAL_WRAPPER_CMATH_NUM(gamma, NotImplemented) 0867 REAL_WRAPPER_CMATH_NUM(lnGamma, NotImplemented) 0868 // CMath PROBABILITY 0869 REAL_WRAPPER_CMATH_NUM_NUM(nCr, OutOfDomain) 0870 REAL_WRAPPER_CMATH_NUM_NUM(nPr, OutOfDomain) 0871 REAL_WRAPPER_CMATH_NUM_NUM_NUM(binomialPmf, OutOfDomain) 0872 REAL_WRAPPER_CMATH_NUM_NUM_NUM(binomialCdf, OutOfDomain) 0873 REAL_WRAPPER_CMATH_NUM_NUM(binomialMean, OutOfDomain) 0874 REAL_WRAPPER_CMATH_NUM_NUM(binomialVariance, OutOfDomain) 0875 REAL_WRAPPER_CMATH_NUM_NUM_NUM_NUM(hypergeometricPmf, OutOfDomain) 0876 REAL_WRAPPER_CMATH_NUM_NUM_NUM_NUM(hypergeometricCdf, OutOfDomain) 0877 REAL_WRAPPER_CMATH_NUM_NUM_NUM(hypergeometricMean, OutOfDomain) 0878 REAL_WRAPPER_CMATH_NUM_NUM_NUM(hypergeometricVariance, OutOfDomain) 0879 REAL_WRAPPER_CMATH_NUM_NUM(poissonPmf, OutOfDomain) 0880 REAL_WRAPPER_CMATH_NUM_NUM(poissonCdf, OutOfDomain) 0881 REAL_WRAPPER_CMATH_NUM(poissonMean, OutOfDomain) 0882 REAL_WRAPPER_CMATH_NUM(poissonVariance, OutOfDomain) 0883 // CMath LOGIC 0884 REAL_WRAPPER_CMATH_NUM_NUM(mask, OutOfLogicRange) 0885 REAL_WRAPPER_CMATH_NUM_NUM(sgnext, OutOfLogicRange) 0886 REAL_WRAPPER_CMATH_NUM_NUM(ashr, OutOfLogicRange) 0887 0888 // CMath IEEE-754 CONVERSION 0889 REAL_WRAPPER_CMATH_NUM_NUM_NUM(decodeIeee754, OutOfDomain) 0890 REAL_WRAPPER_CMATH_NUM_NUM_NUM_NUM(decodeIeee754, OutOfDomain) 0891 0892 CNumber CMath::encodeIeee754(const CNumber& val, const CNumber& exp_bits, const CNumber& significand_bits, 0893 const CNumber& exp_bias) 0894 { 0895 ENSURE_REAL(exp_bits, OutOfDomain); 0896 ENSURE_REAL(significand_bits, OutOfDomain); 0897 ENSURE_REAL(exp_bias, OutOfDomain); 0898 if (!val.isNan() && !val.isNearReal()) 0899 return CMath::nan(OutOfDomain); 0900 return CNumber(HMath::encodeIeee754(val.real, exp_bits.real, significand_bits.real, exp_bias.real)); 0901 } 0902 0903 CNumber CMath::encodeIeee754(const CNumber& val, const CNumber& exp_bits, const CNumber& significand_bits) 0904 { 0905 ENSURE_REAL(exp_bits, OutOfDomain); 0906 ENSURE_REAL(significand_bits, OutOfDomain); 0907 if (!val.isNan() && !val.isNearReal()) 0908 return CMath::nan(OutOfDomain); 0909 return CNumber(HMath::encodeIeee754(val.real, exp_bits.real, significand_bits.real)); 0910 }