diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/CalcEngine.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/CalcEngine.cs
index 22c24db..b0d924a 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/CalcEngine.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/CalcEngine.cs
@@ -20,7 +20,7 @@
/// Use the RegisterFunction method to define custom functions.
/// Override the GetExternalObject method to add arbitrary variables to the engine scope.
///
- public partial class CalcEngine
+ internal class CalcEngine
{
//---------------------------------------------------------------------------
#region ** fields
@@ -776,5 +776,5 @@
/// List of objects that represent the
/// parameters to be used in the function call.
/// The function result.
- public delegate object CalcEngineFunction(List parms);
+ internal delegate object CalcEngineFunction(List parms);
}
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Expression.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Expression.cs
index 1b1732e..30f9b7f 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Expression.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Expression.cs
@@ -19,7 +19,7 @@
/// object val = expr.Evaluate();
///
///
- public class Expression : IComparable
+ internal class Expression : IComparable
{
//---------------------------------------------------------------------------
#region ** fields
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/FunctionDefinition.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/FunctionDefinition.cs
index 6438ce8..fc02182 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/FunctionDefinition.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/FunctionDefinition.cs
@@ -7,7 +7,7 @@
///
/// Function definition class (keeps function name, parameter counts, and delegate).
///
- public class FunctionDefinition
+ internal class FunctionDefinition
{
// ** fields
public int ParmMin, ParmMax;
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Logical.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Logical.cs
index c2cd087..391fed9 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Logical.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Logical.cs
@@ -5,7 +5,7 @@
namespace ClosedXML.Excel.CalcEngine
{
- static class Logical
+ internal static class Logical
{
public static void Register(CalcEngine ce)
{
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs
index a0edb8e..84fb2f0 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs
@@ -54,10 +54,10 @@
ce.RegisterFunction("RAND", 0, Rand);
ce.RegisterFunction("RANDBETWEEN", 2, RandBetween);
ce.RegisterFunction("ROMAN", 1, 2, Roman);
- //ce.RegisterFunction("ROUND", Round, 1);
- //ce.RegisterFunction("ROUNDDOWN", RoundDown, 1);
- //ce.RegisterFunction("ROUNDUP", RoundUp, 1);
- //ce.RegisterFunction("SERIESSUM", SeriesSum, 1);
+ ce.RegisterFunction("ROUND", 2, Round);
+ ce.RegisterFunction("ROUNDDOWN", 2, RoundDown);
+ ce.RegisterFunction("ROUNDUP", 1, 2, RoundUp);
+ ce.RegisterFunction("SERIESSUM", 4, SeriesSum);
ce.RegisterFunction("SIGN", 1, Sign);
ce.RegisterFunction("SIN", 1, Sin);
ce.RegisterFunction("SINH", 1, Sinh);
@@ -522,11 +522,72 @@
Int32 intTemp;
Boolean boolTemp;
if (p.Count == 1
- || (Boolean.TryParse(p[1].ToString(), out boolTemp) && boolTemp)
- || (Int32.TryParse(p[1].ToString(), out intTemp) && intTemp == 1))
+ || (Boolean.TryParse(p[1]._token.Value.ToString(), out boolTemp) && boolTemp)
+ || (Int32.TryParse(p[1]._token.Value.ToString(), out intTemp) && intTemp == 1))
return XLMath.ToRoman((int)p[0]);
throw new ArgumentException("Can only support classic roman types.");
}
+
+ private static object Round(List p)
+ {
+ var value = (Double)p[0];
+ var digits = (Int32)(Double)p[1];
+ if (digits >= 0)
+ {
+ return Math.Round(value, digits);
+ }
+ else
+ {
+ digits = Math.Abs(digits);
+ double temp = value / Math.Pow(10, digits);
+ temp = Math.Round(temp, 0);
+ return temp * Math.Pow(10, digits);
+ }
+
+ }
+
+ private static object RoundDown(List p)
+ {
+ var value = (Double)p[0];
+ var digits = (Int32)(Double)p[1];
+
+ if (value >= 0)
+ return Math.Floor(value * Math.Pow(10, digits)) / Math.Pow(10, digits);
+
+ return Math.Ceiling(value * Math.Pow(10, digits)) / Math.Pow(10, digits);
+ }
+
+ private static object RoundUp(List p)
+ {
+ var value = (Double)p[0];
+ var digits = (Int32)(Double)p[1];
+
+ if (value >= 0)
+ return Math.Ceiling(value * Math.Pow(10, digits)) / Math.Pow(10, digits);
+
+ return Math.Floor(value * Math.Pow(10, digits)) / Math.Pow(10, digits);
+ }
+
+ private static object SeriesSum(List p)
+ {
+ var x = (Double)p[0];
+ var n = (Double)p[1];
+ var m = (Double)p[2];
+ var obj = p[3] as XObjectExpression;
+
+ if (obj == null)
+ return p[3] * Math.Pow(x , n);
+
+ Double total = 0;
+ Int32 i = 0;
+ foreach (var e in obj)
+ {
+ total += (double)e * Math.Pow(x, n + i * m);
+ i++;
+ }
+
+ return total;
+ }
}
}
\ No newline at end of file
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Statistical.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Statistical.cs
index a6015bb..c0e91cd 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Statistical.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Statistical.cs
@@ -5,7 +5,7 @@
namespace ClosedXML.Excel.CalcEngine
{
- static class Statistical
+ internal static class Statistical
{
public static void Register(CalcEngine ce)
{
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Tally.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Tally.cs
index 74c3afd..989497a 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Tally.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Tally.cs
@@ -4,7 +4,7 @@
namespace ClosedXML.Excel.CalcEngine
{
- class Tally
+ internal class Tally
{
double _sum, _sum2, _cnt, _min, _max;
bool _numbersOnly;
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Text.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Text.cs
index ce80362..dbd7ba4 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Text.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/CalcEngine/Functions/Text.cs
@@ -6,7 +6,7 @@
namespace ClosedXML.Excel.CalcEngine
{
- static class Text
+ internal static class Text
{
public static void Register(CalcEngine ce)
{
diff --git a/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs b/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs
index 1e1970e..e0459f6 100644
--- a/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs
+++ b/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs
@@ -199,14 +199,101 @@
[TestMethod]
public void Roman()
{
- var actual = XLWorkbook.EvaluateExpr("Roman(3046)");
+ var actual = XLWorkbook.EvaluateExpr("Roman(3046, 1)");
Assert.AreEqual("MMMXLVI", actual);
actual = XLWorkbook.EvaluateExpr("Roman(270)");
Assert.AreEqual("CCLXX", actual);
- actual = XLWorkbook.EvaluateExpr("Roman(3999)");
+ actual = XLWorkbook.EvaluateExpr("Roman(3999, true)");
Assert.AreEqual("MMMCMXCIX", actual);
}
+
+ [TestMethod]
+ public void Round()
+ {
+ var actual = XLWorkbook.EvaluateExpr("Round(2.15, 1)");
+ Assert.AreEqual(2.2, actual);
+
+ actual = XLWorkbook.EvaluateExpr("Round(2.149, 1)");
+ Assert.AreEqual(2.1, actual);
+
+ actual = XLWorkbook.EvaluateExpr("Round(-1.475, 2)");
+ Assert.AreEqual(-1.48, actual);
+
+ actual = XLWorkbook.EvaluateExpr("Round(21.5, -1)");
+ Assert.AreEqual(20.0, actual);
+
+ actual = XLWorkbook.EvaluateExpr("Round(626.3, -3)");
+ Assert.AreEqual(1000.0, actual);
+
+ actual = XLWorkbook.EvaluateExpr("Round(1.98, -1)");
+ Assert.AreEqual(0.0, actual);
+
+ actual = XLWorkbook.EvaluateExpr("Round(-50.55, -2)");
+ Assert.AreEqual(-100.0, actual);
+ }
+
+ [TestMethod]
+ public void RoundDown()
+ {
+ var actual = XLWorkbook.EvaluateExpr("RoundDown(3.2, 0)");
+ Assert.AreEqual(3.0, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundDown(76.9, 0)");
+ Assert.AreEqual(76.0, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundDown(3.14159, 3)");
+ Assert.AreEqual(3.141, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundDown(-3.14159, 1)");
+ Assert.AreEqual(-3.1, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundDown(31415.92654, -2)");
+ Assert.AreEqual(31400.0, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundDown(0, 3)");
+ Assert.AreEqual(0.0, actual);
+ }
+
+ [TestMethod]
+ public void RoundUp()
+ {
+ var actual = XLWorkbook.EvaluateExpr("RoundUp(3.2, 0)");
+ Assert.AreEqual(4.0, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundUp(76.9, 0)");
+ Assert.AreEqual(77.0, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundUp(3.14159, 3)");
+ Assert.AreEqual(3.142, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundUp(-3.14159, 1)");
+ Assert.AreEqual(-3.2, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundUp(31415.92654, -2)");
+ Assert.AreEqual(31500.0, actual);
+
+ actual = XLWorkbook.EvaluateExpr("RoundUp(0, 3)");
+ Assert.AreEqual(0.0, actual);
+ }
+
+ [TestMethod]
+ public void SeriesSum()
+ {
+ var actual = XLWorkbook.EvaluateExpr("SERIESSUM(2,3,4,5)");
+ Assert.AreEqual(40.0, actual);
+
+ var wb = new XLWorkbook();
+ var ws = wb.AddWorksheet("Sheet1");
+ ws.Cell("A2").FormulaA1 = "PI()/4";
+ ws.Cell("A3").Value = 1;
+ ws.Cell("A4").FormulaA1 = "-1/FACT(2)";
+ ws.Cell("A5").FormulaA1 = "1/FACT(4)";
+ ws.Cell("A6").FormulaA1 = "-1/FACT(6)";
+
+ actual = ws.Evaluate("SERIESSUM(A2,0,2,A3:A6)");
+ Assert.IsTrue(Math.Abs(0.70710321482284566 - (double)actual) < XLHelper.Epsilon);
+ }
}
}