Fixed #727, rounding numeric with precision for formula calculation

formula
xuri 4 years ago
parent 92c8626f81
commit 599a8cb0bc
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7

@ -6,7 +6,7 @@
<a href="https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize"><img src="https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize" alt="Go Report Card"></a> <a href="https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize"><img src="https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize" alt="Go Report Card"></a>
<a href="https://pkg.go.dev/github.com/360EntSecGroup-Skylar/excelize/v2?tab=doc"><img src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white" alt="go.dev"></a> <a href="https://pkg.go.dev/github.com/360EntSecGroup-Skylar/excelize/v2?tab=doc"><img src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white" alt="go.dev"></a>
<a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/license-bsd-orange.svg" alt="Licenses"></a> <a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/license-bsd-orange.svg" alt="Licenses"></a>
<a href="https://www.paypal.me/xuri"><img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Donate"></a> <a href="https://www.paypal.com/paypalme/xuri"><img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Donate"></a>
</p> </p>
# Excelize # Excelize

@ -6,7 +6,7 @@
<a href="https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize"><img src="https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize" alt="Go Report Card"></a> <a href="https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize"><img src="https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize" alt="Go Report Card"></a>
<a href="https://pkg.go.dev/github.com/360EntSecGroup-Skylar/excelize/v2?tab=doc"><img src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white" alt="go.dev"></a> <a href="https://pkg.go.dev/github.com/360EntSecGroup-Skylar/excelize/v2?tab=doc"><img src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white" alt="go.dev"></a>
<a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/license-bsd-orange.svg" alt="Licenses"></a> <a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/license-bsd-orange.svg" alt="Licenses"></a>
<a href="https://www.paypal.me/xuri"><img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Donate"></a> <a href="https://www.paypal.com/paypalme/xuri"><img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Donate"></a>
</p> </p>
# Excelize # Excelize

@ -42,6 +42,14 @@ const (
formulaErrorGETTINGDATA = "#GETTING_DATA" formulaErrorGETTINGDATA = "#GETTING_DATA"
) )
// Numeric precision correct numeric values as legacy Excel application
// https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft_Excel In the
// top figure the fraction 1/9000 in Excel is displayed. Although this number
// has a decimal representation that is an infinite string of ones, Excel
// displays only the leading 15 figures. In the second line, the number one
// is added to the fraction, and again Excel displays only 15 figures.
const numericPrecision = 1000000000000000
// cellRef defines the structure of a cell reference. // cellRef defines the structure of a cell reference.
type cellRef struct { type cellRef struct {
Col int Col int
@ -141,6 +149,13 @@ func (f *File) CalcCellValue(sheet, cell string) (result string, err error) {
return return
} }
result = token.TValue result = token.TValue
if len(result) > 16 {
num, e := roundPrecision(result)
if e != nil {
return result, err
}
result = strings.ToUpper(num)
}
return return
} }

