diff --git a/main/SS/Formula/Atp/AnalysisToolPak.cs b/main/SS/Formula/Atp/AnalysisToolPak.cs index 9ece2d849..8309a57de 100644 --- a/main/SS/Formula/Atp/AnalysisToolPak.cs +++ b/main/SS/Formula/Atp/AnalysisToolPak.cs @@ -183,6 +183,7 @@ private static Dictionary CreateFunctionsMap() r(m, "TBILLPRICE", null); r(m, "TBILLYIELD", null); r(m, "TEXTJOIN", TextJoinFunction.instance); + r(m, "T.INV", TInv.instance); r(m, "WEEKNUM", WeekNum.instance); r(m, "WORKDAY", WorkdayFunction.instance); r(m, "WORKDAY.INTL", WorkdayIntlFunction.instance); diff --git a/main/SS/Formula/Functions/TInv.cs b/main/SS/Formula/Functions/TInv.cs new file mode 100644 index 000000000..ba167fcba --- /dev/null +++ b/main/SS/Formula/Functions/TInv.cs @@ -0,0 +1,46 @@ +using MathNet.Numerics.Distributions; +using NPOI.SS.Formula.Eval; +using System; + +namespace NPOI.SS.Formula.Functions +{ + public class TInv : Fixed2ArgFunction, FreeRefFunction + { + + public static FreeRefFunction instance = new TInv(); + + public override ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2) + { + var probability = EvaluateValue(arg1, srcRowIndex, srcColumnIndex); + if(double.IsNaN(probability)) + { + return ErrorEval.VALUE_INVALID; + } + var degreesOfFreedom = EvaluateValue(arg2, srcRowIndex, srcColumnIndex); + if(double.IsNaN(degreesOfFreedom)) + { + return ErrorEval.VALUE_INVALID; + } + + StudentT studentT = new(0, 1, degreesOfFreedom); + var result = studentT.InverseCumulativeDistribution(probability); + return new NumberEval(result); + } + + private static Double EvaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) + { + ValueEval veText = OperandResolver.GetSingleValue(arg, srcRowIndex, srcColumnIndex); + String strText1 = OperandResolver.CoerceValueToString(veText); + return OperandResolver.ParseDouble(strText1); + } + + public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec) + { + if(args.Length == 2) + { + return Evaluate(ec.RowIndex, ec.ColumnIndex, args[0], args[1]); + } + return ErrorEval.VALUE_INVALID; + } + } +} diff --git a/testcases/main/SS/Formula/Functions/TestTInv.cs b/testcases/main/SS/Formula/Functions/TestTInv.cs new file mode 100644 index 000000000..70266bf48 --- /dev/null +++ b/testcases/main/SS/Formula/Functions/TestTInv.cs @@ -0,0 +1,57 @@ +using NPOI.HSSF.UserModel; +using NPOI.SS.Formula.Eval; +using NPOI.SS.UserModel; +using NUnit.Framework; +using System; + +namespace TestCases.SS.Formula.Functions +{ + [TestFixture] + public class TestTInv + { + [Test] + public void TestBasic() + { + HSSFWorkbook wb = new HSSFWorkbook(); + + ICell cell = wb.CreateSheet().CreateRow(0).CreateCell(0); + wb.GetSheetAt(0).GetRow(0).CreateCell(1).SetCellValue(0.75); + wb.GetSheetAt(0).CreateRow(1).CreateCell(1).SetCellValue(2); + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + + String formulaText = "T.INV(0.75,2)"; + confirmResult(fe, cell, formulaText, 0.816496581); + + formulaText = "T.INV(0.99,100)*126+36/2"; + confirmResult(fe, cell, formulaText, 315.8913881); + + formulaText = "T.INV(B1,B2)"; + confirmResult(fe, cell, formulaText, 0.816496581); + + formulaText = "T.INV(0.75, 2, 1)"; + confirmNumError(fe, cell, formulaText); + + formulaText = "T.INV(B1,B2,C3)"; + confirmNumError(fe, cell, formulaText); + + } + + private static void confirmResult(HSSFFormulaEvaluator fe, ICell cell, String formulaText, Double expectedResult) + { + cell.SetCellFormula(formulaText); + fe.NotifyUpdateCell(cell); + CellValue result = fe.Evaluate(cell); + Assert.AreEqual(CellType.Numeric,result.CellType); + Assert.AreEqual(expectedResult, result.NumberValue, 0.0000001); + } + + private static void confirmNumError(HSSFFormulaEvaluator fe, ICell cell, String formulaText) + { + cell.SetCellFormula(formulaText); + fe.NotifyUpdateCell(cell); + CellValue result = fe.Evaluate(cell); + Assert.AreEqual(CellType.Error, result.CellType); + } + } +}