File indexing completed on 2024-05-12 17:22:29

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 }