From 94f197c4fe6531f96a42fe4e960c1c921a3ee0e8 Mon Sep 17 00:00:00 2001 From: xuri Date: Sat, 19 Mar 2022 00:05:47 +0800 Subject: [PATCH] This improved formula calculate precision and added zero placeholder number format support --- .github/workflows/go.yml | 2 +- calc_test.go | 200 +++++++++++++++++++-------------------- cell.go | 22 ++--- file.go | 2 +- lib.go | 7 +- lib_test.go | 4 +- numfmt.go | 52 ++++++++-- numfmt_test.go | 8 ++ picture_test.go | 4 +- rows.go | 7 ++ 10 files changed, 178 insertions(+), 130 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index b9841144..83102225 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -5,7 +5,7 @@ jobs: test: strategy: matrix: - go-version: [1.15.x, 1.16.x, 1.17.x] + go-version: [1.15.x, 1.16.x, 1.17.x, 1.18.x] os: [ubuntu-latest, macos-latest, windows-latest] targetplatform: [x86, x64] diff --git a/calc_test.go b/calc_test.go index 6f085548..d3500379 100644 --- a/calc_test.go +++ b/calc_test.go @@ -65,19 +65,19 @@ func TestCalcCellValue(t *testing.T) { `="A"<>"A"`: "FALSE", // Engineering Functions // BESSELI - "=BESSELI(4.5,1)": "15.389222753735925", + "=BESSELI(4.5,1)": "15.3892227537359", "=BESSELI(32,1)": "5502845511211.25", // BESSELJ "=BESSELJ(1.9,2)": "0.329925727692387", // BESSELK "=BESSELK(0.05,0)": "3.11423403428966", - "=BESSELK(0.05,1)": "19.90967432724863", + "=BESSELK(0.05,1)": "19.9096743272486", "=BESSELK(0.05,2)": "799.501207124235", "=BESSELK(3,2)": "0.0615104585619118", // BESSELY "=BESSELY(0.05,0)": "-1.97931100684153", - "=BESSELY(0.05,1)": "-12.789855163794034", - "=BESSELY(0.05,2)": "-509.61489554491976", + "=BESSELY(0.05,1)": "-12.789855163794", + "=BESSELY(0.05,2)": "-509.61489554492", "=BESSELY(9,2)": "-0.229082087487741", // BIN2DEC "=BIN2DEC(\"10\")": "2", @@ -213,7 +213,7 @@ func TestCalcCellValue(t *testing.T) { "=IMCOSH(\"2-i\")": "2.0327230070196656-3.0518977991518i", "=IMCOSH(COMPLEX(1,-1))": "0.8337300251311491-0.9888977057628651i", // IMCOT - "=IMCOT(0.5)": "1.830487721712452", + "=IMCOT(0.5)": "1.83048772171245", "=IMCOT(\"3+0.5i\")": "-0.4793455787473728-2.016092521506228i", "=IMCOT(\"2-i\")": "-0.171383612909185+0.8213297974938518i", "=IMCOT(COMPLEX(1,-1))": "0.21762156185440268+0.868014142895925i", @@ -247,7 +247,7 @@ func TestCalcCellValue(t *testing.T) { "=IMREAL(\"3i\")": "0", "=IMREAL(COMPLEX(4,1))": "4", // IMSEC - "=IMSEC(0.5)": "1.139493927324549", + "=IMSEC(0.5)": "1.13949392732455", "=IMSEC(\"3+0.5i\")": "-0.8919131797403304+0.05875317818173977i", "=IMSEC(\"2-i\")": "-0.4131493442669401-0.687527438655479i", "=IMSEC(COMPLEX(1,-1))": "0.49833703055518686-0.5910838417210451i", @@ -271,7 +271,7 @@ func TestCalcCellValue(t *testing.T) { "=IMSQRT(\"i\")": "0.7071067811865476+0.7071067811865476i", "=IMSQRT(\"2-i\")": "1.455346690225355-0.34356074972251244i", "=IMSQRT(\"5+2i\")": "2.27872385417085+0.4388421169022545i", - "=IMSQRT(6)": "2.449489742783178", + "=IMSQRT(6)": "2.44948974278318", "=IMSQRT(\"-2-4i\")": "1.1117859405028423-1.7989074399478673i", // IMSUB "=IMSUB(\"5+i\",\"1+4i\")": "4-3i", @@ -313,17 +313,17 @@ func TestCalcCellValue(t *testing.T) { "=ABS(2-4.5)": "2.5", "=ABS(ABS(-1))": "1", // ACOS - "=ACOS(-1)": "3.141592653589793", + "=ACOS(-1)": "3.14159265358979", "=ACOS(0)": "1.5707963267949", "=ACOS(ABS(0))": "1.5707963267949", // ACOSH "=ACOSH(1)": "0", - "=ACOSH(2.5)": "1.566799236972411", + "=ACOSH(2.5)": "1.56679923697241", "=ACOSH(5)": "2.29243166956118", "=ACOSH(ACOSH(5))": "1.47138332153668", // ACOT "=_xlfn.ACOT(1)": "0.785398163397448", - "=_xlfn.ACOT(-2)": "2.677945044588987", + "=_xlfn.ACOT(-2)": "2.67794504458899", "=_xlfn.ACOT(0)": "1.5707963267949", "=_xlfn.ACOT(_xlfn.ACOT(0))": "0.566911504941009", // ACOTH @@ -445,9 +445,9 @@ func TestCalcCellValue(t *testing.T) { `=_xlfn.DECIMAL("70122",8)`: "28754", `=_xlfn.DECIMAL("0x70122",8)`: "28754", // DEGREES - "=DEGREES(1)": "57.29577951308232", - "=DEGREES(2.5)": "143.2394487827058", - "=DEGREES(DEGREES(1))": "3282.806350011744", + "=DEGREES(1)": "57.2957795130823", + "=DEGREES(2.5)": "143.239448782706", + "=DEGREES(DEGREES(1))": "3282.80635001174", // EVEN "=EVEN(23)": "24", "=EVEN(2.22)": "4", @@ -461,7 +461,7 @@ func TestCalcCellValue(t *testing.T) { "=EXP(0.1)": "1.10517091807565", "=EXP(0)": "1", "=EXP(-5)": "0.00673794699908547", - "=EXP(EXP(0))": "2.718281828459045", + "=EXP(EXP(0))": "2.71828182845905", // FACT "=FACT(3)": "6", "=FACT(6)": "720", @@ -473,12 +473,12 @@ func TestCalcCellValue(t *testing.T) { "=FACTDOUBLE(13)": "135135", "=FACTDOUBLE(FACTDOUBLE(1))": "1", // FLOOR - "=FLOOR(26.75,0.1)": "26.700000000000003", + "=FLOOR(26.75,0.1)": "26.7", "=FLOOR(26.75,0.5)": "26.5", "=FLOOR(26.75,1)": "26", "=FLOOR(26.75,10)": "20", "=FLOOR(26.75,20)": "20", - "=FLOOR(-26.75,-0.1)": "-26.700000000000003", + "=FLOOR(-26.75,-0.1)": "-26.7", "=FLOOR(-26.75,-1)": "-26", "=FLOOR(-26.75,-5)": "-25", "=FLOOR(FLOOR(26.75,1),1)": "26", @@ -493,7 +493,7 @@ func TestCalcCellValue(t *testing.T) { "=_xlfn.FLOOR.MATH(-58.55,10)": "-60", "=_xlfn.FLOOR.MATH(_xlfn.FLOOR.MATH(1),10)": "0", // _xlfn.FLOOR.PRECISE - "=_xlfn.FLOOR.PRECISE(26.75,0.1)": "26.700000000000003", + "=_xlfn.FLOOR.PRECISE(26.75,0.1)": "26.7", "=_xlfn.FLOOR.PRECISE(26.75,0.5)": "26.5", "=_xlfn.FLOOR.PRECISE(26.75,1)": "26", "=_xlfn.FLOOR.PRECISE(26.75)": "26", @@ -524,7 +524,7 @@ func TestCalcCellValue(t *testing.T) { "=ISO.CEILING(22.25,0.1)": "22.3", "=ISO.CEILING(22.25,10)": "30", "=ISO.CEILING(-22.25,1)": "-22", - "=ISO.CEILING(-22.25,0.1)": "-22.200000000000003", + "=ISO.CEILING(-22.25,0.1)": "-22.2", "=ISO.CEILING(-22.25,5)": "-20", "=ISO.CEILING(-22.25,0)": "0", "=ISO.CEILING(1,ISO.CEILING(1,0))": "0", @@ -539,7 +539,7 @@ func TestCalcCellValue(t *testing.T) { `=LCM(0,LCM(0,0))`: "0", // LN "=LN(1)": "0", - "=LN(100)": "4.605170185988092", + "=LN(100)": "4.60517018598809", "=LN(0.5)": "-0.693147180559945", "=LN(LN(100))": "1.5271796258079", // LOG @@ -557,7 +557,7 @@ func TestCalcCellValue(t *testing.T) { // IMLOG2 "=IMLOG2(\"5+2i\")": "2.4289904975637864+0.5489546632866347i", "=IMLOG2(\"2-i\")": "1.1609640474436813-0.6689021062254881i", - "=IMLOG2(6)": "2.584962500721156", + "=IMLOG2(6)": "2.58496250072116", "=IMLOG2(\"3i\")": "1.584962500721156+2.266180070913597i", "=IMLOG2(\"4+i\")": "2.04373142062517+0.3534295024167349i", // IMPOWER @@ -604,7 +604,7 @@ func TestCalcCellValue(t *testing.T) { "=ODD(-3)": "-3", "=ODD(ODD(1))": "1", // PI - "=PI()": "3.141592653589793", + "=PI()": "3.14159265358979", // POWER "=POWER(4,2)": "16", "=POWER(4,POWER(1,1))": "4", @@ -619,9 +619,9 @@ func TestCalcCellValue(t *testing.T) { "=QUOTIENT(QUOTIENT(1,2),3)": "0", // RADIANS "=RADIANS(50)": "0.872664625997165", - "=RADIANS(-180)": "-3.141592653589793", - "=RADIANS(180)": "3.141592653589793", - "=RADIANS(360)": "6.283185307179586", + "=RADIANS(-180)": "-3.14159265358979", + "=RADIANS(180)": "3.14159265358979", + "=RADIANS(360)": "6.28318530717959", "=RADIANS(RADIANS(360))": "0.109662271123215", // ROMAN "=ROMAN(499,0)": "CDXCIX", @@ -634,9 +634,9 @@ func TestCalcCellValue(t *testing.T) { "=ROMAN(1999,5)": "MIM", "=ROMAN(1999,ODD(1))": "MLMVLIV", // ROUND - "=ROUND(100.319,1)": "100.30000000000001", - "=ROUND(5.28,1)": "5.300000000000001", - "=ROUND(5.9999,3)": "6.000000000000002", + "=ROUND(100.319,1)": "100.3", + "=ROUND(5.28,1)": "5.3", + "=ROUND(5.9999,3)": "6", "=ROUND(99.5,0)": "100", "=ROUND(-6.3,0)": "-6", "=ROUND(-100.5,0)": "-101", @@ -646,18 +646,18 @@ func TestCalcCellValue(t *testing.T) { "=ROUND(ROUND(100,1),-1)": "100", // ROUNDDOWN "=ROUNDDOWN(99.999,1)": "99.9", - "=ROUNDDOWN(99.999,2)": "99.99000000000002", + "=ROUNDDOWN(99.999,2)": "99.99", "=ROUNDDOWN(99.999,0)": "99", "=ROUNDDOWN(99.999,-1)": "90", - "=ROUNDDOWN(-99.999,2)": "-99.99000000000002", + "=ROUNDDOWN(-99.999,2)": "-99.99", "=ROUNDDOWN(-99.999,-1)": "-90", "=ROUNDDOWN(ROUNDDOWN(100,1),-1)": "100", // ROUNDUP` - "=ROUNDUP(11.111,1)": "11.200000000000001", - "=ROUNDUP(11.111,2)": "11.120000000000003", + "=ROUNDUP(11.111,1)": "11.2", + "=ROUNDUP(11.111,2)": "11.12", "=ROUNDUP(11.111,0)": "12", "=ROUNDUP(11.111,-1)": "20", - "=ROUNDUP(-11.111,2)": "-11.120000000000003", + "=ROUNDUP(-11.111,2)": "-11.12", "=ROUNDUP(-11.111,-1)": "-20", "=ROUNDUP(ROUNDUP(100,1),-1)": "100", // SEC @@ -681,26 +681,26 @@ func TestCalcCellValue(t *testing.T) { // SINH "=SINH(0)": "0", "=SINH(0.5)": "0.521095305493747", - "=SINH(-2)": "-3.626860407847019", + "=SINH(-2)": "-3.62686040784702", "=SINH(SINH(0))": "0", // SQRT "=SQRT(4)": "2", "=SQRT(SQRT(16))": "2", // SQRTPI - "=SQRTPI(5)": "3.963327297606011", + "=SQRTPI(5)": "3.96332729760601", "=SQRTPI(0.2)": "0.792665459521202", - "=SQRTPI(100)": "17.72453850905516", + "=SQRTPI(100)": "17.7245385090552", "=SQRTPI(0)": "0", "=SQRTPI(SQRTPI(0))": "0", // STDEV - "=STDEV(F2:F9)": "10724.978287523809", + "=STDEV(F2:F9)": "10724.9782875238", "=STDEV(MUNIT(2))": "0.577350269189626", "=STDEV(0,INT(0))": "0", "=STDEV(INT(1),INT(1))": "0", // STDEV.S - "=STDEV.S(F2:F9)": "10724.978287523809", + "=STDEV.S(F2:F9)": "10724.9782875238", // STDEVA - "=STDEVA(F2:F9)": "10724.978287523809", + "=STDEVA(F2:F9)": "10724.9782875238", "=STDEVA(MUNIT(2))": "0.577350269189626", "=STDEVA(0,INT(0))": "0", // POISSON.DIST @@ -723,7 +723,7 @@ func TestCalcCellValue(t *testing.T) { "=SUM(SUM(1+2/1)*2-3/2,2)": "6.5", "=((3+5*2)+3)/5+(-6)/4*2+3": "3.2", "=1+SUM(SUM(1,2*3),4)*-4/2+5+(4+2)*3": "2", - "=1+SUM(SUM(1,2*3),4)*4/3+5+(4+2)*3": "38.666666666666664", + "=1+SUM(SUM(1,2*3),4)*4/3+5+(4+2)*3": "38.6666666666667", "=SUM(1+ROW())": "2", "=SUM((SUM(2))+1)": "3", // SUMIF @@ -754,7 +754,7 @@ func TestCalcCellValue(t *testing.T) { // SUMXMY2 "=SUMXMY2(A1:A4,B1:B4)": "18", // TAN - "=TAN(1.047197551)": "1.732050806782486", + "=TAN(1.047197551)": "1.73205080678249", "=TAN(0)": "0", "=TAN(TAN(0))": "0", // TANH @@ -796,7 +796,7 @@ func TestCalcCellValue(t *testing.T) { "=BETADIST(0.4,2,100)": "1", "=BETADIST(0.75,3,4)": "0.96240234375", "=BETADIST(0.2,0.7,4)": "0.71794309318323", - "=BETADIST(0.01,3,4)": "1.955359E-05", + "=BETADIST(0.01,3,4)": "1.9553589999999998e-05", "=BETADIST(0.75,130,140)": "1", // BETAINV "=BETAINV(0.2,4,5,0,1)": "0.303225844664082", @@ -808,7 +808,7 @@ func TestCalcCellValue(t *testing.T) { // CHIINV "=CHIINV(0.5,1)": "0.454936423119572", "=CHIINV(0.75,1)": "0.101531044267622", - "=CHIINV(0.1,2)": "4.605170185988088", + "=CHIINV(0.1,2)": "4.60517018598809", "=CHIINV(0.8,2)": "0.446287102628419", // CONFIDENCE "=CONFIDENCE(0.05,0.07,100)": "0.0137197479028414", @@ -850,10 +850,10 @@ func TestCalcCellValue(t *testing.T) { "=FISHERINV(INT(0))": "0", "=FISHERINV(2.8)": "0.992631520201128", // GAMMA - "=GAMMA(0.1)": "9.513507698668732", + "=GAMMA(0.1)": "9.51350769866873", "=GAMMA(INT(1))": "1", "=GAMMA(1.5)": "0.886226925452758", - "=GAMMA(5.5)": "52.34277778455352", + "=GAMMA(5.5)": "52.3427777845535", // GAMMA.DIST "=GAMMA.DIST(6,3,2,FALSE)": "0.112020903827694", "=GAMMA.DIST(6,3,2,TRUE)": "0.576809918873156", @@ -861,10 +861,10 @@ func TestCalcCellValue(t *testing.T) { "=GAMMADIST(6,3,2,FALSE)": "0.112020903827694", "=GAMMADIST(6,3,2,TRUE)": "0.576809918873156", // GAMMA.INV - "=GAMMA.INV(0.5,3,2)": "5.348120627447122", + "=GAMMA.INV(0.5,3,2)": "5.34812062744712", "=GAMMA.INV(0.5,0.5,1)": "0.227468211559786", // GAMMAINV - "=GAMMAINV(0.5,3,2)": "5.348120627447122", + "=GAMMAINV(0.5,3,2)": "5.34812062744712", "=GAMMAINV(0.5,0.5,1)": "0.227468211559786", // GAMMALN "=GAMMALN(4.5)": "2.45373657084244", @@ -925,11 +925,11 @@ func TestCalcCellValue(t *testing.T) { "=NORMDIST(0.8,1,0.3,TRUE)": "0.252492537546923", "=NORMDIST(50,40,20,FALSE)": "0.017603266338215", // NORM.INV - "=NORM.INV(0.6,5,2)": "5.506694205719997", + "=NORM.INV(0.6,5,2)": "5.50669420572", // NORMINV - "=NORMINV(0.6,5,2)": "5.506694205719997", - "=NORMINV(0.99,40,1.5)": "43.489521811582044", - "=NORMINV(0.02,40,1.5)": "36.91937663649545", + "=NORMINV(0.6,5,2)": "5.50669420572", + "=NORMINV(0.99,40,1.5)": "43.489521811582", + "=NORMINV(0.02,40,1.5)": "36.9193766364954", // NORM.S.DIST "=NORM.S.DIST(0.8,TRUE)": "0.788144601416603", // NORMSDIST @@ -1052,7 +1052,7 @@ func TestCalcCellValue(t *testing.T) { "=TRIMMEAN(A1:B4,10%)": "2.5", "=TRIMMEAN(A1:B4,70%)": "2.5", // VAR - "=VAR(1,3,5,0,C1)": "4.916666666666667", + "=VAR(1,3,5,0,C1)": "4.91666666666667", "=VAR(1,3,5,0,C1,TRUE)": "4", // VARA "=VARA(1,3,5,0,C1)": "4.7", @@ -1063,16 +1063,16 @@ func TestCalcCellValue(t *testing.T) { // VAR.P "=VAR.P(A1:A5)": "1.25", // VAR.S - "=VAR.S(1,3,5,0,C1)": "4.916666666666667", + "=VAR.S(1,3,5,0,C1)": "4.91666666666667", "=VAR.S(1,3,5,0,C1,TRUE)": "4", // VARPA "=VARPA(1,3,5,0,C1)": "3.76", "=VARPA(1,3,5,0,C1,TRUE)": "3.22222222222222", // WEIBULL - "=WEIBULL(1,3,1,FALSE)": "1.103638323514327", + "=WEIBULL(1,3,1,FALSE)": "1.10363832351433", "=WEIBULL(2,5,1.5,TRUE)": "0.985212776817482", // WEIBULL.DIST - "=WEIBULL.DIST(1,3,1,FALSE)": "1.103638323514327", + "=WEIBULL.DIST(1,3,1,FALSE)": "1.10363832351433", "=WEIBULL.DIST(2,5,1.5,TRUE)": "0.985212776817482", // Information Functions // ERROR.TYPE @@ -1286,7 +1286,7 @@ func TestCalcCellValue(t *testing.T) { "=YEARFRAC(\"01/31/2015\",\"03/31/2015\")": "0.166666666666667", "=YEARFRAC(\"01/30/2015\",\"03/31/2015\")": "0.166666666666667", "=YEARFRAC(\"02/29/2000\", \"02/29/2008\")": "8", - "=YEARFRAC(\"02/29/2000\", \"02/29/2008\",1)": "7.998175182481752", + "=YEARFRAC(\"02/29/2000\", \"02/29/2008\",1)": "7.99817518248175", "=YEARFRAC(\"02/29/2000\", \"01/29/2001\",1)": "0.915300546448087", "=YEARFRAC(\"02/29/2000\", \"03/29/2000\",1)": "0.0792349726775956", "=YEARFRAC(\"01/31/2000\", \"03/29/2000\",4)": "0.163888888888889", @@ -1472,7 +1472,7 @@ func TestCalcCellValue(t *testing.T) { "=VALUE(\"5,000\")": "5000", "=VALUE(\"20%\")": "0.2", "=VALUE(\"12:00:00\")": "0.5", - "=VALUE(\"01/02/2006 15:04:05\")": "38719.62783564815", + "=VALUE(\"01/02/2006 15:04:05\")": "38719.6278356481", // Conditional Functions // IF "=IF(1=1)": "TRUE", @@ -1627,16 +1627,16 @@ func TestCalcCellValue(t *testing.T) { "=COUPPCD(\"10/25/2011\",\"01/01/2012\",4)": "40817", // CUMIPMT "=CUMIPMT(0.05/12,60,50000,1,12,0)": "-2294.97753732664", - "=CUMIPMT(0.05/12,60,50000,13,24,0)": "-1833.1000665738893", + "=CUMIPMT(0.05/12,60,50000,13,24,0)": "-1833.10006657389", // CUMPRINC - "=CUMPRINC(0.05/12,60,50000,1,12,0)": "-9027.762649079885", - "=CUMPRINC(0.05/12,60,50000,13,24,0)": "-9489.640119832635", + "=CUMPRINC(0.05/12,60,50000,1,12,0)": "-9027.76264907988", + "=CUMPRINC(0.05/12,60,50000,13,24,0)": "-9489.64011983263", // DB "=DB(0,1000,5,1)": "0", "=DB(10000,1000,5,1)": "3690", "=DB(10000,1000,5,2)": "2328.39", "=DB(10000,1000,5,1,6)": "1845", - "=DB(10000,1000,5,6,6)": "238.52712458788187", + "=DB(10000,1000,5,6,6)": "238.527124587882", // DDB "=DDB(0,1000,5,1)": "0", "=DDB(10000,1000,5,1)": "4000", @@ -1651,13 +1651,13 @@ func TestCalcCellValue(t *testing.T) { // DOLLARFR "=DOLLARFR(1.0625,16)": "1.01", // DURATION - "=DURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4)": "6.674422798483131", + "=DURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4)": "6.67442279848313", // EFFECT "=EFFECT(0.1,4)": "0.103812890625", "=EFFECT(0.025,2)": "0.02515625", // FV - "=FV(0.05/12,60,-1000)": "68006.08284084337", - "=FV(0.1/4,16,-2000,0,1)": "39729.46089416617", + "=FV(0.05/12,60,-1000)": "68006.0828408434", + "=FV(0.1/4,16,-2000,0,1)": "39729.4608941662", "=FV(0,16,-2000)": "32000", // FVSCHEDULE "=FVSCHEDULE(10000,A1:A5)": "240000", @@ -1665,60 +1665,60 @@ func TestCalcCellValue(t *testing.T) { // INTRATE "=INTRATE(\"04/01/2005\",\"03/31/2010\",1000,2125)": "0.225", // IPMT - "=IPMT(0.05/12,2,60,50000)": "-205.26988187971995", - "=IPMT(0.035/4,2,8,0,5000,1)": "5.257455237829077", + "=IPMT(0.05/12,2,60,50000)": "-205.26988187972", + "=IPMT(0.035/4,2,8,0,5000,1)": "5.25745523782908", // ISPMT - "=ISPMT(0.05/12,1,60,50000)": "-204.8611111111111", - "=ISPMT(0.05/12,2,60,50000)": "-201.38888888888886", - "=ISPMT(0.05/12,2,1,50000)": "208.33333333333334", + "=ISPMT(0.05/12,1,60,50000)": "-204.861111111111", + "=ISPMT(0.05/12,2,60,50000)": "-201.388888888889", + "=ISPMT(0.05/12,2,1,50000)": "208.333333333333", // MDURATION - "=MDURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4)": "6.543551763218756", + "=MDURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4)": "6.54355176321876", // NOMINAL "=NOMINAL(0.025,12)": "0.0247180352381129", // NPER - "=NPER(0.04,-6000,50000)": "10.338035071507665", - "=NPER(0,-6000,50000)": "8.333333333333334", - "=NPER(0.06/4,-2000,60000,30000,1)": "52.794773709274764", + "=NPER(0.04,-6000,50000)": "10.3380350715077", + "=NPER(0,-6000,50000)": "8.33333333333333", + "=NPER(0.06/4,-2000,60000,30000,1)": "52.7947737092748", // NPV - "=NPV(0.02,-5000,\"\",800)": "-4133.025759323337", + "=NPV(0.02,-5000,\"\",800)": "-4133.02575932334", // ODDFPRICE - "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"03/31/2017\",5.5%,3.5%,100,2)": "107.69183025662932", - "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"03/31/2017\",5.5%,3.5%,100,4,1)": "106.76691501092883", - "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"03/31/2017\",5.5%,3.5%,100,4,3)": "106.7819138146997", - "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"03/31/2017\",5.5%,3.5%,100,4,4)": "106.77191377246672", - "=ODDFPRICE(\"11/11/2008\",\"03/01/2021\",\"10/15/2008\",\"03/01/2009\",7.85%,6.25%,100,2,1)": "113.59771747407883", - "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"09/30/2017\",5.5%,3.5%,100,4,0)": "106.72930611878041", - "=ODDFPRICE(\"11/11/2008\",\"03/29/2021\", \"08/15/2008\", \"03/29/2009\", 0.0785, 0.0625, 100, 2, 1)": "113.61826640813996", + "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"03/31/2017\",5.5%,3.5%,100,2)": "107.691830256629", + "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"03/31/2017\",5.5%,3.5%,100,4,1)": "106.766915010929", + "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"03/31/2017\",5.5%,3.5%,100,4,3)": "106.7819138147", + "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"03/31/2017\",5.5%,3.5%,100,4,4)": "106.771913772467", + "=ODDFPRICE(\"11/11/2008\",\"03/01/2021\",\"10/15/2008\",\"03/01/2009\",7.85%,6.25%,100,2,1)": "113.597717474079", + "=ODDFPRICE(\"02/01/2017\",\"03/31/2021\",\"12/01/2016\",\"09/30/2017\",5.5%,3.5%,100,4,0)": "106.72930611878", + "=ODDFPRICE(\"11/11/2008\",\"03/29/2021\", \"08/15/2008\", \"03/29/2009\", 0.0785, 0.0625, 100, 2, 1)": "113.61826640814", // PDURATION - "=PDURATION(0.04,10000,15000)": "10.33803507150765", + "=PDURATION(0.04,10000,15000)": "10.3380350715076", // PMT "=PMT(0,8,0,5000,1)": "-625", - "=PMT(0.035/4,8,0,5000,1)": "-600.8520271804658", + "=PMT(0.035/4,8,0,5000,1)": "-600.852027180466", // PRICE - "=PRICE(\"04/01/2012\",\"02/01/2020\",12%,10%,100,2)": "110.65510517844305", - "=PRICE(\"04/01/2012\",\"02/01/2020\",12%,10%,100,2,4)": "110.65510517844305", - "=PRICE(\"04/01/2012\",\"03/31/2020\",12%,10%,100,2)": "110.83448359321572", - "=PRICE(\"01/01/2010\",\"06/30/2010\",0.5,1,1,1,4)": "8.924190888476605", + "=PRICE(\"04/01/2012\",\"02/01/2020\",12%,10%,100,2)": "110.655105178443", + "=PRICE(\"04/01/2012\",\"02/01/2020\",12%,10%,100,2,4)": "110.655105178443", + "=PRICE(\"04/01/2012\",\"03/31/2020\",12%,10%,100,2)": "110.834483593216", + "=PRICE(\"01/01/2010\",\"06/30/2010\",0.5,1,1,1,4)": "8.92419088847661", // PPMT - "=PPMT(0.05/12,2,60,50000)": "-738.2918003208238", - "=PPMT(0.035/4,2,8,0,5000,1)": "-606.1094824182949", + "=PPMT(0.05/12,2,60,50000)": "-738.291800320824", + "=PPMT(0.035/4,2,8,0,5000,1)": "-606.109482418295", // PRICEDISC "=PRICEDISC(\"04/01/2017\",\"03/31/2021\",2.5%,100)": "90", "=PRICEDISC(\"04/01/2017\",\"03/31/2021\",2.5%,100,3)": "90", // PRICEMAT - "=PRICEMAT(\"04/01/2017\",\"03/31/2021\",\"01/01/2017\",4.5%,2.5%)": "107.17045454545453", - "=PRICEMAT(\"04/01/2017\",\"03/31/2021\",\"01/01/2017\",4.5%,2.5%,0)": "107.17045454545453", + "=PRICEMAT(\"04/01/2017\",\"03/31/2021\",\"01/01/2017\",4.5%,2.5%)": "107.170454545455", + "=PRICEMAT(\"04/01/2017\",\"03/31/2021\",\"01/01/2017\",4.5%,2.5%,0)": "107.170454545455", // PV "=PV(0,60,1000)": "-60000", - "=PV(5%/12,60,1000)": "-52990.70632392748", - "=PV(10%/4,16,2000,0,1)": "-26762.75545288113", + "=PV(5%/12,60,1000)": "-52990.7063239275", + "=PV(10%/4,16,2000,0,1)": "-26762.7554528811", // RATE "=RATE(60,-1000,50000)": "0.0061834131621292", "=RATE(24,-800,0,20000,1)": "0.00325084350160374", "=RATE(48,-200,8000,3,1,0.5)": "0.0080412665831637", // RECEIVED - "=RECEIVED(\"04/01/2011\",\"03/31/2016\",1000,4.5%)": "1290.3225806451612", - "=RECEIVED(\"04/01/2011\",\"03/31/2016\",1000,4.5%,0)": "1290.3225806451612", + "=RECEIVED(\"04/01/2011\",\"03/31/2016\",1000,4.5%)": "1290.32258064516", + "=RECEIVED(\"04/01/2011\",\"03/31/2016\",1000,4.5%,0)": "1290.32258064516", // RRI "=RRI(10,10000,15000)": "0.0413797439924106", // SLN @@ -1729,7 +1729,7 @@ func TestCalcCellValue(t *testing.T) { // TBILLEQ "=TBILLEQ(\"01/01/2017\",\"06/30/2017\",2.5%)": "0.0256680731364276", // TBILLPRICE - "=TBILLPRICE(\"02/01/2017\",\"06/30/2017\",2.75%)": "98.86180555555556", + "=TBILLPRICE(\"02/01/2017\",\"06/30/2017\",2.75%)": "98.8618055555556", // TBILLYIELD "=TBILLYIELD(\"02/01/2017\",\"06/30/2017\",99)": "0.024405125076266", // VDB @@ -1739,10 +1739,10 @@ func TestCalcCellValue(t *testing.T) { "=VDB(10000,1000,5,3,5,0.2,FALSE)": "3600", "=VDB(10000,1000,5,3,5,0.2,TRUE)": "693.633024", "=VDB(24000,3000,10,0,0.875,2)": "4200", - "=VDB(24000,3000,10,0.1,1)": "4233.599999999999", - "=VDB(24000,3000,10,0.1,1,1)": "2138.3999999999996", - "=VDB(24000,3000,100,50,100,1)": "10377.294418465235", - "=VDB(24000,3000,100,50,100,2)": "5740.072322090805", + "=VDB(24000,3000,10,0.1,1)": "4233.6", + "=VDB(24000,3000,10,0.1,1,1)": "2138.4", + "=VDB(24000,3000,100,50,100,1)": "10377.2944184652", + "=VDB(24000,3000,100,50,100,2)": "5740.0723220908", // YIELD "=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,100,4)": "0.0975631546829798", "=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,100,4,4)": "0.0976269355643988", @@ -4284,7 +4284,7 @@ func TestCalcXNPV(t *testing.T) { } f := prepareCalcData(cellData) formulaList := map[string]string{ - "=XNPV(B1,B2:B7,A2:A7)": "4447.938009440515", + "=XNPV(B1,B2:B7,A2:A7)": "4447.93800944052", } for formula, expected := range formulaList { assert.NoError(t, f.SetCellFormula("Sheet1", "C1", formula)) diff --git a/cell.go b/cell.go index c3b62dc2..6ecce4fe 100644 --- a/cell.go +++ b/cell.go @@ -1088,22 +1088,12 @@ func (f *File) formattedValue(s int, v string, raw bool) string { if raw { return v } - precise := v - isNum, precision := isNumeric(v) - if isNum { - if precision > 15 { - precise = roundPrecision(v, 15) - } - if precision <= 15 { - precise = roundPrecision(v, -1) - } - } if s == 0 { - return precise + return v } styleSheet := f.stylesReader() if s >= len(styleSheet.CellXfs.Xf) { - return precise + return v } var numFmtID int if styleSheet.CellXfs.Xf[s].NumFmtID != nil { @@ -1112,17 +1102,17 @@ func (f *File) formattedValue(s int, v string, raw bool) string { ok := builtInNumFmtFunc[numFmtID] if ok != nil { - return ok(precise, builtInNumFmt[numFmtID]) + return ok(v, builtInNumFmt[numFmtID]) } if styleSheet == nil || styleSheet.NumFmts == nil { - return precise + return v } for _, xlsxFmt := range styleSheet.NumFmts.NumFmt { if xlsxFmt.NumFmtID == numFmtID { - return format(precise, xlsxFmt.FormatCode) + return format(v, xlsxFmt.FormatCode) } } - return precise + return v } // prepareCellStyle provides a function to prepare style index of cell in diff --git a/file.go b/file.go index 0cfed05e..0135e20e 100644 --- a/file.go +++ b/file.go @@ -81,7 +81,7 @@ func (f *File) SaveAs(name string, opt ...Options) error { return ErrWorkbookExt } f.setContentTypePartProjectExtensions(contentType) - file, err := os.OpenFile(filepath.Clean(name), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600) + file, err := os.OpenFile(filepath.Clean(name), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0o600) if err != nil { return err } diff --git a/lib.go b/lib.go index 5bbbec9c..439e50a8 100644 --- a/lib.go +++ b/lib.go @@ -688,12 +688,15 @@ func isNumeric(s string) (bool, int) { if i == 0 && v == '-' { continue } - if e && (v == '+' || v == '-') { + if e && v == '-' { + return true, 0 + } + if e && v == '+' { p = 15 continue } return false, 0 - } else if dot { + } else { p++ } n = true diff --git a/lib_test.go b/lib_test.go index 1e2f3249..027e5dd6 100644 --- a/lib_test.go +++ b/lib_test.go @@ -342,7 +342,7 @@ func TestReadBytes(t *testing.T) { func TestUnzipToTemp(t *testing.T) { os.Setenv("TMPDIR", "test") defer os.Unsetenv("TMPDIR") - assert.NoError(t, os.Chmod(os.TempDir(), 0444)) + assert.NoError(t, os.Chmod(os.TempDir(), 0o444)) f := NewFile() data := []byte("PK\x03\x040000000PK\x01\x0200000" + "0000000000000000000\x00" + @@ -364,7 +364,7 @@ func TestUnzipToTemp(t *testing.T) { _, err = f.unzipToTemp(z.File[0]) require.Error(t, err) - assert.NoError(t, os.Chmod(os.TempDir(), 0755)) + assert.NoError(t, os.Chmod(os.TempDir(), 0o755)) _, err = f.unzipToTemp(z.File[0]) assert.EqualError(t, err, "EOF") diff --git a/numfmt.go b/numfmt.go index 50ce1f31..3b20e028 100644 --- a/numfmt.go +++ b/numfmt.go @@ -13,6 +13,7 @@ package excelize import ( "fmt" + "math" "strconv" "strings" "time" @@ -41,13 +42,15 @@ type numberFormat struct { var ( // supportedTokenTypes list the supported number format token types currently. supportedTokenTypes = []string{ + nfp.TokenSubTypeLanguageInfo, + nfp.TokenTypeColor, nfp.TokenTypeCurrencyLanguage, nfp.TokenTypeDateTimes, nfp.TokenTypeElapsedDateTimes, nfp.TokenTypeGeneral, nfp.TokenTypeLiteral, nfp.TokenTypeTextPlaceHolder, - nfp.TokenSubTypeLanguageInfo, + nfp.TokenTypeZeroPlaceHolder, } // supportedLanguageInfo directly maps the supported language ID and tags. supportedLanguageInfo = map[string]languageInfo{ @@ -276,11 +279,9 @@ var ( // prepareNumberic split the number into two before and after parts by a // decimal point. func (nf *numberFormat) prepareNumberic(value string) { - prec := 0 - if nf.isNumberic, prec = isNumeric(value); !nf.isNumberic { + if nf.isNumberic, _ = isNumeric(value); !nf.isNumberic { return } - nf.beforePoint, nf.afterPoint = value[:len(value)-prec-1], value[len(value)-prec:] } // format provides a function to return a string parse by number format @@ -336,6 +337,20 @@ func (nf *numberFormat) positiveHandler() (result string) { nf.result += token.TValue continue } + if token.TType == nfp.TokenTypeZeroPlaceHolder && token.TValue == "0" { + if isNum, precision := isNumeric(nf.value); isNum { + if nf.number < 1 { + nf.result += "0" + continue + } + if precision > 15 { + nf.result += roundPrecision(nf.value, 15) + } else { + nf.result += fmt.Sprintf("%.f", nf.number) + } + continue + } + } } result = nf.result return @@ -874,8 +889,33 @@ func (nf *numberFormat) secondsNext(i int) bool { // negativeHandler will be handling negative selection for a number format // expression. -func (nf *numberFormat) negativeHandler() string { - return nf.value +func (nf *numberFormat) negativeHandler() (result string) { + for _, token := range nf.section[nf.sectionIdx].Items { + if inStrSlice(supportedTokenTypes, token.TType, true) == -1 || token.TType == nfp.TokenTypeGeneral { + result = nf.value + return + } + if token.TType == nfp.TokenTypeLiteral { + nf.result += token.TValue + continue + } + if token.TType == nfp.TokenTypeZeroPlaceHolder && token.TValue == "0" { + if isNum, precision := isNumeric(nf.value); isNum { + if math.Abs(nf.number) < 1 { + nf.result += "0" + continue + } + if precision > 15 { + nf.result += strings.TrimLeft(roundPrecision(nf.value, 15), "-") + } else { + nf.result += fmt.Sprintf("%.f", math.Abs(nf.number)) + } + continue + } + } + } + result = nf.result + return } // zeroHandler will be handling zero selection for a number format expression. diff --git a/numfmt_test.go b/numfmt_test.go index 80534e97..7dc3f770 100644 --- a/numfmt_test.go +++ b/numfmt_test.go @@ -996,6 +996,14 @@ func TestNumFmt(t *testing.T) { {"44896.18957170139", "[$-435]mmmmm dd yyyy h:mm AM/PM", "D 01 2022 4:32 AM"}, {"text_", "General", "text_"}, {"text_", "\"=====\"@@@\"--\"@\"----\"", "=====text_text_text_--text_----"}, + {"0.0450685976001E+21", "0_);[Red]\\(0\\)", "45068597600100000000"}, + {"8.0450685976001E+21", "0_);[Red]\\(0\\)", "8045068597600100000000"}, + {"8.0450685976001E-21", "0_);[Red]\\(0\\)", "0"}, + {"8.04506", "0_);[Red]\\(0\\)", "8"}, + {"-0.0450685976001E+21", "0_);[Red]\\(0\\)", "(45068597600100000000)"}, + {"-8.0450685976001E+21", "0_);[Red]\\(0\\)", "(8045068597600100000000)"}, + {"-8.0450685976001E-21", "0_);[Red]\\(0\\)", "(0)"}, + {"-8.04506", "0_);[Red]\\(0\\)", "(8)"}, } { result := format(item[0], item[1]) assert.Equal(t, item[2], result, item) diff --git a/picture_test.go b/picture_test.go index 8da7c3d8..fbbdf114 100644 --- a/picture_test.go +++ b/picture_test.go @@ -102,7 +102,7 @@ func TestGetPicture(t *testing.T) { file, raw, err := f.GetPicture("Sheet1", "F21") assert.NoError(t, err) if !assert.NotEmpty(t, filepath.Join("test", file)) || !assert.NotEmpty(t, raw) || - !assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0644)) { + !assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0o644)) { t.FailNow() } @@ -137,7 +137,7 @@ func TestGetPicture(t *testing.T) { file, raw, err = f.GetPicture("Sheet1", "F21") assert.NoError(t, err) if !assert.NotEmpty(t, filepath.Join("test", file)) || !assert.NotEmpty(t, raw) || - !assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0644)) { + !assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0o644)) { t.FailNow() } diff --git a/rows.go b/rows.go index ec94c644..ae7e01ed 100644 --- a/rows.go +++ b/rows.go @@ -459,6 +459,13 @@ func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) { } return f.formattedValue(c.S, c.V, raw), nil default: + if isNum, precision := isNumeric(c.V); isNum && !raw { + if precision == 0 { + c.V = roundPrecision(c.V, 15) + } else { + c.V = roundPrecision(c.V, -1) + } + } return f.formattedValue(c.S, c.V, raw), nil } }