Smart rounding settings

TO SUPPORT MY WORK, ORDER A COMMERCIAL LICENSE
THANK YOU!

The tutorial consists of more than 200 live examples from 50 sections given separately for JAVA, C# and C++. Each of the examples can be copied and run on your own environment. In addition, mXparser provides an extensive collection of over 500 built-in math functions, expressions and symbols. Familiarize yourself with the scope and the syntax. Live testing is the best way to learn. Good luck! 🙂

Tutorial Math Collection API spec Download

Below is the code for JAVA, C# (the code for C# is almost identical) and C++. To copy the code, double-click inside the frame.

A few words on Floating Point Math

0.1+0.1+0.1 is the most famous example that surprises even many experienced programmers – take a look at the code and its result. Run this code in JAVA or .NET, or just about any other programming language that supports floating point numbers.

Java/C# code
double a = 0.1;
double b = 0.1;
double c = 0.1;
double d = a + b + c;
mXparser.consolePrintln("d = " + d);
d = 0.30000000000000004
C++ code
double a = 0.1;
double b = 0.1;
double c = 0.1;
double d = a + b + c;
mXparser_consolePrintln("d-0.3 = " + (d-0.3));
d-0.3 = 0.00000000000000005551115123125783

Why is this happening? This is the result of representing a floating point decimal number (varying in scale and precision) using the binary system. Everything is well described in the IEEE 754 standard. Another great explanation delivers the 0.30000000000000004.com website.

Why mXparser is based on the double data type?

Despite the problem mentioned above, the double type is extremely flexible.

  • It allows to work with very small numbers as well as with very large numbers. The double type is therefore great for scientific applications.
  • In addition, standard mathematical libraries are the richest in API-s when the double data type is considered.
  • Another important element is the full multi-platform compatibility of the double – e.g. double is supported in the same way by JAVA and .NET (this is very different e.g. in the case of BigDecimal).

mXparser is cross-platform and scientific application-oriented – therefore double was selected.

Smart rounding options available in mXparser

In order not to lose the flexibility of double, and to remedy a large proportion of unwanted problems like 0.1 + 0.1 + 0.1, mXparser provides three interesting automatic rounding options for partial and final results:

  • Almost Integer Rounding – a number is rounded to the nearest integer if it is close enough to an integer. This is a fairly quick procedure, but you lose the ability to work with small numbers.
  • Unit In The Last Place Rounding – depending on the size of the number represented by double, its density changes in the last place of the precision. The ULP rounding identifies the minimum unit at the “end” and rounds the result to considering this precision. It is a moderately quick procedure, it works for many cases, but you will easily find a number of scenarios where the effect is not satisfactory.
  • Canonical Rounding – trying to do many different things at once, including going through BigDecimal / decimal classes and String data. It solves a huge part of the problem, but comes at a cost in computing performance.

Case 1: Check which rounding settings are currently active

Java/C# code
// JAVA: import org.mariuszgromada.math.mxparser.*;
// C#: using org.mariuszgromada.math.mxparser;
// ...
mXparser.consolePrintln("checkIfAlmostIntRounding = " + mXparser.checkIfAlmostIntRounding());
mXparser.consolePrintln("checkIfUlpRounding = " + mXparser.checkIfUlpRounding());
mXparser.consolePrintln("checkIfCanonicalRounding = " + mXparser.checkIfCanonicalRounding());
C++ code
#include "org/mariuszgromada/math/mxparser.hpp"
// ...
mXparser_consolePrintln("checkIfAlmostIntRounding = " + mXparser::checkIfAlmostIntRounding());
mXparser_consolePrintln("checkIfUlpRounding = " + mXparser::checkIfUlpRounding());
mXparser_consolePrintln("checkIfCanonicalRounding = " + mXparser::checkIfCanonicalRounding());
Code result
[mXparser-v.5.2.1] checkIfAlmostIntRounding = true
[mXparser-v.5.2.1] checkIfUlpRounding = false
[mXparser-v.5.2.1] checkIfCanonicalRounding = true