@ -54,42 +54,42 @@ func TestCalcCellValue(t *testing.T) {
"=ABS(2-4.5)": "2.5", "=ABS(2-4.5)": "2.5",
// ACOS // ACOS
"=ACOS(-1)": "3.141592653589793", "=ACOS(-1)": "3.141592653589793",
"=ACOS(0)": "1.5707963267948966", "=ACOS(0)": "1.570796326794897",
// ACOSH // ACOSH
"=ACOSH(1)": "0", "=ACOSH(1)": "0",
"=ACOSH(2.5)": "1.566799236972411", "=ACOSH(2.5)": "1.566799236972411",
"=ACOSH(5)": "2.2924316695611777", "=ACOSH(5)": "2.292431669561178",
// ACOT // ACOT
"=_xlfn.ACOT(1)": "0.7853981633974483", "=_xlfn.ACOT(1)": "0.785398163397448",
"=_xlfn.ACOT(-2)": "2.677945044588987", "=_xlfn.ACOT(-2)": "2.677945044588987",
"=_xlfn.ACOT(0)": "1.5707963267948966", "=_xlfn.ACOT(0)": "1.570796326794897",
// ACOTH // ACOTH
"=_xlfn.ACOTH(-5)": "-0.2027325540540822", "=_xlfn.ACOTH(-5)": "-0.202732554054082",
"=_xlfn.ACOTH(1.1)": "1.5222612188617113", "=_xlfn.ACOTH(1.1)": "1.522261218861711",
"=_xlfn.ACOTH(2)": "0.5493061443340548", "=_xlfn.ACOTH(2)": "0.549306144334055",
// ARABIC // ARABIC
`=_xlfn.ARABIC("IV")`: "4", `=_xlfn.ARABIC("IV")`: "4",
`=_xlfn.ARABIC("-IV")`: "-4", `=_xlfn.ARABIC("-IV")`: "-4",
`=_xlfn.ARABIC("MCXX")`: "1120", `=_xlfn.ARABIC("MCXX")`: "1120",
`=_xlfn.ARABIC("")`: "0", `=_xlfn.ARABIC("")`: "0",
// ASIN // ASIN
"=ASIN(-1)": "-1.5707963267948966", "=ASIN(-1)": "-1.570796326794897",
"=ASIN(0)": "0", "=ASIN(0)": "0",
// ASINH // ASINH
"=ASINH(0)": "0", "=ASINH(0)": "0",
"=ASINH(-0.5)": "-0.48121182505960347", "=ASINH(-0.5)": "-0.481211825059604",
"=ASINH(2)": "1.4436354751788103", "=ASINH(2)": "1.44363547517881",
// ATAN // ATAN
"=ATAN(-1)": "-0.7853981633974483", "=ATAN(-1)": "-0.785398163397448",
"=ATAN(0)": "0", "=ATAN(0)": "0",
"=ATAN(1)": "0.7853981633974483", "=ATAN(1)": "0.785398163397448",
// ATANH // ATANH
"=ATANH(-0.8)": "-1.0986122886681098", "=ATANH(-0.8)": "-1.09861228866811",
"=ATANH(0)": "0", "=ATANH(0)": "0",
"=ATANH(0.5)": "0.5493061443340548", "=ATANH(0.5)": "0.549306144334055",
// ATAN2 // ATAN2
"=ATAN2(1,1)": "0.7853981633974483", "=ATAN2(1,1)": "0.785398163397448",
"=ATAN2(1,-1)": "-0.7853981633974483", "=ATAN2(1,-1)": "-0.785398163397448",
"=ATAN2(4,0)": "0", "=ATAN2(4,0)": "0",
// BASE // BASE
"=BASE(12,2)": "1100", "=BASE(12,2)": "1100",
@ -145,17 +145,17 @@ func TestCalcCellValue(t *testing.T) {
"=COS(0)": "1", "=COS(0)": "1",
// COSH // COSH
"=COSH(0)": "1", "=COSH(0)": "1",
"=COSH(0.5)": "1.1276259652063807", "=COSH(0.5)": "1.127625965206381",
"=COSH(-2)": "3.7621956910836314", "=COSH(-2)": "3.762195691083632",
// _xlfn.COT // _xlfn.COT
"=_xlfn.COT(0.785398163397448)": "0.9999999999999992", "=_xlfn.COT(0.785398163397448)": "0.999999999999999",
// _xlfn.COTH // _xlfn.COTH
"=_xlfn.COTH(-3.14159265358979)": "-0.9962720762207499", "=_xlfn.COTH(-3.14159265358979)": "-0.99627207622075",
// _xlfn.CSC // _xlfn.CSC
"=_xlfn.CSC(-6)": "3.5788995472544056", "=_xlfn.CSC(-6)": "3.578899547254406",
"=_xlfn.CSC(1.5707963267949)": "1", "=_xlfn.CSC(1.5707963267949)": "1",
// _xlfn.CSCH // _xlfn.CSCH
"=_xlfn.CSCH(-3.14159265358979)": "-0.08658953753004724", "=_xlfn.CSCH(-3.14159265358979)": "-0.086589537530047",
// _xlfn.DECIMAL // _xlfn.DECIMAL
`=_xlfn.DECIMAL("1100",2)`: "12", `=_xlfn.DECIMAL("1100",2)`: "12",
`=_xlfn.DECIMAL("186A0",16)`: "100000", `=_xlfn.DECIMAL("186A0",16)`: "100000",
@ -174,9 +174,9 @@ func TestCalcCellValue(t *testing.T) {
"=EVEN(-4)": "-4", "=EVEN(-4)": "-4",
// EXP // EXP
"=EXP(100)": "2.6881171418161356E+43", "=EXP(100)": "2.6881171418161356E+43",
"=EXP(0.1)": "1.1051709180756477", "=EXP(0.1)": "1.105170918075648",
"=EXP(0)": "1", "=EXP(0)": "1",
"=EXP(-5)": "0.006737946999085467", "=EXP(-5)": "0.006737946999085",
// FACT // FACT
"=FACT(3)": "6", "=FACT(3)": "6",
"=FACT(6)": "720", "=FACT(6)": "720",
@ -247,23 +247,23 @@ func TestCalcCellValue(t *testing.T) {
// LN // LN
"=LN(1)": "0", "=LN(1)": "0",
"=LN(100)": "4.605170185988092", "=LN(100)": "4.605170185988092",
"=LN(0.5)": "-0.6931471805599453", "=LN(0.5)": "-0.693147180559945",
// LOG // LOG
"=LOG(64,2)": "6", "=LOG(64,2)": "6",
"=LOG(100)": "2", "=LOG(100)": "2",
"=LOG(4,0.5)": "-2", "=LOG(4,0.5)": "-2",
"=LOG(500)": "2.6989700043360183", "=LOG(500)": "2.698970004336019",
// LOG10 // LOG10
"=LOG10(100)": "2", "=LOG10(100)": "2",
"=LOG10(1000)": "3", "=LOG10(1000)": "3",
"=LOG10(0.001)": "-3", "=LOG10(0.001)": "-3",
"=LOG10(25)": "1.3979400086720375", "=LOG10(25)": "1.397940008672038",
// MOD // MOD
"=MOD(6,4)": "2", "=MOD(6,4)": "2",
"=MOD(6,3)": "0", "=MOD(6,3)": "0",
"=MOD(6,2.5)": "1", "=MOD(6,2.5)": "1",
"=MOD(6,1.333)": "0.6680000000000001", "=MOD(6,1.333)": "0.668",
"=MOD(-10.23,1)": "0.7699999999999996", "=MOD(-10.23,1)": "0.77",
// MROUND // MROUND
"=MROUND(333.7,0.5)": "333.5", "=MROUND(333.7,0.5)": "333.5",
"=MROUND(333.8,1)": "334", "=MROUND(333.8,1)": "334",
@ -298,7 +298,7 @@ func TestCalcCellValue(t *testing.T) {
"=QUOTIENT(4.5,3.1)": "1", "=QUOTIENT(4.5,3.1)": "1",
"=QUOTIENT(-10,3)": "-3", "=QUOTIENT(-10,3)": "-3",
// RADIANS // RADIANS
"=RADIANS(50)": "0.8726646259971648", "=RADIANS(50)": "0.872664625997165",
"=RADIANS(-180)": "-3.141592653589793", "=RADIANS(-180)": "-3.141592653589793",
"=RADIANS(180)": "3.141592653589793", "=RADIANS(180)": "3.141592653589793",
"=RADIANS(360)": "6.283185307179586", "=RADIANS(360)": "6.283185307179586",
@ -323,13 +323,13 @@ func TestCalcCellValue(t *testing.T) {
"=ROUND(991,-1)": "990", "=ROUND(991,-1)": "990",
// ROUNDDOWN // ROUNDDOWN
"=ROUNDDOWN(99.999,1)": "99.9", "=ROUNDDOWN(99.999,1)": "99.9",
"=ROUNDDOWN(99.999,2)": "99.99000000000002", "=ROUNDDOWN(99.999,2)": "99.99000000000001",
"=ROUNDDOWN(99.999,0)": "99", "=ROUNDDOWN(99.999,0)": "99",
"=ROUNDDOWN(99.999,-1)": "90", "=ROUNDDOWN(99.999,-1)": "90",
"=ROUNDDOWN(-99.999,2)": "-99.99000000000002", "=ROUNDDOWN(-99.999,2)": "-99.99000000000001",
"=ROUNDDOWN(-99.999,-1)": "-90", "=ROUNDDOWN(-99.999,-1)": "-90",
// ROUNDUP // ROUNDUP
"=ROUNDUP(11.111,1)": "11.200000000000001", "=ROUNDUP(11.111,1)": "11.200000000000003",
"=ROUNDUP(11.111,2)": "11.120000000000003", "=ROUNDUP(11.111,2)": "11.120000000000003",
"=ROUNDUP(11.111,0)": "12", "=ROUNDUP(11.111,0)": "12",
"=ROUNDUP(11.111,-1)": "20", "=ROUNDUP(11.111,-1)": "20",
@ -339,7 +339,7 @@ func TestCalcCellValue(t *testing.T) {
"=_xlfn.SEC(-3.14159265358979)": "-1", "=_xlfn.SEC(-3.14159265358979)": "-1",
"=_xlfn.SEC(0)": "1", "=_xlfn.SEC(0)": "1",
// SECH // SECH
"=_xlfn.SECH(-3.14159265358979)": "0.0862667383340547", "=_xlfn.SECH(-3.14159265358979)": "0.086266738334055",
"=_xlfn.SECH(0)": "1", "=_xlfn.SECH(0)": "1",
// SIGN // SIGN
"=SIGN(9.5)": "1", "=SIGN(9.5)": "1",
@ -348,17 +348,17 @@ func TestCalcCellValue(t *testing.T) {
"=SIGN(0.00000001)": "1", "=SIGN(0.00000001)": "1",
"=SIGN(6-7)": "-1", "=SIGN(6-7)": "-1",
// SIN // SIN
"=SIN(0.785398163)": "0.7071067809055092", "=SIN(0.785398163)": "0.707106780905509",
// SINH // SINH
"=SINH(0)": "0", "=SINH(0)": "0",
"=SINH(0.5)": "0.5210953054937474", "=SINH(0.5)": "0.521095305493747",
"=SINH(-2)": "-3.626860407847019", "=SINH(-2)": "-3.626860407847019",
// SQRT // SQRT
"=SQRT(4)": "2", "=SQRT(4)": "2",
`=SQRT("")`: "0", `=SQRT("")`: "0",
// SQRTPI // SQRTPI
"=SQRTPI(5)": "3.963327297606011", "=SQRTPI(5)": "3.963327297606011",
"=SQRTPI(0.2)": "0.7926654595212022", "=SQRTPI(0.2)": "0.792665459521202",
"=SQRTPI(100)": "17.72453850905516", "=SQRTPI(100)": "17.72453850905516",
"=SQRTPI(0)": "0", "=SQRTPI(0)": "0",
// SUM // SUM
@ -399,8 +399,8 @@ func TestCalcCellValue(t *testing.T) {
"=TAN(0)": "0", "=TAN(0)": "0",
// TANH // TANH
"=TANH(0)": "0", "=TANH(0)": "0",
"=TANH(0.5)": "0.46211715726000974", "=TANH(0.5)": "0.46211715726001",
"=TANH(-2)": "-0.9640275800758169", "=TANH(-2)": "-0.964027580075817",
// TRUNC // TRUNC
"=TRUNC(99.999,1)": "99.9", "=TRUNC(99.999,1)": "99.9",
"=TRUNC(99.999,2)": "99.99", "=TRUNC(99.999,2)": "99.99",
@ -794,14 +794,14 @@ func TestCalcCellValue(t *testing.T) {
// PRODUCT // PRODUCT
"=PRODUCT(Sheet1!A1:Sheet1!A1:A2,A2)": "4", "=PRODUCT(Sheet1!A1:Sheet1!A1:A2,A2)": "4",
// SUM // SUM
"=A1/A3": "0.3333333333333333", "=A1/A3": "0.333333333333333",
"=SUM(A1:A2)": "3", "=SUM(A1:A2)": "3",
"=SUM(Sheet1!A1,A2)": "3", "=SUM(Sheet1!A1,A2)": "3",
"=(-2-SUM(-4+A2))*5": "0", "=(-2-SUM(-4+A2))*5": "0",
"=SUM(Sheet1!A1:Sheet1!A1:A2,A2)": "5", "=SUM(Sheet1!A1:Sheet1!A1:A2,A2)": "5",
"=SUM(A1,A2,A3)*SUM(2,3)": "30", "=SUM(A1,A2,A3)*SUM(2,3)": "30",
"=1+SUM(SUM(A1+A2/A3)*(2-3),2)": "1.3333333333333335", "=1+SUM(SUM(A1+A2/A3)*(2-3),2)": "1.333333333333334",
"=A1/A2/SUM(A1:A2:B1)": "0.041666666666666664", "=A1/A2/SUM(A1:A2:B1)": "0.041666666666667",
"=A1/A2/SUM(A1:A2:B1)*A3": "0.125", "=A1/A2/SUM(A1:A2:B1)*A3": "0.125",
} }
for formula, expected := range referenceCalc { for formula, expected := range referenceCalc {

@ -345,20 +345,11 @@ func (c *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
} }
return f.formattedValue(c.S, c.V), nil return f.formattedValue(c.S, c.V), nil
default: default:
// correct numeric values as legacy Excel app
// https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft_Excel
// In the top figure the fraction 1/9000 in Excel is displayed.
// Although this number has a decimal representation that is an infinite string of ones,
// Excel displays only the leading 15 figures. In the second line, the number one is added to the fraction, and again Excel displays only 15 figures.
const precision = 1000000000000000
if len(c.V) > 16 { if len(c.V) > 16 {
num, err := strconv.ParseFloat(c.V, 64) val, err := roundPrecision(c.V)
if err != nil { if err != nil {
return "", err return "", err
} }
num = math.Round(num*precision) / precision
val := fmt.Sprintf("%g", num)
if val != c.V { if val != c.V {
return f.formattedValue(c.S, val), nil return f.formattedValue(c.S, val), nil
} }
@ -367,6 +358,16 @@ func (c *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
} }
} }
// roundPrecision round precision for numeric.
func roundPrecision(value string) (result string, err error) {
var num float64
if num, err = strconv.ParseFloat(value, 64); err != nil {
return
}
result = fmt.Sprintf("%g", math.Round(num*numericPrecision)/numericPrecision)
return
}
// SetRowVisible provides a function to set visible of a single row by given // SetRowVisible provides a function to set visible of a single row by given
// worksheet name and Excel row number. For example, hide row 2 in Sheet1: // worksheet name and Excel row number. For example, hide row 2 in Sheet1:
// //

Loading…
Cancel
Save