Skip to content

Commit

Permalink
Support Expression("...").approximate(100).approximate(5)
Browse files Browse the repository at this point in the history
  • Loading branch information
fintarin committed Dec 27, 2023
1 parent 5b96e7d commit 57c54aa
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 8 deletions.
8 changes: 7 additions & 1 deletion include/fintamath/numbers/Real.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class Real : public INumberCRTP<Real> {

const Backend &getBackend() const;

unsigned getOutputPrecision() const;

void setOutputPrecision(unsigned precision);

static unsigned getCalculationPrecision();

static unsigned getPrecision();
Expand Down Expand Up @@ -84,10 +88,12 @@ class Real : public INumberCRTP<Real> {

void updatePrecision(const Real &rhs);

void validateNewPrecision(unsigned precision) const;

private:
Backend backend;

unsigned currentPrecision = Real::getPrecision();
unsigned outputPrecision = Real::getPrecision();

bool isNegative = false;
};
Expand Down
7 changes: 7 additions & 0 deletions src/fintamath/expressions/IExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ void IExpression::approximateSimplifyChild(ArgumentPtr &child) {
if (const auto constChild = cast<IConstant>(child)) {
child = (*constChild)();
}
else if (const auto realChild = cast<Real>(child)) {
if (realChild->getOutputPrecision() > Real::getPrecision()) {
auto newRealChild = cast<Real>(realChild->clone());
newRealChild->setOutputPrecision(Real::getPrecision());
child = std::move(newRealChild);
}
}
else if (const auto exprChild = cast<IExpression>(child)) {
child = exprChild->approximateSimplify();
}
Expand Down
27 changes: 20 additions & 7 deletions src/fintamath/numbers/Real.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Real::Real(int64_t val) : backend(val),
}

std::string Real::toString() const {
std::string res = toString(currentPrecision);
std::string res = toString(outputPrecision);

if (isNegative && res.front() != '-') {
res.insert(res.begin(), '-');
Expand All @@ -72,11 +72,7 @@ std::string Real::toString() const {
}

std::string Real::toString(unsigned precision) const {
if (precision > currentPrecision) {
// TODO: use std::format
throw InvalidInputException("Precision must be less than or equal to " +
std::to_string(currentPrecision));
}
validateNewPrecision(precision);

if (precision == 0) {
precision++;
Expand Down Expand Up @@ -132,6 +128,15 @@ const Real::Backend &Real::getBackend() const {
return backend;
}

unsigned Real::getOutputPrecision() const {
return outputPrecision;
}

void Real::setOutputPrecision(unsigned precision) {
validateNewPrecision(precision);
outputPrecision = precision;
}

unsigned Real::getCalculationPrecision() {
return Backend::thread_default_precision();
}
Expand Down Expand Up @@ -217,7 +222,15 @@ bool Real::isFinite() const {
}

void Real::updatePrecision(const Real &rhs) {
currentPrecision = std::min(currentPrecision, rhs.currentPrecision);
outputPrecision = std::min(outputPrecision, rhs.outputPrecision);
}

void Real::validateNewPrecision(unsigned precision) const {
if (precision > outputPrecision) {
// TODO: use std::format
throw InvalidInputException("Precision must be less than or equal to " +
std::to_string(outputPrecision));
}
}

Real::ScopedSetPrecision::ScopedSetPrecision(unsigned precision) {
Expand Down
13 changes: 13 additions & 0 deletions tests/src/expressions/ExpressionTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2495,6 +2495,19 @@ TEST(ExpressionTests, approximateTest) {
EXPECT_EQ(Expression("x/2^200").approximate(10).toString(), "6.223015278*10^-61 x");
EXPECT_EQ(Expression("(sqrt(2) - a - 1)^2").approximate(5).toString(), "a^2 - 0.82843 a + 0.17157");
EXPECT_EQ(Expression("2 sqrt2 sin3 a + 3 ln5 root(2, 3) b").approximate(5).toString(), "0.39915 a + 6.0833 b");

EXPECT_EQ(Expression("sin(5)").approximate(100).approximate(5).toString(), "-0.95892");

{
Expression expr = Expression("cos(5)").approximate(56);
EXPECT_EQ(expr.toString(), "0.28366218546322626446663917151355730833442259225221594493");

expr = expr.approximate(55);
EXPECT_EQ(expr.toString(), "0.2836621854632262644666391715135573083344225922522159449");

expr = expr.approximate(1);
EXPECT_EQ(expr.toString(), "0.3");
}
}

TEST(ExpressionTests, toMinimalObjectTest) {
Expand Down
120 changes: 120 additions & 0 deletions tests/src/numbers/RealTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,126 @@ TEST(RealTests, toStringPrecisionPrecisionTest) {
EXPECT_THROW(val.toString(20), InvalidInputException);
}

TEST(RealTests, getOutputPrecisionTest) {
EXPECT_EQ(Real().getOutputPrecision(), Real::getPrecision());
}

TEST(RealTests, setOutputPrecisionTest) {
Real a;
EXPECT_EQ(a.getOutputPrecision(), Real::getPrecision());

a.setOutputPrecision(10);
EXPECT_EQ(a.getOutputPrecision(), 10);

a.setOutputPrecision(5);
EXPECT_EQ(a.getOutputPrecision(), 5);

a.setOutputPrecision(5);
EXPECT_EQ(a.getOutputPrecision(), 5);

EXPECT_THROW(a.setOutputPrecision(6), InvalidInputException);
EXPECT_THROW(a.setOutputPrecision(10), InvalidInputException);
}

TEST(RealTests, updatePrecisionTest) {
{
Real a = 1;
a.setOutputPrecision(10);

Real b = 1;
b.setOutputPrecision(5);

a += b;

EXPECT_EQ(a.getOutputPrecision(), 5);
EXPECT_EQ(b.getOutputPrecision(), 5);
}
{
Real a = 1;
a.setOutputPrecision(10);

Real b = 1;
b.setOutputPrecision(5);

b += a;

EXPECT_EQ(a.getOutputPrecision(), 10);
EXPECT_EQ(b.getOutputPrecision(), 5);
}
{
Real a = 1;
a.setOutputPrecision(10);

Real b = 1;
b.setOutputPrecision(5);

a -= b;

EXPECT_EQ(a.getOutputPrecision(), 5);
EXPECT_EQ(b.getOutputPrecision(), 5);
}
{
Real a = 1;
a.setOutputPrecision(10);

Real b = 1;
b.setOutputPrecision(5);

b -= a;

EXPECT_EQ(a.getOutputPrecision(), 10);
EXPECT_EQ(b.getOutputPrecision(), 5);
}
{
Real a = 1;
a.setOutputPrecision(10);

Real b = 1;
b.setOutputPrecision(5);

a *= b;

EXPECT_EQ(a.getOutputPrecision(), 5);
EXPECT_EQ(b.getOutputPrecision(), 5);
}
{
Real a = 1;
a.setOutputPrecision(10);

Real b = 1;
b.setOutputPrecision(5);

b *= a;

EXPECT_EQ(a.getOutputPrecision(), 10);
EXPECT_EQ(b.getOutputPrecision(), 5);
}
{
Real a = 1;
a.setOutputPrecision(10);

Real b = 1;
b.setOutputPrecision(5);

a /= b;

EXPECT_EQ(a.getOutputPrecision(), 5);
EXPECT_EQ(b.getOutputPrecision(), 5);
}
{
Real a = 1;
a.setOutputPrecision(10);

Real b = 1;
b.setOutputPrecision(5);

b /= a;

EXPECT_EQ(a.getOutputPrecision(), 10);
EXPECT_EQ(b.getOutputPrecision(), 5);
}
}

TEST(RealTests, getPrecisionTest) {
EXPECT_EQ(Real::getPrecision(), 80);
}
Expand Down

0 comments on commit 57c54aa

Please sign in to comment.