Case 2: Only Canonical Rounding option is active

Java/C# code
// JAVA: import org.mariuszgromada.math.mxparser.*;
// C#: using org.mariuszgromada.math.mxparser;
// ...
mXparser.disableAlmostIntRounding();
mXparser.disableUlpRounding();
mXparser.enableCanonicalRounding();

mXparser.consolePrintln("checkIfAlmostIntRounding = " + mXparser.checkIfAlmostIntRounding());
mXparser.consolePrintln("checkIfUlpRounding = " + mXparser.checkIfUlpRounding());
mXparser.consolePrintln("checkIfCanonicalRounding = " + mXparser.checkIfCanonicalRounding());
mXparser.consolePrintln("-------------------");

Expression e1 = new Expression("0.1 + 0.1 + 0.1");
Expression e2 = new Expression("2.5 - 2.2");
Expression e3 = new Expression("0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1");
Expression e4 = new Expression("5.55 / 5");
Expression e5 = new Expression("(1/6.2)^(-3)");

mXparser.consolePrintln(e1.getExpressionString() + " = " + e1.calculate());
mXparser.consolePrintln(e2.getExpressionString() + " = " + e2.calculate());
mXparser.consolePrintln(e3.getExpressionString() + " = " + e3.calculate());
mXparser.consolePrintln(e4.getExpressionString() + " = " + e4.calculate());
mXparser.consolePrintln(e5.getExpressionString() + " = " + e5.calculate());
C++ code
#include "org/mariuszgromada/math/mxparser.hpp"
// ...
mXparser::disableAlmostIntRounding();
mXparser::disableUlpRounding();
mXparser::enableCanonicalRounding();

mXparser_consolePrintln("checkIfAlmostIntRounding = " + mXparser::checkIfAlmostIntRounding());
mXparser_consolePrintln("checkIfUlpRounding = " + mXparser::checkIfUlpRounding());
mXparser_consolePrintln("checkIfCanonicalRounding = " + mXparser::checkIfCanonicalRounding());
mXparser_consolePrintln("-------------------");

ExpressionPtr e1 = new_Expression("0.1 + 0.1 + 0.1");
ExpressionPtr e2 = new_Expression("2.5 - 2.2");
ExpressionPtr e3 = new_Expression("0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1");
ExpressionPtr e4 = new_Expression("5.55 / 5");
ExpressionPtr e5 = new_Expression("(1/6.2)^(-3)");

mXparser::consolePrintln(e1->getExpressionString() + " = " + e1->calculate());
mXparser::consolePrintln(e2->getExpressionString() + " = " + e2->calculate());
mXparser::consolePrintln(e3->getExpressionString() + " = " + e3->calculate());
mXparser::consolePrintln(e4->getExpressionString() + " = " + e4->calculate());
mXparser::consolePrintln(e5->getExpressionString() + " = " + e5->calculate());
Code result
[mXparser-v.5.2.1] checkIfAlmostIntRounding = false
[mXparser-v.5.2.1] checkIfUlpRounding = false
[mXparser-v.5.2.1] checkIfCanonicalRounding = true
[mXparser-v.5.2.1] -------------------
[mXparser-v.5.2.1] 0.1 + 0.1 + 0.1 = 0.3
[mXparser-v.5.2.1] 2.5 - 2.2 = 0.3
[mXparser-v.5.2.1] 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 1.0
[mXparser-v.5.2.1] 5.55 / 5 = 1.11
[mXparser-v.5.2.1] (1/6.2)^(-3) = 238.328

Case 3: Only Unit In The Last Place Rounding option is active

Java/C# code
// JAVA: import org.mariuszgromada.math.mxparser.*;
// C#: using org.mariuszgromada.math.mxparser;
// ...
mXparser.disableAlmostIntRounding();
mXparser.enableUlpRounding();
mXparser.disableCanonicalRounding();

