Skip to content

Commit

Permalink
EPPlusSoftware#779 implemented FullPrecision workbook property
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan.horbach committed Jan 2, 2023
1 parent 3d26cfd commit 24d9155
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 2 deletions.
20 changes: 19 additions & 1 deletion src/EPPlus/ExcelWorkbook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1096,7 +1096,25 @@ public bool FullCalcOnLoad
}
}

ExcelThemeManager _theme = null;
private const string FULL_PRECISION = "d:calcPr/@fullPrecision";
/// <summary>
/// Should Excel calculate with the displayed value?
/// </summary>
public bool FullPrecision
{
get
{

return GetXmlNodeBool(FULL_PRECISION, true);
}
set
{
SetXmlNodeBool(FULL_PRECISION, value);
}
}


ExcelThemeManager _theme = null;
/// <summary>
/// Create and manage the theme for the workbook.
/// </summary>
Expand Down
60 changes: 59 additions & 1 deletion src/EPPlus/ExcelWorksheet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
using OfficeOpenXml.Sorting;
using OfficeOpenXml.Constants;
using OfficeOpenXml.Drawing.Interfaces;
using OfficeOpenXml.FormulaParsing.Utilities;
using OfficeOpenXml.Packaging;
namespace OfficeOpenXml
{
Expand Down Expand Up @@ -4203,8 +4204,65 @@ internal int GetStyleInner(int row, int col)
/// <param name="value">value</param>
internal void SetValueInner(int row, int col, object value)
{
_values.SetValue_Value(row, col, value);
if (!value.IsNumeric()
|| Workbook.FullPrecision)
{
_values.SetValue_Value(row, col, value);
return;
}

byte? numberOfDecimals = GetNumberOfDecimals(Cells[row, col]);

_values.SetValue_Value(row, col,
RoundValue(value, numberOfDecimals));
}

private const string _DECIMAL_PLACES_PATTERN = @"\.(?<dec> [#0]+ )";
private static byte? GetNumberOfDecimals(IExcelCell cell)
{
var formatting = cell.Style.Numberformat.Format;

if (string.IsNullOrEmpty(formatting))
return null;

// get number of decimal places #.# or 0.00
var match = Regex.Match(formatting, _DECIMAL_PLACES_PATTERN,
RegexOptions.IgnorePatternWhitespace);

if (match.Success)
{
if (!string.IsNullOrEmpty(match.Groups["dec"].Value))
return (byte)match.Groups["dec"].Value.Length;
}

return 0;
}

private static object RoundValue(object value, byte? numberOfDecimals)
{
if (numberOfDecimals.HasValue
&& TryParseToDecimal(value, out var val))
{
return Math.Round(val, numberOfDecimals.Value);
}

return value;
}

private static bool TryParseToDecimal(object number, out decimal val)
{
if (decimal.TryParse(number.ToString(), out val))
return true;

if (double.TryParse(number.ToString(), out var dblVal))
{
val = (decimal)dblVal;
return true;
}

return false;
}

/// <summary>
/// Set accessor of sheet styleId
/// </summary>
Expand Down
28 changes: 28 additions & 0 deletions src/EPPlusTest/Issues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3965,5 +3965,33 @@ public void i762()
SaveAndCleanup(p);
}
}

[TestMethod]
public void If_full_precision_is_off_value_should_be_calculated_as_seen_issue_779()
{
//Issue: If Excel has rounding errors(due to the fact that calculation is always
//done with floating points) some formulas like "If" are wrong due to aftereffects.
//One can do work around that issue by ticking the checkbox "precision as displayed"
//in the advanced excel options.This function was not yet implemented in EPPlus.

using var p = new ExcelPackage();
p.Workbook.Worksheets.Add("first");
p.Workbook.FullPrecision = false;

var sheet = p.Workbook.Worksheets.First();

sheet.Cells["A1"].Value = 0.0000001;
sheet.Cells["A2"].Value = 0.00000001;
sheet.Cells["A3"].Formula = "=SUM(A1:A2)";
sheet.Cells["A3"].Style.Numberformat.Format = "#,##0";
sheet.Cells["A4"].Formula = "=IF(A3=0;\"OK\";\"Not OK\")";

//var path = Path.Combine(GetLocalResourcesPath(), "FullPrecisionIF.xlsx");
//using var p = new ExcelPackage(path);

p.Workbook.Calculate();
Assert.IsFalse(p.Workbook.FullPrecision);
Assert.AreEqual("OK", p.Workbook.Worksheets.First().Cells["A4"].Value);
}
}
}

0 comments on commit 24d9155

Please sign in to comment.