Skip to content

Commit

Permalink
Canonical rounding fix #271 #268
Browse files Browse the repository at this point in the history
  • Loading branch information
mariuszgromada committed Aug 20, 2022
1 parent 9ceb6db commit 8031baf
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* @(#)Expression.cs 5.0.7 2022-07-23
* @(#)Expression.cs 5.0.7 2022-08-16
*
* MathParser.org-mXparser DUAL LICENSE AGREEMENT as of date 2022-05-22
* The most up-to-date license is available at the below link:
Expand Down Expand Up @@ -6289,9 +6289,11 @@ private double calculateInternal(CalcStepsRegister calcStepsRegister) {
double resultint = Math.Round(result);
if ( Math.Abs(result-resultint) <= BinaryRelations.getEpsilon() )
result = resultint;
}
else if (mXparser.canonicalRounding)
result = MathFunctions.canonicalRound(result);
}
if (mXparser.canonicalRounding) {
//result = MathFunctions.canonicalRound(result);
result = MathFunctions.lengthRound(result);
}
}

if (calcStepsRegister != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* @(#)MathFunctions.cs 5.0.6 2022-05-30
* @(#)MathFunctions.cs 5.0.7 2022-08-16
*
* MathParser.org-mXparser DUAL LICENSE AGREEMENT as of date 2022-05-22
* The most up-to-date license is available at the below link:
Expand Down Expand Up @@ -199,16 +199,17 @@ namespace org.mariuszgromada.math.mxparser.mathcollection {
* <a href="https://play.google.com/store/apps/details?id=org.mathparser.scalar.pro" target="_blank">Scalar Pro</a><br>
* <a href="https://mathspace.pl" target="_blank">MathSpace.pl</a><br>
*
* @version 5.0.6
* @version 5.0.7
*/
[CLSCompliant(true)]
public sealed class MathFunctions {
private static readonly double DECIMAL_MIN_VALUE = (double)Decimal.MinValue / 1e17;
private static readonly double DECIMAL_MAX_VALUE = (double)Decimal.MaxValue / 1e17;

private static int MAX_RECURSION_CALLS = mXparser.getMaxAllowedRecursionDepth();
private static readonly String DECIMAL_FORMAT = "0." + new String('#', 339);

private static void refreshMaxAllowedRecursionDepth() {
private static void refreshMaxAllowedRecursionDepth() {
MAX_RECURSION_CALLS = mXparser.getMaxAllowedRecursionDepth();
}

Expand Down Expand Up @@ -1585,7 +1586,7 @@ public static double asin(double a) {
else r = Math.Asin(a);
if (mXparser.checkIfDegreesMode()) {
if (sv != null) return sv.fvdeg;
return intIfAlmostIntOtherwiseOrig(r / Units.DEGREE_ARC);
return intIfAlmostIntOtherwiseOrig(div(r, Units.DEGREE_ARC));
} else return r;
}
/**
Expand All @@ -1605,7 +1606,7 @@ public static double acos(double a) {
else r = Math.Acos(a);
if (mXparser.checkIfDegreesMode()) {
if (sv != null) return sv.fvdeg;
return intIfAlmostIntOtherwiseOrig(r / Units.DEGREE_ARC);
return intIfAlmostIntOtherwiseOrig(div(r, Units.DEGREE_ARC));
}
else return r;
}
Expand All @@ -1626,7 +1627,7 @@ public static double atan(double a) {
else r = Math.Atan(a);
if (mXparser.checkIfDegreesMode()) {
if (sv != null) return sv.fvdeg;
return intIfAlmostIntOtherwiseOrig(r / Units.DEGREE_ARC);
return intIfAlmostIntOtherwiseOrig(div(r, Units.DEGREE_ARC));
}
else return r;
}
Expand All @@ -1651,7 +1652,7 @@ public static double actan(double a) {
}
if (mXparser.checkIfDegreesMode()) {
if (sv != null) return sv.fvdeg;
return intIfAlmostIntOtherwiseOrig(r / Units.DEGREE_ARC);
return intIfAlmostIntOtherwiseOrig(div(r, Units.DEGREE_ARC));
}
else return r;
}
Expand All @@ -1670,7 +1671,7 @@ public static double asec(double a) {
else r = Math.Acos(1 / a);
if (mXparser.checkIfDegreesMode()) {
if (sv != null) return sv.fvdeg;
return intIfAlmostIntOtherwiseOrig(r / Units.DEGREE_ARC);
return intIfAlmostIntOtherwiseOrig(div(r, Units.DEGREE_ARC));
}
else return r;
}
Expand All @@ -1689,7 +1690,7 @@ public static double acosec(double a) {
else r = Math.Asin(1 / a);
if (mXparser.checkIfDegreesMode()) {
if (sv != null) return sv.fvdeg;
return intIfAlmostIntOtherwiseOrig(r / Units.DEGREE_ARC);
return intIfAlmostIntOtherwiseOrig(div(r, Units.DEGREE_ARC));
}
else return r;
}
Expand Down Expand Up @@ -2181,7 +2182,7 @@ public static double roundUlp(double number) {
/**
* Returns integer part of a doube value.
* @param x Number
* @return For non- negative x returns Math.floor(x),
* @return For non-negative x returns Math.floor(x),
* otherwise returns -Math.floor(-x)
*/
public static double integerPart(double x) {
Expand Down Expand Up @@ -2546,6 +2547,57 @@ public static int ulpDecimalDigitsBefore(double value) {
double u = ulp(value);
return decimalDigitsBefore(u);
}
/**
* Length of a number represented in a standard decimal format
* @param value A given number
* @return Length of a number represented in a standard decimal format
* including decimal separator, excluding leading zeros (integer part),
* excluding trailing zeros (fractional part)
*/
public static int decimalNumberLength(double value) {
return value.ToString(CultureInfo.InvariantCulture).Length;
}
/**
* Fractional part length of a number represented in a standard decimal format
* @param value A given number
* @return Fractional part length of a number represented in a standard decimal
* format excluding decimal separator, excluding trailing zeros (fractional part)
*/
public static int fractionalPartLength(double value) {
if (Double.IsNaN(value)) return 0;
if (Double.IsInfinity(value)) return 0;
if (ulpDecimalDigitsBefore(value) <= 0) return 0;
String valueStr = value.ToString(CultureInfo.InvariantCulture);
int dotPos = valueStr.IndexOf('.');
if (dotPos >= 0) return valueStr.Length - 1 - dotPos;
return 0;
}
/**
* Intelligent rounding of a number within the decimal position of the ULP (Unit in the Last Place),
* provided that the result is significantly shortened in the standard decimal notation. Examples:
* 30.499999999999992 is rounded to 30.5, but 30.499999999999122 will not be rounded. Rounding is
* made to the decimal position of the ULP minus 2 on condition that the resulted number is shortened
* by at least 9 places.
* @param value A given number
* @return Returns an intelligently rounded number when the decimal position of ULP
* is a minimum of 11 and when rounded to the position of ULP - 2, shortens
* the number by a minimum of 9 places. Otherwise, returns original number.
*/
public static double lengthRound(double value) {
if (Double.IsNaN(value)) return value;
if (Double.IsInfinity(value)) return value;
if (value == 0d || value == -1d || value == 1d || value == -2d || value == 2d || value == -3d || value == 3d) return value;
if (value == -4d || value == 4d || value == -5d || value == 5d || value == -6d || value == 6d) return value;
if (value == -7d || value == 7d || value == -8d || value == 8d || value == -9d || value == 9d) return value;
if (value == -10d || value == 10d || value == -11d || value == 11d || value == -12d || value == 12d) return value;
if (ulpDecimalDigitsBefore(value) < 6) return value;
int decPartLen = fractionalPartLength(value);
if (decPartLen < 11) return value;
double valueRound = round(value, decPartLen - 2);
int decPartLenRound = fractionalPartLength(valueRound);
if (decPartLen - decPartLenRound >= 9) return valueRound;
return value;
}
/**
* Returns the first non-NaN value
*
Expand Down
117 changes: 110 additions & 7 deletions CURRENT/c-sharp/tests-and-release/4-Unit-Tests/ExpressionTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* @(#)ExpressionTest.cs 5.0.7 2022-07-23
* @(#)ExpressionTest.cs 5.0.7 2022-08-16
*
* MathParser.org-mXparser DUAL LICENSE AGREEMENT as of date 2022-05-22
* The most up-to-date license is available at the below link:
Expand Down Expand Up @@ -199,7 +199,7 @@ namespace org.mariuszgromada.math.mxparser.test {
* <a href="https://play.google.com/store/apps/details?id=org.mathparser.scalar.pro" target="_blank">Scalar Pro</a><br>
* <a href="https://mathspace.pl" target="_blank">MathSpace.pl</a><br>
*
* @version 5.0.6
* @version 5.0.7
*
*/
[TestClass]
Expand Down Expand Up @@ -10059,7 +10059,10 @@ public void TestExpr0650() {
TestCommonTools.testExprSettingsInit();
bool testResult = false;
mXparser.setEpsilonComparison();
String expStr = "-00000001.0002e-0002";
mXparser.disableCanonicalRounding();
mXparser.disableAlmostIntRounding();
mXparser.disableUlpRounding();
String expStr = "-00000001.0002e-0002";
TestCommonTools.consolePrintTestExprStart(650, expStr);
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
Expand Down Expand Up @@ -10180,7 +10183,10 @@ public void TestExpr0658() {
bool testResult = false;
mXparser.setEpsilonComparison();
String expStr = "((1%)%)%";
TestCommonTools.consolePrintTestExprStart(658, expStr);
mXparser.disableCanonicalRounding();
mXparser.disableAlmostIntRounding();
mXparser.disableUlpRounding();
TestCommonTools.consolePrintTestExprStart(658, expStr);
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
double reg = 0.000001;
Expand Down Expand Up @@ -13307,7 +13313,10 @@ public void TestExpr0857() {
TestCommonTools.testExprSettingsInit();
bool testResult = false;
mXparser.setEpsilonComparison();
Function f = new Function("f(x,a,n) = (sqrt(pi)/2) * sum(k, 0, n, ( a^(1/2 - k) / ( Gamma(3/2 - k) * k! ) ) * (x-a)^k )");
mXparser.disableCanonicalRounding();
mXparser.disableAlmostIntRounding();
mXparser.disableUlpRounding();
Function f = new Function("f(x,a,n) = (sqrt(pi)/2) * sum(k, 0, n, ( a^(1/2 - k) / ( Gamma(3/2 - k) * k! ) ) * (x-a)^k )");
String expStr = "sum(x, 1, 3, sqrt(x) - f(x,2,50) , 0.001)";
TestCommonTools.consolePrintTestExprStart(857, expStr);
Expression testExp = new Expression(expStr, f);
Expand Down Expand Up @@ -14776,6 +14785,8 @@ public void TestExpr0943() {
* SetPrecision[Sum[Gamma[x], {x, -0.9, -0.1, 0.001}], 16] = -4033.861662372823
*/
mXparser.disableUlpRounding();
mXparser.disableCanonicalRounding();
mXparser.disableAlmostIntRounding();
String expStr = "( sum(x, -0.9, -0.1, Gamma(x), 0.001) - (-4033.861662372823) ) / (-4033.861662372823)";
TestCommonTools.consolePrintTestExprStart(943, expStr);
Expression testExp = new Expression(expStr);
Expand Down Expand Up @@ -17463,7 +17474,8 @@ public void TestExpr1090() {
bool testResult = false;
mXparser.disableUlpRounding();
mXparser.disableAlmostIntRounding();
String expStr = "1 + 1e-14";
mXparser.disableCanonicalRounding();
String expStr = "1 + 1e-14";
TestCommonTools.consolePrintTestExprStart(1090, expStr);
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
Expand All @@ -17481,7 +17493,8 @@ public void TestExpr1091() {
bool testResult = false;
mXparser.disableUlpRounding();
mXparser.disableAlmostIntRounding();
String expStr = "-1 - 1e-14";
mXparser.disableCanonicalRounding();
String expStr = "-1 - 1e-14";
TestCommonTools.consolePrintTestExprStart(1091, expStr);
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
Expand Down Expand Up @@ -22348,5 +22361,95 @@ public void TestExpr1361() {
TestCommonTools.consolePrintTestExprEnd(value, reg, testResult, testExp);
Assert.IsTrue(testResult);
}
[TestMethod]
public void TestExpr1362() {
TestCommonTools.testExprSettingsInit();
bool testResult = false;
String expStr = "asin(sin(30.5))";
TestCommonTools.consolePrintTestExprStart(1362, expStr);
mXparser.setDegreesMode();
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
double reg = 30.5;
if (reg == value)
testResult = true;
TestCommonTools.consolePrintTestExprEnd(value, reg, testResult, testExp);
Assert.IsTrue(testResult);
}
[TestMethod]
public void TestExpr1363() {
TestCommonTools.testExprSettingsInit();
bool testResult = false;
String expStr = "acos(cos(30.5))";
TestCommonTools.consolePrintTestExprStart(1363, expStr);
mXparser.setDegreesMode();
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
double reg = 30.5;
if (reg == value)
testResult = true;
TestCommonTools.consolePrintTestExprEnd(value, reg, testResult, testExp);
Assert.IsTrue(testResult);
}
[TestMethod]
public void TestExpr1364() {
TestCommonTools.testExprSettingsInit();
bool testResult = false;
String expStr = "atan(tan(30.5))";
TestCommonTools.consolePrintTestExprStart(1364, expStr);
mXparser.setDegreesMode();
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
double reg = 30.5;
if (reg == value)
testResult = true;
TestCommonTools.consolePrintTestExprEnd(value, reg, testResult, testExp);
Assert.IsTrue(testResult);
}
[TestMethod]
public void TestExpr1365() {
TestCommonTools.testExprSettingsInit();
bool testResult = false;
String expStr = "actan(ctan(30.5))";
TestCommonTools.consolePrintTestExprStart(1365, expStr);
mXparser.setDegreesMode();
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
double reg = 30.5;
if (reg == value)
testResult = true;
TestCommonTools.consolePrintTestExprEnd(value, reg, testResult, testExp);
Assert.IsTrue(testResult);
}
[TestMethod]
public void TestExpr1366() {
TestCommonTools.testExprSettingsInit();
bool testResult = false;
String expStr = "arcsec(sec(30.5))";
TestCommonTools.consolePrintTestExprStart(1366, expStr);
mXparser.setDegreesMode();
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
double reg = 30.5;
if (reg == value)
testResult = true;
TestCommonTools.consolePrintTestExprEnd(value, reg, testResult, testExp);
Assert.IsTrue(testResult);
}
[TestMethod]
public void TestExpr1367() {
TestCommonTools.testExprSettingsInit();
bool testResult = false;
String expStr = "arccsc(csc(30.5))";
TestCommonTools.consolePrintTestExprStart(1367, expStr);
mXparser.setDegreesMode();
Expression testExp = new Expression(expStr);
double value = testExp.calculate();
double reg = 30.5;
if (reg == value)
testResult = true;
TestCommonTools.consolePrintTestExprEnd(value, reg, testResult, testExp);
Assert.IsTrue(testResult);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,10 @@ internal static void testExprSettingsInit() {
mXparser.setEpsilonComparison();
mXparser.setDefaultEpsilon();
mXparser.enableUlpRounding();
mXparser.enableCanonicalRounding();
mXparser.enableImpliedMultiplicationMode();
mXparser.enableUnicodeBuiltinKeyWordsMode();
mXparser.setRadiansMode();
}
internal static void testSynSettingsInit() {
mXparser.setDefaultOptions();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* @(#)Expression.java 5.0.7 2022-07-23
* @(#)Expression.java 5.0.7 2022-08-16
*
* MathParser.org-mXparser DUAL LICENSE AGREEMENT as of date 2022-05-22
* The most up-to-date license is available at the below link:
Expand Down Expand Up @@ -6315,6 +6315,9 @@ else if (token.tokenTypeId == RandomVariable.TYPE_ID)
if ( Math.abs(result-resultint) <= BinaryRelations.getEpsilon() )
result = resultint;
}
if (mXparser.canonicalRounding) {
result = MathFunctions.lengthRound(result);
}
}

if (calcStepsRegister != null) {
Expand Down
Loading

0 comments on commit 8031baf

Please sign in to comment.