mXparser.consolePrintln("checkIfAlmostIntRounding = " + mXparser.checkIfAlmostIntRounding());
mXparser.consolePrintln("checkIfUlpRounding = " + mXparser.checkIfUlpRounding());
mXparser.consolePrintln("checkIfCanonicalRounding = " + mXparser.checkIfCanonicalRounding());
mXparser.consolePrintln("-------------------");

Expression e1 = new Expression("0.1 + 0.1 + 0.1");
Expression e2 = new Expression("2.5 - 2.2");
Expression e3 = new Expression("0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1");
Expression e4 = new Expression("5.55 / 5");
Expression e5 = new Expression("(1/6.2)^(-3)");

mXparser.consolePrintln(e1.getExpressionString() + " = " + e1.calculate());
mXparser.consolePrintln(e2.getExpressionString() + " = " + e2.calculate());
mXparser.consolePrintln(e3.getExpressionString() + " = " + e3.calculate());
mXparser.consolePrintln(e4.getExpressionString() + " = " + e4.calculate());
mXparser.consolePrintln(e5.getExpressionString() + " = " + e5.calculate());
C++ code
#include "org/mariuszgromada/math/mxparser.hpp"
// ...
mXparser::disableAlmostIntRounding();
mXparser::enableUlpRounding();
mXparser::disableCanonicalRounding();

mXparser_consolePrintln("checkIfAlmostIntRounding = " + mXparser::checkIfAlmostIntRounding());
mXparser_consolePrintln("checkIfUlpRounding = " + mXparser::checkIfUlpRounding());
mXparser_consolePrintln("checkIfCanonicalRounding = " + mXparser::checkIfCanonicalRounding());
mXparser_consolePrintln("-------------------");

ExpressionPtr e1 = new_Expression("0.1 + 0.1 + 0.1");
ExpressionPtr e2 = new_Expression("2.5 - 2.2");
ExpressionPtr e3 = new_Expression("0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1");
ExpressionPtr e4 = new_Expression("5.55 / 5");
ExpressionPtr e5 = new_Expression("(1/6.2)^(-3)");

mXparser::consolePrintln(e1->getExpressionString() + " = " + e1->calculate());
mXparser::consolePrintln(e2->getExpressionString() + " = " + e2->calculate());
mXparser::consolePrintln(e3->getExpressionString() + " = " + e3->calculate());
mXparser::consolePrintln(e4->getExpressionString() + " = " + e4->calculate());
mXparser::consolePrintln(e5->getExpressionString() + " = " + e5->calculate());
Code result
[mXparser-v.5.2.1] checkIfAlmostIntRounding = false
[mXparser-v.5.2.1] checkIfUlpRounding = true
[mXparser-v.5.2.1] checkIfCanonicalRounding = false
[mXparser-v.5.2.1] -------------------
[mXparser-v.5.2.1] 0.1 + 0.1 + 0.1 = 0.3
[mXparser-v.5.2.1] 2.5 - 2.2 = 0.2999999999999998
[mXparser-v.5.2.1] 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 1.0
[mXparser-v.5.2.1] 5.55 / 5 = 1.11
[mXparser-v.5.2.1] (1/6.2)^(-3) = 238.3279999999998

Case 4: Only Almost Integer Rounding option is active

Java/C# code
// JAVA: import org.mariuszgromada.math.mxparser.*;
// C#: using org.mariuszgromada.math.mxparser;
// ...
mXparser.enableAlmostIntRounding();
mXparser.disableUlpRounding();
mXparser.disableCanonicalRounding();

mXparser.consolePrintln("checkIfAlmostIntRounding = " + mXparser.checkIfAlmostIntRounding());
mXparser.consolePrintln("checkIfUlpRounding = " + mXparser.checkIfUlpRounding());
mXparser.consolePrintln("checkIfCanonicalRounding = " + mXparser.checkIfCanonicalRounding());
mXparser.consolePrintln("-------------------");

