diff --git a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs index 2d1368d..c6ef569 100644 --- a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs +++ b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Text; namespace ClosedXML.Excel.CalcEngine { @@ -25,6 +26,7 @@ ce.RegisterFunction("COMBIN", 2, Combin); ce.RegisterFunction("COS", 1, Cos); ce.RegisterFunction("COSH", 1, Cosh); + ce.RegisterFunction("DECIMAL", 2, MathTrig.Decimal); ce.RegisterFunction("DEGREES", 1, Degrees); ce.RegisterFunction("EVEN", 1, Even); ce.RegisterFunction("EXP", 1, Exp); @@ -115,6 +117,37 @@ return Math.Cosh(p[0]); } + private static object Decimal(List p) + { + string source = p[0]; + double radix = p[1]; + + if (radix < 2 || radix > 36) + throw new NumberException(); + + var asciiValues = Encoding.ASCII.GetBytes(source.ToUpperInvariant()); + + double result = 0; + int i = 0; + + foreach (byte digit in asciiValues) + { + int digitNumber = digit >= 48 && digit < 58 + ? digit - 48 + : digit > 90 + ? throw new NumberException() + : digit - 55; + + if (digitNumber > radix - 1) + throw new NumberException(); + + result = result * radix + digitNumber; + i++; + } + + return result; + } + private static object Exp(List p) { return Math.Exp(p[0]); diff --git a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs index b9003d2..6cfe211 100644 --- a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs +++ b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs @@ -1,4 +1,5 @@ using ClosedXML.Excel; +using ClosedXML.Excel.CalcEngine; using ClosedXML.Excel.CalcEngine.Exceptions; using NUnit.Framework; using System; @@ -11,6 +12,33 @@ { private readonly double tolerance = 1e-10; + [TestCase("FF", 16, 255)] + [TestCase("111", 2, 7)] + [TestCase("zap", 36, 45745)] + public void Decimal(string inputString, int radix, int expectedResult) + { + var actualResult = XLWorkbook.EvaluateExpr($"DECIMAL(\"{inputString}\", {radix})"); + Assert.AreEqual(expectedResult, actualResult); + } + + [Test] + public void Decimal_ZeroIsZeroInAnyRadix([Range(1, 36)] int radix) + { + Assert.AreEqual(0, XLWorkbook.EvaluateExpr($"DECIMAL(\"0\", {radix})")); + } + + [Theory] + public void Decimal_ReturnsErrorForRadiansGreater36([Range(37, 255)] int radix) + { + Assert.Throws(() => XLWorkbook.EvaluateExpr($"DECIMAL(\"0\", {radix})")); + } + + [Theory] + public void Decimal_ReturnsErrorForRadiansSmaller2([Range(-5, 1)] int radix) + { + Assert.Throws(() => XLWorkbook.EvaluateExpr($"DECIMAL(\"0\", {radix})")); + } + [Test] public void Floor() {