diff --git a/include/fintamath/expressions/ExpressionFunctions.hpp b/include/fintamath/expressions/ExpressionFunctions.hpp index a3795556d..4785f27c1 100644 --- a/include/fintamath/expressions/ExpressionFunctions.hpp +++ b/include/fintamath/expressions/ExpressionFunctions.hpp @@ -105,6 +105,6 @@ Expression complexInf(); Expression solve(const Expression &rhs); -extern Expression approximate(const Expression &rhs, unsigned precision = Real::getPrecision()); +extern Expression approximate(const Expression &rhs, unsigned precision = Real::getPrecisionStatic()); } diff --git a/include/fintamath/numbers/Complex.hpp b/include/fintamath/numbers/Complex.hpp index 0943f924a..681ca01e5 100644 --- a/include/fintamath/numbers/Complex.hpp +++ b/include/fintamath/numbers/Complex.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "fintamath/core/IMathObject.hpp" @@ -48,7 +49,7 @@ class Complex : public INumberCRTP { std::unique_ptr toMinimalObject() const override; - bool isPrecise() const noexcept override; + std::optional getPrecision() const noexcept override; bool isComplex() const noexcept override; diff --git a/include/fintamath/numbers/INumber.hpp b/include/fintamath/numbers/INumber.hpp index 8085e76c8..0d83304b4 100644 --- a/include/fintamath/numbers/INumber.hpp +++ b/include/fintamath/numbers/INumber.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -17,8 +18,8 @@ class INumber : public IComparable { FINTAMATH_PARENT_CLASS_BODY(INumber, IComparable) public: - virtual bool isPrecise() const noexcept { - return true; + virtual std::optional getPrecision() const noexcept { + return {}; } virtual bool isComplex() const noexcept { diff --git a/include/fintamath/numbers/Real.hpp b/include/fintamath/numbers/Real.hpp index 2cf26ca5b..89d704de4 100644 --- a/include/fintamath/numbers/Real.hpp +++ b/include/fintamath/numbers/Real.hpp @@ -27,7 +27,7 @@ class Real : public INumberCRTP { using Backend = boost::multiprecision::mpfr_float; struct ScopedSetPrecision final { - unsigned currPrecision = getPrecision(); + unsigned currPrecision = getPrecisionStatic(); public: explicit ScopedSetPrecision(unsigned precision); @@ -56,8 +56,6 @@ class Real : public INumberCRTP { std::string toString(unsigned precision) const; - bool isPrecise() const noexcept override; - int sign() const; bool isZero() const; @@ -68,15 +66,15 @@ class Real : public INumberCRTP { const Backend &getBackend() const noexcept; - unsigned getOutputPrecision() const noexcept; + std::optional getPrecision() const noexcept override; - void setOutputPrecision(unsigned precision); + void setPrecision(unsigned precision); - static unsigned getCalculationPrecision() noexcept; + static unsigned getCalculationPrecisionStatic() noexcept; - static unsigned getPrecision() noexcept; + static unsigned getPrecisionStatic() noexcept; - static void setPrecision(unsigned precision); + static void setPrecisionStatic(unsigned precision); protected: bool equals(const Real &rhs) const override; @@ -107,7 +105,7 @@ class Real : public INumberCRTP { private: Backend backend; - unsigned outputPrecision = getPrecision(); + unsigned outputPrecision = getPrecisionStatic(); }; } diff --git a/src/fintamath/config/PrecisionConfig.cpp b/src/fintamath/config/PrecisionConfig.cpp index a787376da..997691dd3 100644 --- a/src/fintamath/config/PrecisionConfig.cpp +++ b/src/fintamath/config/PrecisionConfig.cpp @@ -6,7 +6,7 @@ namespace fintamath::detail { PrecisionConfig::PrecisionConfig() { constexpr unsigned defaultPrecision = 20; - Real::setPrecision(defaultPrecision); + Real::setPrecisionStatic(defaultPrecision); } } diff --git a/src/fintamath/expressions/IExpression.cpp b/src/fintamath/expressions/IExpression.cpp index 90bc34430..737a3e08d 100644 --- a/src/fintamath/expressions/IExpression.cpp +++ b/src/fintamath/expressions/IExpression.cpp @@ -110,7 +110,7 @@ void IExpression::preSimplifyChild(ArgumentPtr &child) { if (const auto constChild = cast(child)) { const ArgumentPtr constVal = (*constChild)(); - if (const auto num = cast(constVal); num && !num->isPrecise()) { + if (const auto num = cast(constVal); num && num->getPrecision()) { child = constChild; } else { @@ -205,7 +205,7 @@ std::unique_ptr IExpression::convertToApproximated(const INumber &num, const Integer & /*inPrecision*/, const Integer & /*inMaxInt*/) { auto res = cast(inRhs.clone()); - res->setOutputPrecision(Real::getPrecision()); + res->setPrecision(Real::getPrecisionStatic()); return res; }); @@ -261,7 +261,7 @@ ArgumentPtr IExpression::callFunction(const IFunction &func, const ArgumentPtrVe for (const auto &argPtr : argPtrs) { args.emplace_back(*argPtr); - if (const auto num = cast(argPtr); num && !num->isPrecise()) { + if (const auto num = cast(argPtr); num && num->getPrecision()) { areArgumentsPrecise = false; } } @@ -273,7 +273,7 @@ ArgumentPtr IExpression::callFunction(const IFunction &func, const ArgumentPtrVe ArgumentPtr res = func(args); if (areArgumentsPrecise) { - if (const auto num = cast(res); num && !num->isPrecise()) { + if (const auto num = cast(res); num && num->getPrecision()) { return {}; } } @@ -309,7 +309,7 @@ ArgumentPtr IExpression::approximate() const { if (const auto childNum = cast(child)) { numberChildrenCount++; - if (!childNum->isPrecise()) { + if (childNum->getPrecision()) { areNumberChilrenPrecise = false; } } diff --git a/src/fintamath/functions/logarithms/Log.cpp b/src/fintamath/functions/logarithms/Log.cpp index 2c7fb4370..cea857a33 100644 --- a/src/fintamath/functions/logarithms/Log.cpp +++ b/src/fintamath/functions/logarithms/Log.cpp @@ -57,7 +57,7 @@ std::unique_ptr Log::call(const ArgumentRefVector &argVect) const { return Integer(0).clone(); } - if (lhs == rhs && lhs.isPrecise()) { + if (lhs == rhs && !lhs.getPrecision()) { return Integer(1).clone(); } diff --git a/src/fintamath/numbers/Complex.cpp b/src/fintamath/numbers/Complex.cpp index 42c67a77a..e6381d99c 100644 --- a/src/fintamath/numbers/Complex.cpp +++ b/src/fintamath/numbers/Complex.cpp @@ -120,8 +120,23 @@ std::unique_ptr Complex::toMinimalObject() const { return clone(); } -bool Complex::isPrecise() const noexcept { - return !is(re) && !is(im); +std::optional Complex::getPrecision() const noexcept { + std::optional rePrecision = re->getPrecision(); + std::optional imPrecision = im->getPrecision(); + + if (rePrecision && imPrecision) { + return std::min(*rePrecision, *imPrecision); + } + + if (rePrecision) { + return *rePrecision; + } + + if (imPrecision) { + return *imPrecision; + } + + return {}; } bool Complex::isComplex() const noexcept { diff --git a/src/fintamath/numbers/NumberAbstract.cpp b/src/fintamath/numbers/NumberAbstract.cpp index df5cf4655..79e318d1d 100644 --- a/src/fintamath/numbers/NumberAbstract.cpp +++ b/src/fintamath/numbers/NumberAbstract.cpp @@ -54,7 +54,7 @@ std::unique_ptr Rational::divideAbstract(const IArithmetic &rhs) co //-------------------------------------------------------------------------------------// bool Real::equalsAbstract(const IMathObject &rhs) const { - if (const auto *rhsNum = cast(&rhs); rhsNum && rhsNum->isPrecise()) { + if (const auto *rhsNum = cast(&rhs); rhsNum && !rhsNum->getPrecision()) { return false; } @@ -65,7 +65,7 @@ std::strong_ordering Real::compareAbstract(const IComparable &rhs) const { const auto res = INumberCRTP::compareAbstract(rhs); if (res == std::strong_ordering::equal) { - if (const auto *rhsNum = cast(&rhs); rhsNum && rhsNum->isPrecise()) { + if (const auto *rhsNum = cast(&rhs); rhsNum && !rhsNum->getPrecision()) { return sign() != 0 ? sign() <=> 0 : std::strong_ordering::greater; } } diff --git a/src/fintamath/numbers/Real.cpp b/src/fintamath/numbers/Real.cpp index 571f850b3..b2925cfba 100644 --- a/src/fintamath/numbers/Real.cpp +++ b/src/fintamath/numbers/Real.cpp @@ -124,10 +124,6 @@ std::string Real::toString(unsigned precision) const { return str; } -bool Real::isPrecise() const noexcept { - return false; -} - int Real::sign() const { if (mpfr_signbit(backend.backend().data())) { return -1; @@ -152,24 +148,24 @@ const Real::Backend &Real::getBackend() const noexcept { return backend; } -unsigned Real::getOutputPrecision() const noexcept { +std::optional Real::getPrecision() const noexcept { return outputPrecision; } -void Real::setOutputPrecision(const unsigned precision) { +void Real::setPrecision(const unsigned precision) { assert(precision <= outputPrecision); outputPrecision = precision; } -unsigned Real::getCalculationPrecision() noexcept { +unsigned Real::getCalculationPrecisionStatic() noexcept { return Backend::thread_default_precision(); } -unsigned Real::getPrecision() noexcept { - return (getCalculationPrecision() - precisionDelta) / precisionMultiplier; +unsigned Real::getPrecisionStatic() noexcept { + return (getCalculationPrecisionStatic() - precisionDelta) / precisionMultiplier; } -void Real::setPrecision(unsigned precision) { +void Real::setPrecisionStatic(unsigned precision) { if (precision == 0) { precision++; } @@ -258,11 +254,11 @@ void Real::updatePrecision(const Real &rhs) { } Real::ScopedSetPrecision::ScopedSetPrecision(const unsigned precision) { - setPrecision(precision); + setPrecisionStatic(precision); } Real::ScopedSetPrecision::~ScopedSetPrecision() { - setPrecision(currPrecision); + setPrecisionStatic(currPrecision); } } diff --git a/src/fintamath/numbers/RealFunctions.cpp b/src/fintamath/numbers/RealFunctions.cpp index 96e7a9653..6837faaa2 100644 --- a/src/fintamath/numbers/RealFunctions.cpp +++ b/src/fintamath/numbers/RealFunctions.cpp @@ -29,7 +29,7 @@ bool isOverflow(const Real &rhs) { return pow(powBase, precision); }); - return abs(rhs) > cache[Real::getPrecision()]; + return abs(rhs) > cache[Real::getPrecisionStatic()]; } bool isUnderflow(const Real &rhs) { @@ -38,7 +38,7 @@ bool isUnderflow(const Real &rhs) { return 1 / pow(powBase, precision); }); - return !rhs.isZero() && abs(rhs) < cache[Real::getPrecision()]; + return !rhs.isZero() && abs(rhs) < cache[Real::getPrecisionStatic()]; } bool isLogUnderflow(const Real &rhs) { @@ -46,7 +46,7 @@ bool isLogUnderflow(const Real &rhs) { return 1 / pow(precision, getE().getBackend()); }); - return !rhs.isZero() && abs(rhs) < cache[Real::getPrecision()]; + return !rhs.isZero() && abs(rhs) < cache[Real::getPrecisionStatic()]; } std::string getExceptionMessage(const std::string_view message) { @@ -517,7 +517,7 @@ const Real &getE() { return Real(res); }); - return cache[Real::getCalculationPrecision()]; + return cache[Real::getCalculationPrecisionStatic()]; } const Real &getPi() { @@ -527,7 +527,7 @@ const Real &getPi() { return Real(res); }); - return cache[Real::getCalculationPrecision()]; + return cache[Real::getCalculationPrecisionStatic()]; } } diff --git a/tests/src/numbers/ComplexTests.cpp b/tests/src/numbers/ComplexTests.cpp index f87390887..9bf955a14 100644 --- a/tests/src/numbers/ComplexTests.cpp +++ b/tests/src/numbers/ComplexTests.cpp @@ -975,13 +975,27 @@ TEST(ComplexTests, simplifyTest) { EXPECT_EQ(Complex(Real("5.2"), Integer(0)).toMinimalObject()->toString(), "5.2"); } -TEST(ComplexTests, isPreciseTest) { - EXPECT_TRUE(Complex(1, 2).isPrecise()); - EXPECT_TRUE(Complex(Rational(1, 2), Rational(1, 2)).isPrecise()); - - EXPECT_FALSE(Complex(Real(1), Real(1)).isPrecise()); - EXPECT_FALSE(Complex(Real(1), Integer(1)).isPrecise()); - EXPECT_FALSE(Complex(Integer(1), Real(1)).isPrecise()); +TEST(ComplexTests, getPrecisionTest) { + EXPECT_FALSE(Complex(1, 2).getPrecision()); + EXPECT_FALSE(Complex(Rational(1, 2), Rational(1, 2)).getPrecision()); + + EXPECT_EQ(*Complex(Real(1), Real(1)).getPrecision(), Real::getPrecisionStatic()); + EXPECT_EQ(*Complex(Real(1), Integer(1)).getPrecision(), Real::getPrecisionStatic()); + EXPECT_EQ(*Complex(Integer(1), Real(1)).getPrecision(), Real::getPrecisionStatic()); + + { + Real a = 1; + Real b = 2; + a.setPrecision(5); + EXPECT_EQ(*Complex(a, b).getPrecision(), 5); + } + + { + Real a = 1; + Real b = 2; + b.setPrecision(5); + EXPECT_EQ(*Complex(a, b).getPrecision(), 5); + } } TEST(ComplexTests, isComplexTest) { diff --git a/tests/src/numbers/IntegerTests.cpp b/tests/src/numbers/IntegerTests.cpp index 0ee965239..fdfca9f87 100644 --- a/tests/src/numbers/IntegerTests.cpp +++ b/tests/src/numbers/IntegerTests.cpp @@ -615,8 +615,8 @@ TEST(IntegerTests, intOperatorTest) { EXPECT_EQ(static_cast(Integer("-100000000000000000000000000000000000000000000000000")) + 1, -9223372036854775807); } -TEST(IntegerTests, isPreciseTest) { - EXPECT_TRUE(Integer(1).isPrecise()); +TEST(IntegerTests, getPrecisionTest) { + EXPECT_FALSE(Integer(1).getPrecision()); } TEST(IntegerTests, isComplexTest) { diff --git a/tests/src/numbers/RationalTests.cpp b/tests/src/numbers/RationalTests.cpp index 5df353a0f..a3e0b1b3f 100644 --- a/tests/src/numbers/RationalTests.cpp +++ b/tests/src/numbers/RationalTests.cpp @@ -556,8 +556,8 @@ TEST(RationalTests, signTest) { EXPECT_EQ(Rational(2).sign(), 1); } -TEST(RationalTests, isPreciseTest) { - EXPECT_TRUE(Rational(1, 2).isPrecise()); +TEST(RationalTests, getPrecisionTest) { + EXPECT_FALSE(Rational(1, 2).getPrecision()); } TEST(RationalTests, isComplexTest) { diff --git a/tests/src/numbers/RealTests.cpp b/tests/src/numbers/RealTests.cpp index bd449f3ae..cba5b3be3 100644 --- a/tests/src/numbers/RealTests.cpp +++ b/tests/src/numbers/RealTests.cpp @@ -947,153 +947,153 @@ TEST(RealTests, toStringPrecisionPrecisionTest) { EXPECT_DEBUG_DEATH(val.toString(20), ""); } -TEST(RealTests, getOutputPrecisionTest) { - EXPECT_EQ(Real().getOutputPrecision(), Real::getPrecision()); +TEST(RealTests, getPrecisionTest) { + EXPECT_EQ(Real().getPrecision(), Real::getPrecisionStatic()); } -TEST(RealTests, setOutputPrecisionTest) { +TEST(RealTests, setPrecisionTest) { Real a; - EXPECT_EQ(a.getOutputPrecision(), Real::getPrecision()); + EXPECT_EQ(a.getPrecision(), Real::getPrecisionStatic()); - a.setOutputPrecision(10); - EXPECT_EQ(a.getOutputPrecision(), 10); + a.setPrecision(10); + EXPECT_EQ(a.getPrecision(), 10); - a.setOutputPrecision(5); - EXPECT_EQ(a.getOutputPrecision(), 5); + a.setPrecision(5); + EXPECT_EQ(a.getPrecision(), 5); - a.setOutputPrecision(5); - EXPECT_EQ(a.getOutputPrecision(), 5); + a.setPrecision(5); + EXPECT_EQ(a.getPrecision(), 5); - EXPECT_DEBUG_DEATH(a.setOutputPrecision(6), ""); - EXPECT_DEBUG_DEATH(a.setOutputPrecision(10), ""); + EXPECT_DEBUG_DEATH(a.setPrecision(6), ""); + EXPECT_DEBUG_DEATH(a.setPrecision(10), ""); } TEST(RealTests, updatePrecisionTest) { { Real a = 1; - a.setOutputPrecision(10); + a.setPrecision(10); Real b = 1; - b.setOutputPrecision(5); + b.setPrecision(5); a += b; - EXPECT_EQ(a.getOutputPrecision(), 5); - EXPECT_EQ(b.getOutputPrecision(), 5); + EXPECT_EQ(*a.getPrecision(), 5); + EXPECT_EQ(*b.getPrecision(), 5); } { Real a = 1; - a.setOutputPrecision(10); + a.setPrecision(10); Real b = 1; - b.setOutputPrecision(5); + b.setPrecision(5); b += a; - EXPECT_EQ(a.getOutputPrecision(), 10); - EXPECT_EQ(b.getOutputPrecision(), 5); + EXPECT_EQ(*a.getPrecision(), 10); + EXPECT_EQ(*b.getPrecision(), 5); } { Real a = 1; - a.setOutputPrecision(10); + a.setPrecision(10); Real b = 1; - b.setOutputPrecision(5); + b.setPrecision(5); a -= b; - EXPECT_EQ(a.getOutputPrecision(), 5); - EXPECT_EQ(b.getOutputPrecision(), 5); + EXPECT_EQ(*a.getPrecision(), 5); + EXPECT_EQ(*b.getPrecision(), 5); } { Real a = 1; - a.setOutputPrecision(10); + a.setPrecision(10); Real b = 1; - b.setOutputPrecision(5); + b.setPrecision(5); b -= a; - EXPECT_EQ(a.getOutputPrecision(), 10); - EXPECT_EQ(b.getOutputPrecision(), 5); + EXPECT_EQ(*a.getPrecision(), 10); + EXPECT_EQ(*b.getPrecision(), 5); } { Real a = 1; - a.setOutputPrecision(10); + a.setPrecision(10); Real b = 1; - b.setOutputPrecision(5); + b.setPrecision(5); a *= b; - EXPECT_EQ(a.getOutputPrecision(), 5); - EXPECT_EQ(b.getOutputPrecision(), 5); + EXPECT_EQ(*a.getPrecision(), 5); + EXPECT_EQ(*b.getPrecision(), 5); } { Real a = 1; - a.setOutputPrecision(10); + a.setPrecision(10); Real b = 1; - b.setOutputPrecision(5); + b.setPrecision(5); b *= a; - EXPECT_EQ(a.getOutputPrecision(), 10); - EXPECT_EQ(b.getOutputPrecision(), 5); + EXPECT_EQ(*a.getPrecision(), 10); + EXPECT_EQ(*b.getPrecision(), 5); } { Real a = 1; - a.setOutputPrecision(10); + a.setPrecision(10); Real b = 1; - b.setOutputPrecision(5); + b.setPrecision(5); a /= b; - EXPECT_EQ(a.getOutputPrecision(), 5); - EXPECT_EQ(b.getOutputPrecision(), 5); + EXPECT_EQ(*a.getPrecision(), 5); + EXPECT_EQ(*b.getPrecision(), 5); } { Real a = 1; - a.setOutputPrecision(10); + a.setPrecision(10); Real b = 1; - b.setOutputPrecision(5); + b.setPrecision(5); b /= a; - EXPECT_EQ(a.getOutputPrecision(), 10); - EXPECT_EQ(b.getOutputPrecision(), 5); + EXPECT_EQ(*a.getPrecision(), 10); + EXPECT_EQ(*b.getPrecision(), 5); } } -TEST(RealTests, getPrecisionTest) { - EXPECT_EQ(Real::getPrecision(), 20); +TEST(RealTests, getPrecisionStaticTest) { + EXPECT_EQ(Real::getPrecisionStatic(), 20); } -TEST(RealTests, getCalculationPrecisionTest) { - EXPECT_EQ(Real::getCalculationPrecision(), 50); +TEST(RealTests, getCalculationPrecisionStaticTest) { + EXPECT_EQ(Real::getCalculationPrecisionStatic(), 50); } -TEST(RealTests, setPrecisionTest) { - const unsigned currPrecision = Real::getPrecision(); +TEST(RealTests, setPrecisionStaticTest) { + const unsigned currPrecision = Real::getPrecisionStatic(); - Real::setPrecision(10); - EXPECT_EQ(Real::getPrecision(), 10); + Real::setPrecisionStatic(10); + EXPECT_EQ(Real::getPrecisionStatic(), 10); - Real::setPrecision(currPrecision); - EXPECT_EQ(Real::getPrecision(), 20); + Real::setPrecisionStatic(currPrecision); + EXPECT_EQ(Real::getPrecisionStatic(), 20); } TEST(RealTests, scopedSetPrecisionTest) { - const unsigned currPrecision = Real::getPrecision(); + const unsigned currPrecision = Real::getPrecisionStatic(); { Real::ScopedSetPrecision setPrecision(123); - EXPECT_EQ(Real::getPrecision(), 123); + EXPECT_EQ(Real::getPrecisionStatic(), 123); } - EXPECT_EQ(Real::getPrecision(), currPrecision); + EXPECT_EQ(Real::getPrecisionStatic(), currPrecision); } TEST(RealTests, signTest) { @@ -1126,10 +1126,6 @@ TEST(RealTests, isNegZeroTest) { EXPECT_FALSE(Real("-1").isNegZero()); } -TEST(RealTests, isPreciseTest) { - EXPECT_FALSE(Real(2).isPrecise()); -} - TEST(RealTests, isComplexTest) { EXPECT_FALSE(Real(2).isComplex()); }