Expression e1 = new Expression("0.1 + 0.1 + 0.1");
Expression e2 = new Expression("2.5 - 2.2");
Expression e3 = new Expression("0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1");
Expression e4 = new Expression("5.55 / 5");
Expression e5 = new Expression("(1/6.2)^(-3)");

mXparser.consolePrintln(e1.getExpressionString() + " = " + e1.calculate());
mXparser.consolePrintln(e2.getExpressionString() + " = " + e2.calculate());
mXparser.consolePrintln(e3.getExpressionString() + " = " + e3.calculate());
mXparser.consolePrintln(e4.getExpressionString() + " = " + e4.calculate());
mXparser.consolePrintln(e5.getExpressionString() + " = " + e5.calculate());
C++ code
#include "org/mariuszgromada/math/mxparser.hpp"
// ...
mXparser::enableAlmostIntRounding();
mXparser::disableUlpRounding();
mXparser::disableCanonicalRounding();

mXparser_consolePrintln("checkIfAlmostIntRounding = " + mXparser::checkIfAlmostIntRounding());
mXparser_consolePrintln("checkIfUlpRounding = " + mXparser::checkIfUlpRounding());
mXparser_consolePrintln("checkIfCanonicalRounding = " + mXparser::checkIfCanonicalRounding());
mXparser_consolePrintln("-------------------");

ExpressionPtr e1 = new_Expression("0.1 + 0.1 + 0.1");
ExpressionPtr e2 = new_Expression("2.5 - 2.2");
ExpressionPtr e3 = new_Expression("0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1");
ExpressionPtr e4 = new_Expression("5.55 / 5");
ExpressionPtr e5 = new_Expression("(1/6.2)^(-3)");

mXparser::consolePrintln(e1->getExpressionString() + " = " + e1->calculate());
mXparser::consolePrintln(e2->getExpressionString() + " = " + e2->calculate());
mXparser::consolePrintln(e3->getExpressionString() + " = " + e3->calculate());
mXparser::consolePrintln(e4->getExpressionString() + " = " + e4->calculate());
mXparser::consolePrintln(e5->getExpressionString() + " = " + e5->calculate());
Code result
[mXparser-v.5.2.1] checkIfAlmostIntRounding = true
[mXparser-v.5.2.1] checkIfUlpRounding = false
[mXparser-v.5.2.1] checkIfCanonicalRounding = false
[mXparser-v.5.2.1] -------------------
[mXparser-v.5.2.1] 0.1 + 0.1 + 0.1 = 0.30000000000000004
[mXparser-v.5.2.1] 2.5 - 2.2 = 0.2999999999999998
[mXparser-v.5.2.1] 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 1.0
[mXparser-v.5.2.1] 5.55 / 5 = 1.1099999999999999
[mXparser-v.5.2.1] (1/6.2)^(-3) = 238.32800000000003

Case 5: None of the rounding options are active

Java/C# code
// JAVA: import org.mariuszgromada.math.mxparser.*;
// C#: using org.mariuszgromada.math.mxparser;
// ...
mXparser.disableAlmostIntRounding();
mXparser.disableUlpRounding();
mXparser.disableCanonicalRounding();

mXparser.consolePrintln("checkIfAlmostIntRounding = " + mXparser.checkIfAlmostIntRounding());
mXparser.consolePrintln("checkIfUlpRounding = " + mXparser.checkIfUlpRounding());
mXparser.consolePrintln("checkIfCanonicalRounding = " + mXparser.checkIfCanonicalRounding());
mXparser.consolePrintln("-------------------");

Expression e1 = new Expression("0.1 + 0.1 + 0.1");
Expression e2 = new Expression("2.5 - 2.2");
Expression e3 = new Expression("0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1");
Expression e4 = new Expression("5.55 / 5");
Expression e5 = new Expression("(1/6.2)^(-3)");

mXparser.consolePrintln(e1.getExpressionString() + " = " + e1.calculate());
mXparser.consolePrintln(e2.getExpressionString() + " = " + e2.calculate());
mXparser.consolePrintln(e3.getExpressionString() + " = " + e3.calculate());
mXparser.consolePrintln(e4.getExpressionString() + " = " + e4.calculate());
mXparser.consolePrintln(e5.getExpressionString() + " = " + e5.calculate());
C++ code
#include "org/mariuszgromada/math/mxparser.hpp"
// ...
mXparser::disableAlmostIntRounding();
mXparser::disableUlpRounding();
mXparser::disableCanonicalRounding();

mXparser_consolePrintln("checkIfAlmostIntRounding = " + mXparser::checkIfAlmostIntRounding());
mXparser_consolePrintln("checkIfUlpRounding = " + mXparser::checkIfUlpRounding());
mXparser_consolePrintln("checkIfCanonicalRounding = " + mXparser::checkIfCanonicalRounding());
mXparser_consolePrintln("-------------------");

ExpressionPtr e1 = new_Expression("0.1 + 0.1 + 0.1");
ExpressionPtr e2 = new_Expression("2.5 - 2.2");
ExpressionPtr e3 = new_Expression("0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1");
ExpressionPtr e4 = new_Expression("5.55 / 5");
ExpressionPtr e5 = new_Expression("(1/6.2)^(-3)");

mXparser::consolePrintln(e1->getExpressionString() + " = " + e1->calculate());
mXparser::consolePrintln(e2->getExpressionString() + " = " + e2->calculate());
mXparser::consolePrintln(e3->getExpressionString() + " = " + e3->calculate());
mXparser::consolePrintln(e4->getExpressionString() + " = " + e4->calculate());
mXparser::consolePrintln(e5->getExpressionString() + " = " + e5->calculate());
Code result
[mXparser-v.5.2.1] checkIfAlmostIntRounding = false
[mXparser-v.5.2.1] checkIfUlpRounding = false
[mXparser-v.5.2.1] checkIfCanonicalRounding = false
[mXparser-v.5.2.1] -------------------
[mXparser-v.5.2.1] 0.1 + 0.1 + 0.1 = 0.30000000000000004
[mXparser-v.5.2.1] 2.5 - 2.2 = 0.2999999999999998
[mXparser-v.5.2.1] 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 0.9999999999999999
[mXparser-v.5.2.1] 5.55 / 5 = 1.1099999999999999
[mXparser-v.5.2.1] (1/6.2)^(-3) = 238.32800000000003
Nuget – Package Manager

Install-Package MathParser.org-mXparser -Version 6.0.0

Nuget – .NET CLI

dotnet add package MathParser.org-mXparser --version 6.0.0

Nuget – Package Reference

<PackageReference Include="MathParser.org-mXparser" Version="6.0.0"/>

Maven – Dependency

<dependency>
<groupid>
org.mariuszgromada.math</groupid>
<artifactid>
MathParser.org-mXparser</artifactid>
<version>
6.0.0</version>
</dependency>

Maven – Gradle

implementation 'org.mariuszgromada.math:MathParser.org-mXparser:6.0.0'

CMake – Dependency / FetchContent

include(FetchContent)
FetchContent_Declare(
MathParserOrgMxParser
GIT_REPOSITORY
https://github.com/mariuszgromada/MathParser.org-mXparser.git
SOURCE_SUBDIR
CURRENT/cpp/lib)
FetchContent_MakeAvailable(
MathParserOrgMxParser)
target_link_libraries(YourExecutable
MathParserOrgMxParser)

GitHub

git clone https://github.com/mariuszgromada/MathParser.org-mXparser

OTHER DOWNLOAD OPTIONS

Download latest release – v.6.0.0 Picon: .NET bin onlyDownload latest release – v.6.0.0 Picon: JAVA bin onlyDownload latest release – v.6.0.0 Picon: bin + doc

NEWS FROM MATHPARSER.ORG
SOURCE CODE

Source code .zipSource code .tar.gz
View on GitHubMathSpace.pl

My other creative spaces