| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988 |
- // Copyright 2016 - 2023 The excelize Authors. All rights reserved. Use of
- // this source code is governed by a BSD-style license that can be found in
- // the LICENSE file.
- //
- // Package excelize providing a set of functions that allow you to write to and
- // read from XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and
- // writing spreadsheet documents generated by Microsoft Excel™ 2007 and later.
- // Supports complex components by high compatibility, and provided streaming
- // API for generating or reading data from a worksheet with huge amounts of
- // data. This library needs Go version 1.16 or later.
- package excelize
- import (
- "bytes"
- "container/list"
- "errors"
- "fmt"
- "math"
- "math/big"
- "math/cmplx"
- "math/rand"
- "net/url"
- "reflect"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "sync"
- "time"
- "unicode"
- "unicode/utf8"
- "unsafe"
- "github.com/xuri/efp"
- "golang.org/x/text/language"
- "golang.org/x/text/message"
- )
- const (
- // Excel formula errors
- formulaErrorDIV = "#DIV/0!"
- formulaErrorNAME = "#NAME?"
- formulaErrorNA = "#N/A"
- formulaErrorNUM = "#NUM!"
- formulaErrorVALUE = "#VALUE!"
- formulaErrorREF = "#REF!"
- formulaErrorNULL = "#NULL!"
- formulaErrorSPILL = "#SPILL!"
- formulaErrorCALC = "#CALC!"
- formulaErrorGETTINGDATA = "#GETTING_DATA"
- // Formula criteria condition enumeration
- _ byte = iota
- criteriaEq
- criteriaLe
- criteriaGe
- criteriaNe
- criteriaL
- criteriaG
- criteriaErr
- criteriaRegexp
- categoryWeightAndMass
- categoryDistance
- categoryTime
- categoryPressure
- categoryForce
- categoryEnergy
- categoryPower
- categoryMagnetism
- categoryTemperature
- categoryVolumeAndLiquidMeasure
- categoryArea
- categoryInformation
- categorySpeed
- matchModeExact = 0
- matchModeMinGreater = 1
- matchModeMaxLess = -1
- matchModeWildcard = 2
- searchModeLinear = 1
- searchModeReverseLinear = -1
- searchModeAscBinary = 2
- searchModeDescBinary = -2
- maxFinancialIterations = 128
- financialPrecision = 1.0e-08
- // Date and time format regular expressions
- monthRe = `((jan|january)|(feb|february)|(mar|march)|(apr|april)|(may)|(jun|june)|(jul|july)|(aug|august)|(sep|september)|(oct|october)|(nov|november)|(dec|december))`
- df1 = `(([0-9])+)/(([0-9])+)/(([0-9])+)`
- df2 = monthRe + ` (([0-9])+), (([0-9])+)`
- df3 = `(([0-9])+)-(([0-9])+)-(([0-9])+)`
- df4 = `(([0-9])+)-` + monthRe + `-(([0-9])+)`
- datePrefix = `^((` + df1 + `|` + df2 + `|` + df3 + `|` + df4 + `) )?`
- tfhh = `(([0-9])+) (am|pm)`
- tfhhmm = `(([0-9])+):(([0-9])+)( (am|pm))?`
- tfmmss = `(([0-9])+):(([0-9])+\.([0-9])+)( (am|pm))?`
- tfhhmmss = `(([0-9])+):(([0-9])+):(([0-9])+(\.([0-9])+)?)( (am|pm))?`
- timeSuffix = `( (` + tfhh + `|` + tfhhmm + `|` + tfmmss + `|` + tfhhmmss + `))?$`
- )
- var (
- // tokenPriority defined basic arithmetic operator priority
- tokenPriority = map[string]int{
- "^": 5,
- "*": 4,
- "/": 4,
- "+": 3,
- "-": 3,
- "=": 2,
- "<>": 2,
- "<": 2,
- "<=": 2,
- ">": 2,
- ">=": 2,
- "&": 1,
- }
- month2num = map[string]int{
- "january": 1,
- "february": 2,
- "march": 3,
- "april": 4,
- "may": 5,
- "june": 6,
- "july": 7,
- "august": 8,
- "september": 9,
- "october": 10,
- "november": 11,
- "december": 12,
- "jan": 1,
- "feb": 2,
- "mar": 3,
- "apr": 4,
- "jun": 6,
- "jul": 7,
- "aug": 8,
- "sep": 9,
- "oct": 10,
- "nov": 11,
- "dec": 12,
- }
- dateFormats = map[string]*regexp.Regexp{
- "mm/dd/yy": regexp.MustCompile(`^` + df1 + timeSuffix),
- "mm dd, yy": regexp.MustCompile(`^` + df2 + timeSuffix),
- "yy-mm-dd": regexp.MustCompile(`^` + df3 + timeSuffix),
- "yy-mmStr-dd": regexp.MustCompile(`^` + df4 + timeSuffix),
- }
- timeFormats = map[string]*regexp.Regexp{
- "hh": regexp.MustCompile(datePrefix + tfhh + `$`),
- "hh:mm": regexp.MustCompile(datePrefix + tfhhmm + `$`),
- "mm:ss": regexp.MustCompile(datePrefix + tfmmss + `$`),
- "hh:mm:ss": regexp.MustCompile(datePrefix + tfhhmmss + `$`),
- }
- dateOnlyFormats = []*regexp.Regexp{
- regexp.MustCompile(`^` + df1 + `$`),
- regexp.MustCompile(`^` + df2 + `$`),
- regexp.MustCompile(`^` + df3 + `$`),
- regexp.MustCompile(`^` + df4 + `$`),
- }
- addressFmtMaps = map[string]func(col, row int) (string, error){
- "1_TRUE": func(col, row int) (string, error) {
- return CoordinatesToCellName(col, row, true)
- },
- "1_FALSE": func(col, row int) (string, error) {
- return fmt.Sprintf("R%dC%d", row, col), nil
- },
- "2_TRUE": func(col, row int) (string, error) {
- column, err := ColumnNumberToName(col)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("%s$%d", column, row), nil
- },
- "2_FALSE": func(col, row int) (string, error) {
- return fmt.Sprintf("R%dC[%d]", row, col), nil
- },
- "3_TRUE": func(col, row int) (string, error) {
- column, err := ColumnNumberToName(col)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("$%s%d", column, row), nil
- },
- "3_FALSE": func(col, row int) (string, error) {
- return fmt.Sprintf("R[%d]C%d", row, col), nil
- },
- "4_TRUE": func(col, row int) (string, error) {
- return CoordinatesToCellName(col, row, false)
- },
- "4_FALSE": func(col, row int) (string, error) {
- return fmt.Sprintf("R[%d]C[%d]", row, col), nil
- },
- }
- )
- // calcContext defines the formula execution context.
- type calcContext struct {
- sync.Mutex
- entry string
- maxCalcIterations uint
- iterations map[string]uint
- iterationsCache map[string]formulaArg
- }
- // cellRef defines the structure of a cell reference.
- type cellRef struct {
- Col int
- Row int
- Sheet string
- }
- // cellRef defines the structure of a cell range.
- type cellRange struct {
- From cellRef
- To cellRef
- }
- // formulaCriteria defined formula criteria parser result.
- type formulaCriteria struct {
- Type byte
- Condition string
- }
- // ArgType is the type of formula argument type.
- type ArgType byte
- // Formula argument types enumeration.
- const (
- ArgUnknown ArgType = iota
- ArgNumber
- ArgString
- ArgList
- ArgMatrix
- ArgError
- ArgEmpty
- )
- // formulaArg is the argument of a formula or function.
- type formulaArg struct {
- SheetName string
- Number float64
- String string
- List []formulaArg
- Matrix [][]formulaArg
- Boolean bool
- Error string
- Type ArgType
- cellRefs, cellRanges *list.List
- }
- // Value returns a string data type of the formula argument.
- func (fa formulaArg) Value() (value string) {
- switch fa.Type {
- case ArgNumber:
- if fa.Boolean {
- if fa.Number == 0 {
- return "FALSE"
- }
- return "TRUE"
- }
- return fmt.Sprintf("%g", fa.Number)
- case ArgString:
- return fa.String
- case ArgError:
- return fa.Error
- }
- return
- }
- // ToNumber returns a formula argument with number data type.
- func (fa formulaArg) ToNumber() formulaArg {
- var n float64
- var err error
- switch fa.Type {
- case ArgString:
- n, err = strconv.ParseFloat(fa.String, 64)
- if err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- case ArgNumber:
- n = fa.Number
- }
- return newNumberFormulaArg(n)
- }
- // ToBool returns a formula argument with boolean data type.
- func (fa formulaArg) ToBool() formulaArg {
- var b bool
- var err error
- switch fa.Type {
- case ArgString:
- b, err = strconv.ParseBool(fa.String)
- if err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- case ArgNumber:
- if fa.Boolean && fa.Number == 1 {
- b = true
- }
- }
- return newBoolFormulaArg(b)
- }
- // ToList returns a formula argument with array data type.
- func (fa formulaArg) ToList() []formulaArg {
- switch fa.Type {
- case ArgMatrix:
- var args []formulaArg
- for _, row := range fa.Matrix {
- args = append(args, row...)
- }
- return args
- case ArgList:
- return fa.List
- case ArgNumber, ArgString, ArgError, ArgUnknown:
- return []formulaArg{fa}
- }
- return nil
- }
- // formulaFuncs is the type of the formula functions.
- type formulaFuncs struct {
- f *File
- ctx *calcContext
- sheet, cell string
- }
- // CalcCellValue provides a function to get calculated cell value. This feature
- // is currently in working processing. Iterative calculation, implicit
- // intersection, explicit intersection, array formula, table formula and some
- // other formulas are not supported currently.
- //
- // Supported formula functions:
- //
- // ABS
- // ACCRINT
- // ACCRINTM
- // ACOS
- // ACOSH
- // ACOT
- // ACOTH
- // ADDRESS
- // AGGREGATE
- // AMORDEGRC
- // AMORLINC
- // AND
- // ARABIC
- // ASIN
- // ASINH
- // ATAN
- // ATAN2
- // ATANH
- // AVEDEV
- // AVERAGE
- // AVERAGEA
- // AVERAGEIF
- // AVERAGEIFS
- // BASE
- // BESSELI
- // BESSELJ
- // BESSELK
- // BESSELY
- // BETADIST
- // BETA.DIST
- // BETAINV
- // BETA.INV
- // BIN2DEC
- // BIN2HEX
- // BIN2OCT
- // BINOMDIST
- // BINOM.DIST
- // BINOM.DIST.RANGE
- // BINOM.INV
- // BITAND
- // BITLSHIFT
- // BITOR
- // BITRSHIFT
- // BITXOR
- // CEILING
- // CEILING.MATH
- // CEILING.PRECISE
- // CHAR
- // CHIDIST
- // CHIINV
- // CHITEST
- // CHISQ.DIST
- // CHISQ.DIST.RT
- // CHISQ.INV
- // CHISQ.INV.RT
- // CHISQ.TEST
- // CHOOSE
- // CLEAN
- // CODE
- // COLUMN
- // COLUMNS
- // COMBIN
- // COMBINA
- // COMPLEX
- // CONCAT
- // CONCATENATE
- // CONFIDENCE
- // CONFIDENCE.NORM
- // CONFIDENCE.T
- // CONVERT
- // CORREL
- // COS
- // COSH
- // COT
- // COTH
- // COUNT
- // COUNTA
- // COUNTBLANK
- // COUNTIF
- // COUNTIFS
- // COUPDAYBS
- // COUPDAYS
- // COUPDAYSNC
- // COUPNCD
- // COUPNUM
- // COUPPCD
- // COVAR
- // COVARIANCE.P
- // COVARIANCE.S
- // CRITBINOM
- // CSC
- // CSCH
- // CUMIPMT
- // CUMPRINC
- // DATE
- // DATEDIF
- // DATEVALUE
- // DAVERAGE
- // DAY
- // DAYS
- // DAYS360
- // DB
- // DCOUNT
- // DCOUNTA
- // DDB
- // DEC2BIN
- // DEC2HEX
- // DEC2OCT
- // DECIMAL
- // DEGREES
- // DELTA
- // DEVSQ
- // DGET
- // DISC
- // DMAX
- // DMIN
- // DOLLARDE
- // DOLLARFR
- // DPRODUCT
- // DSTDEV
- // DSTDEVP
- // DSUM
- // DURATION
- // DVAR
- // DVARP
- // EFFECT
- // EDATE
- // ENCODEURL
- // EOMONTH
- // ERF
- // ERF.PRECISE
- // ERFC
- // ERFC.PRECISE
- // ERROR.TYPE
- // EUROCONVERT
- // EVEN
- // EXACT
- // EXP
- // EXPON.DIST
- // EXPONDIST
- // FACT
- // FACTDOUBLE
- // FALSE
- // F.DIST
- // F.DIST.RT
- // FDIST
- // FIND
- // FINDB
- // F.INV
- // F.INV.RT
- // FINV
- // FISHER
- // FISHERINV
- // FIXED
- // FLOOR
- // FLOOR.MATH
- // FLOOR.PRECISE
- // FORMULATEXT
- // F.TEST
- // FTEST
- // FV
- // FVSCHEDULE
- // GAMMA
- // GAMMA.DIST
- // GAMMADIST
- // GAMMA.INV
- // GAMMAINV
- // GAMMALN
- // GAMMALN.PRECISE
- // GAUSS
- // GCD
- // GEOMEAN
- // GESTEP
- // GROWTH
- // HARMEAN
- // HEX2BIN
- // HEX2DEC
- // HEX2OCT
- // HLOOKUP
- // HOUR
- // HYPERLINK
- // HYPGEOM.DIST
- // HYPGEOMDIST
- // IF
- // IFERROR
- // IFNA
- // IFS
- // IMABS
- // IMAGINARY
- // IMARGUMENT
- // IMCONJUGATE
- // IMCOS
- // IMCOSH
- // IMCOT
- // IMCSC
- // IMCSCH
- // IMDIV
- // IMEXP
- // IMLN
- // IMLOG10
- // IMLOG2
- // IMPOWER
- // IMPRODUCT
- // IMREAL
- // IMSEC
- // IMSECH
- // IMSIN
- // IMSINH
- // IMSQRT
- // IMSUB
- // IMSUM
- // IMTAN
- // INDEX
- // INDIRECT
- // INT
- // INTRATE
- // IPMT
- // IRR
- // ISBLANK
- // ISERR
- // ISERROR
- // ISEVEN
- // ISFORMULA
- // ISLOGICAL
- // ISNA
- // ISNONTEXT
- // ISNUMBER
- // ISODD
- // ISREF
- // ISTEXT
- // ISO.CEILING
- // ISOWEEKNUM
- // ISPMT
- // KURT
- // LARGE
- // LCM
- // LEFT
- // LEFTB
- // LEN
- // LENB
- // LN
- // LOG
- // LOG10
- // LOGINV
- // LOGNORM.DIST
- // LOGNORMDIST
- // LOGNORM.INV
- // LOOKUP
- // LOWER
- // MATCH
- // MAX
- // MAXA
- // MAXIFS
- // MDETERM
- // MDURATION
- // MEDIAN
- // MID
- // MIDB
- // MIN
- // MINA
- // MINIFS
- // MINUTE
- // MINVERSE
- // MIRR
- // MMULT
- // MOD
- // MODE
- // MODE.MULT
- // MODE.SNGL
- // MONTH
- // MROUND
- // MULTINOMIAL
- // MUNIT
- // N
- // NA
- // NEGBINOM.DIST
- // NEGBINOMDIST
- // NETWORKDAYS
- // NETWORKDAYS.INTL
- // NOMINAL
- // NORM.DIST
- // NORMDIST
- // NORM.INV
- // NORMINV
- // NORM.S.DIST
- // NORMSDIST
- // NORM.S.INV
- // NORMSINV
- // NOT
- // NOW
- // NPER
- // NPV
- // OCT2BIN
- // OCT2DEC
- // OCT2HEX
- // ODD
- // ODDFPRICE
- // OR
- // PDURATION
- // PEARSON
- // PERCENTILE.EXC
- // PERCENTILE.INC
- // PERCENTILE
- // PERCENTRANK.EXC
- // PERCENTRANK.INC
- // PERCENTRANK
- // PERMUT
- // PERMUTATIONA
- // PHI
- // PI
- // PMT
- // POISSON.DIST
- // POISSON
- // POWER
- // PPMT
- // PRICE
- // PRICEDISC
- // PRICEMAT
- // PRODUCT
- // PROPER
- // PV
- // QUARTILE
- // QUARTILE.EXC
- // QUARTILE.INC
- // QUOTIENT
- // RADIANS
- // RAND
- // RANDBETWEEN
- // RANK
- // RANK.EQ
- // RATE
- // RECEIVED
- // REPLACE
- // REPLACEB
- // REPT
- // RIGHT
- // RIGHTB
- // ROMAN
- // ROUND
- // ROUNDDOWN
- // ROUNDUP
- // ROW
- // ROWS
- // RRI
- // RSQ
- // SEC
- // SECH
- // SECOND
- // SERIESSUM
- // SHEET
- // SHEETS
- // SIGN
- // SIN
- // SINH
- // SKEW
- // SKEW.P
- // SLN
- // SLOPE
- // SMALL
- // SQRT
- // SQRTPI
- // STANDARDIZE
- // STDEV
- // STDEV.P
- // STDEV.S
- // STDEVA
- // STDEVP
- // STDEVPA
- // STEYX
- // SUBSTITUTE
- // SUBTOTAL
- // SUM
- // SUMIF
- // SUMIFS
- // SUMPRODUCT
- // SUMSQ
- // SUMX2MY2
- // SUMX2PY2
- // SUMXMY2
- // SWITCH
- // SYD
- // T
- // TAN
- // TANH
- // TBILLEQ
- // TBILLPRICE
- // TBILLYIELD
- // T.DIST
- // T.DIST.2T
- // T.DIST.RT
- // TDIST
- // TEXTJOIN
- // TIME
- // TIMEVALUE
- // T.INV
- // T.INV.2T
- // TINV
- // TODAY
- // TRANSPOSE
- // TREND
- // TRIM
- // TRIMMEAN
- // TRUE
- // TRUNC
- // T.TEST
- // TTEST
- // TYPE
- // UNICHAR
- // UNICODE
- // UPPER
- // VALUE
- // VAR
- // VAR.P
- // VAR.S
- // VARA
- // VARP
- // VARPA
- // VDB
- // VLOOKUP
- // WEEKDAY
- // WEEKNUM
- // WEIBULL
- // WEIBULL.DIST
- // WORKDAY
- // WORKDAY.INTL
- // XIRR
- // XLOOKUP
- // XNPV
- // XOR
- // YEAR
- // YEARFRAC
- // YIELD
- // YIELDDISC
- // YIELDMAT
- // Z.TEST
- // ZTEST
- func (f *File) CalcCellValue(sheet, cell string, opts ...Options) (result string, err error) {
- var (
- rawCellValue = getOptions(opts...).RawCellValue
- styleIdx int
- token formulaArg
- )
- if token, err = f.calcCellValue(&calcContext{
- entry: fmt.Sprintf("%s!%s", sheet, cell),
- maxCalcIterations: getOptions(opts...).MaxCalcIterations,
- iterations: make(map[string]uint),
- iterationsCache: make(map[string]formulaArg),
- }, sheet, cell); err != nil {
- result = token.String
- return
- }
- if !rawCellValue {
- styleIdx, _ = f.GetCellStyle(sheet, cell)
- }
- result = token.Value()
- if isNum, precision, decimal := isNumeric(result); isNum {
- if precision > 15 {
- result, err = f.formattedValue(styleIdx, strings.ToUpper(strconv.FormatFloat(decimal, 'G', 15, 64)), rawCellValue)
- return
- }
- if !strings.HasPrefix(result, "0") {
- result, err = f.formattedValue(styleIdx, strings.ToUpper(strconv.FormatFloat(decimal, 'f', -1, 64)), rawCellValue)
- }
- }
- return
- }
- // calcCellValue calculate cell value by given context, worksheet name and cell
- // reference.
- func (f *File) calcCellValue(ctx *calcContext, sheet, cell string) (result formulaArg, err error) {
- var formula string
- if formula, err = f.GetCellFormula(sheet, cell); err != nil {
- return
- }
- ps := efp.ExcelParser()
- tokens := ps.Parse(formula)
- if tokens == nil {
- return
- }
- result, err = f.evalInfixExp(ctx, sheet, cell, tokens)
- return
- }
- // getPriority calculate arithmetic operator priority.
- func getPriority(token efp.Token) (pri int) {
- pri = tokenPriority[token.TValue]
- if token.TValue == "-" && token.TType == efp.TokenTypeOperatorPrefix {
- pri = 6
- }
- if isBeginParenthesesToken(token) { // (
- pri = 0
- }
- return
- }
- // newNumberFormulaArg constructs a number formula argument.
- func newNumberFormulaArg(n float64) formulaArg {
- if math.IsNaN(n) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return formulaArg{Type: ArgNumber, Number: n}
- }
- // newStringFormulaArg constructs a string formula argument.
- func newStringFormulaArg(s string) formulaArg {
- return formulaArg{Type: ArgString, String: s}
- }
- // newMatrixFormulaArg constructs a matrix formula argument.
- func newMatrixFormulaArg(m [][]formulaArg) formulaArg {
- return formulaArg{Type: ArgMatrix, Matrix: m}
- }
- // newListFormulaArg create a list formula argument.
- func newListFormulaArg(l []formulaArg) formulaArg {
- return formulaArg{Type: ArgList, List: l}
- }
- // newBoolFormulaArg constructs a boolean formula argument.
- func newBoolFormulaArg(b bool) formulaArg {
- var n float64
- if b {
- n = 1
- }
- return formulaArg{Type: ArgNumber, Number: n, Boolean: true}
- }
- // newErrorFormulaArg create an error formula argument of a given type with a
- // specified error message.
- func newErrorFormulaArg(formulaError, msg string) formulaArg {
- return formulaArg{Type: ArgError, String: formulaError, Error: msg}
- }
- // newEmptyFormulaArg create an empty formula argument.
- func newEmptyFormulaArg() formulaArg {
- return formulaArg{Type: ArgEmpty}
- }
- // evalInfixExp evaluate syntax analysis by given infix expression after
- // lexical analysis. Evaluate an infix expression containing formulas by
- // stacks:
- //
- // opd - Operand
- // opt - Operator
- // opf - Operation formula
- // opfd - Operand of the operation formula
- // opft - Operator of the operation formula
- // args - Arguments list of the operation formula
- //
- // TODO: handle subtypes: Nothing, Text, Logical, Error, Concatenation, Intersection, Union
- func (f *File) evalInfixExp(ctx *calcContext, sheet, cell string, tokens []efp.Token) (formulaArg, error) {
- var err error
- opdStack, optStack, opfStack, opfdStack, opftStack, argsStack := NewStack(), NewStack(), NewStack(), NewStack(), NewStack(), NewStack()
- var inArray, inArrayRow bool
- for i := 0; i < len(tokens); i++ {
- token := tokens[i]
- // out of function stack
- if opfStack.Len() == 0 {
- if err = f.parseToken(ctx, sheet, token, opdStack, optStack); err != nil {
- return newEmptyFormulaArg(), err
- }
- }
- // function start
- if isFunctionStartToken(token) {
- if token.TValue == "ARRAY" {
- inArray = true
- continue
- }
- if token.TValue == "ARRAYROW" {
- inArrayRow = true
- continue
- }
- opfStack.Push(token)
- argsStack.Push(list.New().Init())
- opftStack.Push(token) // to know which operators belong to a function use the function as a separator
- continue
- }
- // in function stack, walk 2 token at once
- if opfStack.Len() > 0 {
- var nextToken efp.Token
- if i+1 < len(tokens) {
- nextToken = tokens[i+1]
- }
- // current token is args or range, skip next token, order required: parse reference first
- if token.TSubType == efp.TokenSubTypeRange {
- if opftStack.Peek().(efp.Token) != opfStack.Peek().(efp.Token) {
- refTo := f.getDefinedNameRefTo(token.TValue, sheet)
- if refTo != "" {
- token.TValue = refTo
- }
- // parse reference: must reference at here
- result, err := f.parseReference(ctx, sheet, token.TValue)
- if err != nil {
- return result, err
- }
- if result.Type == ArgError {
- return result, errors.New(result.Error)
- }
- opfdStack.Push(result)
- continue
- }
- if nextToken.TType == efp.TokenTypeArgument || nextToken.TType == efp.TokenTypeFunction {
- // parse reference: reference or range at here
- refTo := f.getDefinedNameRefTo(token.TValue, sheet)
- if refTo != "" {
- token.TValue = refTo
- }
- result, err := f.parseReference(ctx, sheet, token.TValue)
- if err != nil {
- return newEmptyFormulaArg(), err
- }
- if result.Type == ArgUnknown {
- return newEmptyFormulaArg(), errors.New(formulaErrorVALUE)
- }
- // when current token is range, next token is argument and opfdStack not empty,
- // should push value to opfdStack and continue
- if nextToken.TType == efp.TokenTypeArgument && !opfdStack.Empty() {
- opfdStack.Push(result)
- continue
- }
- argsStack.Peek().(*list.List).PushBack(result)
- continue
- }
- }
- if isEndParenthesesToken(token) && isBeginParenthesesToken(opftStack.Peek().(efp.Token)) {
- if arg := argsStack.Peek().(*list.List).Back(); arg != nil {
- opfdStack.Push(arg.Value.(formulaArg))
- argsStack.Peek().(*list.List).Remove(arg)
- }
- }
- // check current token is opft
- if err = f.parseToken(ctx, sheet, token, opfdStack, opftStack); err != nil {
- return newEmptyFormulaArg(), err
- }
- // current token is arg
- if token.TType == efp.TokenTypeArgument {
- for opftStack.Peek().(efp.Token) != opfStack.Peek().(efp.Token) {
- // calculate trigger
- topOpt := opftStack.Peek().(efp.Token)
- if err := calculate(opfdStack, topOpt); err != nil {
- argsStack.Peek().(*list.List).PushFront(newErrorFormulaArg(formulaErrorVALUE, err.Error()))
- }
- opftStack.Pop()
- }
- if !opfdStack.Empty() {
- argsStack.Peek().(*list.List).PushBack(opfdStack.Pop().(formulaArg))
- }
- continue
- }
- if inArrayRow && isOperand(token) {
- continue
- }
- if inArrayRow && isFunctionStopToken(token) {
- inArrayRow = false
- continue
- }
- if inArray && isFunctionStopToken(token) {
- argsStack.Peek().(*list.List).PushBack(opfdStack.Pop())
- inArray = false
- continue
- }
- if errArg := f.evalInfixExpFunc(ctx, sheet, cell, token, nextToken, opfStack, opdStack, opftStack, opfdStack, argsStack); errArg.Type == ArgError {
- return errArg, errors.New(errArg.Error)
- }
- }
- }
- for optStack.Len() != 0 {
- topOpt := optStack.Peek().(efp.Token)
- if err = calculate(opdStack, topOpt); err != nil {
- return newEmptyFormulaArg(), err
- }
- optStack.Pop()
- }
- if opdStack.Len() == 0 {
- return newEmptyFormulaArg(), ErrInvalidFormula
- }
- return opdStack.Peek().(formulaArg), err
- }
- // evalInfixExpFunc evaluate formula function in the infix expression.
- func (f *File) evalInfixExpFunc(ctx *calcContext, sheet, cell string, token, nextToken efp.Token, opfStack, opdStack, opftStack, opfdStack, argsStack *Stack) formulaArg {
- if !isFunctionStopToken(token) {
- return newEmptyFormulaArg()
- }
- prepareEvalInfixExp(opfStack, opftStack, opfdStack, argsStack)
- // call formula function to evaluate
- arg := callFuncByName(&formulaFuncs{f: f, sheet: sheet, cell: cell, ctx: ctx}, strings.NewReplacer(
- "_xlfn.", "", ".", "dot").Replace(opfStack.Peek().(efp.Token).TValue),
- []reflect.Value{reflect.ValueOf(argsStack.Peek().(*list.List))})
- if arg.Type == ArgError && opfStack.Len() == 1 {
- return arg
- }
- argsStack.Pop()
- opftStack.Pop() // remove current function separator
- opfStack.Pop()
- if opfStack.Len() > 0 { // still in function stack
- if nextToken.TType == efp.TokenTypeOperatorInfix || (opftStack.Len() > 1 && opfdStack.Len() > 0) {
- // mathematics calculate in formula function
- opfdStack.Push(arg)
- } else {
- argsStack.Peek().(*list.List).PushBack(arg)
- }
- } else {
- val := arg.Value()
- if arg.Type == ArgMatrix && len(arg.Matrix) > 0 && len(arg.Matrix[0]) > 0 {
- val = arg.Matrix[0][0].Value()
- }
- opdStack.Push(newStringFormulaArg(val))
- }
- return newEmptyFormulaArg()
- }
- // prepareEvalInfixExp check the token and stack state for formula function
- // evaluate.
- func prepareEvalInfixExp(opfStack, opftStack, opfdStack, argsStack *Stack) {
- // current token is function stop
- for opftStack.Peek().(efp.Token) != opfStack.Peek().(efp.Token) {
- // calculate trigger
- topOpt := opftStack.Peek().(efp.Token)
- if err := calculate(opfdStack, topOpt); err != nil {
- argsStack.Peek().(*list.List).PushBack(newErrorFormulaArg(err.Error(), err.Error()))
- opftStack.Pop()
- continue
- }
- opftStack.Pop()
- }
- argument := true
- if opftStack.Len() > 2 && opfdStack.Len() == 1 {
- topOpt := opftStack.Pop()
- if opftStack.Peek().(efp.Token).TType == efp.TokenTypeOperatorInfix {
- argument = false
- }
- opftStack.Push(topOpt)
- }
- // push opfd to args
- if argument && opfdStack.Len() > 0 {
- argsStack.Peek().(*list.List).PushBack(opfdStack.Pop().(formulaArg))
- }
- }
- // calcPow evaluate exponentiation arithmetic operations.
- func calcPow(rOpd, lOpd formulaArg, opdStack *Stack) error {
- lOpdVal := lOpd.ToNumber()
- if lOpdVal.Type != ArgNumber {
- return errors.New(lOpdVal.Value())
- }
- rOpdVal := rOpd.ToNumber()
- if rOpdVal.Type != ArgNumber {
- return errors.New(rOpdVal.Value())
- }
- opdStack.Push(newNumberFormulaArg(math.Pow(lOpdVal.Number, rOpdVal.Number)))
- return nil
- }
- // calcEq evaluate equal arithmetic operations.
- func calcEq(rOpd, lOpd formulaArg, opdStack *Stack) error {
- opdStack.Push(newBoolFormulaArg(rOpd.Value() == lOpd.Value()))
- return nil
- }
- // calcNEq evaluate not equal arithmetic operations.
- func calcNEq(rOpd, lOpd formulaArg, opdStack *Stack) error {
- opdStack.Push(newBoolFormulaArg(rOpd.Value() != lOpd.Value()))
- return nil
- }
- // calcL evaluate less than arithmetic operations.
- func calcL(rOpd, lOpd formulaArg, opdStack *Stack) error {
- if rOpd.Type == ArgNumber && lOpd.Type == ArgNumber {
- opdStack.Push(newBoolFormulaArg(lOpd.Number < rOpd.Number))
- }
- if rOpd.Type == ArgString && lOpd.Type == ArgString {
- opdStack.Push(newBoolFormulaArg(strings.Compare(lOpd.Value(), rOpd.Value()) == -1))
- }
- if rOpd.Type == ArgNumber && lOpd.Type == ArgString {
- opdStack.Push(newBoolFormulaArg(false))
- }
- if rOpd.Type == ArgString && lOpd.Type == ArgNumber {
- opdStack.Push(newBoolFormulaArg(true))
- }
- return nil
- }
- // calcLe evaluate less than or equal arithmetic operations.
- func calcLe(rOpd, lOpd formulaArg, opdStack *Stack) error {
- if rOpd.Type == ArgNumber && lOpd.Type == ArgNumber {
- opdStack.Push(newBoolFormulaArg(lOpd.Number <= rOpd.Number))
- }
- if rOpd.Type == ArgString && lOpd.Type == ArgString {
- opdStack.Push(newBoolFormulaArg(strings.Compare(lOpd.Value(), rOpd.Value()) != 1))
- }
- if rOpd.Type == ArgNumber && lOpd.Type == ArgString {
- opdStack.Push(newBoolFormulaArg(false))
- }
- if rOpd.Type == ArgString && lOpd.Type == ArgNumber {
- opdStack.Push(newBoolFormulaArg(true))
- }
- return nil
- }
- // calcG evaluate greater than arithmetic operations.
- func calcG(rOpd, lOpd formulaArg, opdStack *Stack) error {
- if rOpd.Type == ArgNumber && lOpd.Type == ArgNumber {
- opdStack.Push(newBoolFormulaArg(lOpd.Number > rOpd.Number))
- }
- if rOpd.Type == ArgString && lOpd.Type == ArgString {
- opdStack.Push(newBoolFormulaArg(strings.Compare(lOpd.Value(), rOpd.Value()) == 1))
- }
- if rOpd.Type == ArgNumber && lOpd.Type == ArgString {
- opdStack.Push(newBoolFormulaArg(true))
- }
- if rOpd.Type == ArgString && lOpd.Type == ArgNumber {
- opdStack.Push(newBoolFormulaArg(false))
- }
- return nil
- }
- // calcGe evaluate greater than or equal arithmetic operations.
- func calcGe(rOpd, lOpd formulaArg, opdStack *Stack) error {
- if rOpd.Type == ArgNumber && lOpd.Type == ArgNumber {
- opdStack.Push(newBoolFormulaArg(lOpd.Number >= rOpd.Number))
- }
- if rOpd.Type == ArgString && lOpd.Type == ArgString {
- opdStack.Push(newBoolFormulaArg(strings.Compare(lOpd.Value(), rOpd.Value()) != -1))
- }
- if rOpd.Type == ArgNumber && lOpd.Type == ArgString {
- opdStack.Push(newBoolFormulaArg(true))
- }
- if rOpd.Type == ArgString && lOpd.Type == ArgNumber {
- opdStack.Push(newBoolFormulaArg(false))
- }
- return nil
- }
- // calcSplice evaluate splice '&' operations.
- func calcSplice(rOpd, lOpd formulaArg, opdStack *Stack) error {
- opdStack.Push(newStringFormulaArg(lOpd.Value() + rOpd.Value()))
- return nil
- }
- // calcAdd evaluate addition arithmetic operations.
- func calcAdd(rOpd, lOpd formulaArg, opdStack *Stack) error {
- lOpdVal := lOpd.ToNumber()
- if lOpdVal.Type != ArgNumber {
- return errors.New(lOpdVal.Value())
- }
- rOpdVal := rOpd.ToNumber()
- if rOpdVal.Type != ArgNumber {
- return errors.New(rOpdVal.Value())
- }
- opdStack.Push(newNumberFormulaArg(lOpdVal.Number + rOpdVal.Number))
- return nil
- }
- // calcSubtract evaluate subtraction arithmetic operations.
- func calcSubtract(rOpd, lOpd formulaArg, opdStack *Stack) error {
- lOpdVal := lOpd.ToNumber()
- if lOpdVal.Type != ArgNumber {
- return errors.New(lOpdVal.Value())
- }
- rOpdVal := rOpd.ToNumber()
- if rOpdVal.Type != ArgNumber {
- return errors.New(rOpdVal.Value())
- }
- opdStack.Push(newNumberFormulaArg(lOpdVal.Number - rOpdVal.Number))
- return nil
- }
- // calcMultiply evaluate multiplication arithmetic operations.
- func calcMultiply(rOpd, lOpd formulaArg, opdStack *Stack) error {
- lOpdVal := lOpd.ToNumber()
- if lOpdVal.Type != ArgNumber {
- return errors.New(lOpdVal.Value())
- }
- rOpdVal := rOpd.ToNumber()
- if rOpdVal.Type != ArgNumber {
- return errors.New(rOpdVal.Value())
- }
- opdStack.Push(newNumberFormulaArg(lOpdVal.Number * rOpdVal.Number))
- return nil
- }
- // calcDiv evaluate division arithmetic operations.
- func calcDiv(rOpd, lOpd formulaArg, opdStack *Stack) error {
- lOpdVal := lOpd.ToNumber()
- if lOpdVal.Type != ArgNumber {
- return errors.New(lOpdVal.Value())
- }
- rOpdVal := rOpd.ToNumber()
- if rOpdVal.Type != ArgNumber {
- return errors.New(rOpdVal.Value())
- }
- if rOpdVal.Number == 0 {
- return errors.New(formulaErrorDIV)
- }
- opdStack.Push(newNumberFormulaArg(lOpdVal.Number / rOpdVal.Number))
- return nil
- }
- // calculate evaluate basic arithmetic operations.
- func calculate(opdStack *Stack, opt efp.Token) error {
- if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorPrefix {
- if opdStack.Len() < 1 {
- return ErrInvalidFormula
- }
- opd := opdStack.Pop().(formulaArg)
- opdStack.Push(newNumberFormulaArg(0 - opd.ToNumber().Number))
- }
- if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorInfix {
- if opdStack.Len() < 2 {
- return ErrInvalidFormula
- }
- rOpd := opdStack.Pop().(formulaArg)
- lOpd := opdStack.Pop().(formulaArg)
- if err := calcSubtract(rOpd, lOpd, opdStack); err != nil {
- return err
- }
- }
- tokenCalcFunc := map[string]func(rOpd, lOpd formulaArg, opdStack *Stack) error{
- "^": calcPow,
- "*": calcMultiply,
- "/": calcDiv,
- "+": calcAdd,
- "=": calcEq,
- "<>": calcNEq,
- "<": calcL,
- "<=": calcLe,
- ">": calcG,
- ">=": calcGe,
- "&": calcSplice,
- }
- fn, ok := tokenCalcFunc[opt.TValue]
- if ok {
- if opdStack.Len() < 2 {
- return ErrInvalidFormula
- }
- rOpd := opdStack.Pop().(formulaArg)
- lOpd := opdStack.Pop().(formulaArg)
- if rOpd.Type == ArgError {
- return errors.New(rOpd.Value())
- }
- if lOpd.Type == ArgError {
- return errors.New(lOpd.Value())
- }
- if err := fn(rOpd, lOpd, opdStack); err != nil {
- return err
- }
- }
- return nil
- }
- // parseOperatorPrefixToken parse operator prefix token.
- func (f *File) parseOperatorPrefixToken(optStack, opdStack *Stack, token efp.Token) (err error) {
- if optStack.Len() == 0 {
- optStack.Push(token)
- return
- }
- tokenPriority := getPriority(token)
- topOpt := optStack.Peek().(efp.Token)
- topOptPriority := getPriority(topOpt)
- if tokenPriority > topOptPriority {
- optStack.Push(token)
- return
- }
- for tokenPriority <= topOptPriority {
- optStack.Pop()
- if err = calculate(opdStack, topOpt); err != nil {
- return
- }
- if optStack.Len() > 0 {
- topOpt = optStack.Peek().(efp.Token)
- topOptPriority = getPriority(topOpt)
- continue
- }
- break
- }
- optStack.Push(token)
- return
- }
- // isFunctionStartToken determine if the token is function start.
- func isFunctionStartToken(token efp.Token) bool {
- return token.TType == efp.TokenTypeFunction && token.TSubType == efp.TokenSubTypeStart
- }
- // isFunctionStopToken determine if the token is function stop.
- func isFunctionStopToken(token efp.Token) bool {
- return token.TType == efp.TokenTypeFunction && token.TSubType == efp.TokenSubTypeStop
- }
- // isBeginParenthesesToken determine if the token is begin parentheses: (.
- func isBeginParenthesesToken(token efp.Token) bool {
- return token.TType == efp.TokenTypeSubexpression && token.TSubType == efp.TokenSubTypeStart
- }
- // isEndParenthesesToken determine if the token is end parentheses: ).
- func isEndParenthesesToken(token efp.Token) bool {
- return token.TType == efp.TokenTypeSubexpression && token.TSubType == efp.TokenSubTypeStop
- }
- // isOperatorPrefixToken determine if the token is parse operator prefix
- // token.
- func isOperatorPrefixToken(token efp.Token) bool {
- _, ok := tokenPriority[token.TValue]
- return (token.TValue == "-" && token.TType == efp.TokenTypeOperatorPrefix) || (ok && token.TType == efp.TokenTypeOperatorInfix)
- }
- // isOperand determine if the token is parse operand.
- func isOperand(token efp.Token) bool {
- return token.TType == efp.TokenTypeOperand && (token.TSubType == efp.TokenSubTypeNumber || token.TSubType == efp.TokenSubTypeText || token.TSubType == efp.TokenSubTypeLogical)
- }
- // tokenToFormulaArg create a formula argument by given token.
- func tokenToFormulaArg(token efp.Token) formulaArg {
- switch token.TSubType {
- case efp.TokenSubTypeLogical:
- return newBoolFormulaArg(strings.EqualFold(token.TValue, "TRUE"))
- case efp.TokenSubTypeNumber:
- num, _ := strconv.ParseFloat(token.TValue, 64)
- return newNumberFormulaArg(num)
- default:
- return newStringFormulaArg(token.TValue)
- }
- }
- // formulaArgToToken create a token by given formula argument.
- func formulaArgToToken(arg formulaArg) efp.Token {
- switch arg.Type {
- case ArgNumber:
- if arg.Boolean {
- return efp.Token{TValue: arg.Value(), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeLogical}
- }
- return efp.Token{TValue: arg.Value(), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber}
- default:
- return efp.Token{TValue: arg.Value(), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeText}
- }
- }
- // parseToken parse basic arithmetic operator priority and evaluate based on
- // operators and operands.
- func (f *File) parseToken(ctx *calcContext, sheet string, token efp.Token, opdStack, optStack *Stack) error {
- // parse reference: must reference at here
- if token.TSubType == efp.TokenSubTypeRange {
- refTo := f.getDefinedNameRefTo(token.TValue, sheet)
- if refTo != "" {
- token.TValue = refTo
- }
- result, err := f.parseReference(ctx, sheet, token.TValue)
- if err != nil {
- return errors.New(formulaErrorNAME)
- }
- token = formulaArgToToken(result)
- }
- if isOperatorPrefixToken(token) {
- if err := f.parseOperatorPrefixToken(optStack, opdStack, token); err != nil {
- return err
- }
- }
- if isBeginParenthesesToken(token) { // (
- optStack.Push(token)
- }
- if isEndParenthesesToken(token) { // )
- for !isBeginParenthesesToken(optStack.Peek().(efp.Token)) { // != (
- topOpt := optStack.Peek().(efp.Token)
- if err := calculate(opdStack, topOpt); err != nil {
- return err
- }
- optStack.Pop()
- }
- optStack.Pop()
- }
- if token.TType == efp.TokenTypeOperatorPostfix && !opdStack.Empty() {
- topOpd := opdStack.Pop().(formulaArg)
- opdStack.Push(newNumberFormulaArg(topOpd.Number / 100))
- }
- // opd
- if isOperand(token) {
- opdStack.Push(tokenToFormulaArg(token))
- }
- return nil
- }
- // parseReference parse reference and extract values by given reference
- // characters and default sheet name.
- func (f *File) parseReference(ctx *calcContext, sheet, reference string) (arg formulaArg, err error) {
- reference = strings.ReplaceAll(reference, "$", "")
- refs, cellRanges, cellRefs := list.New(), list.New(), list.New()
- for _, ref := range strings.Split(reference, ":") {
- tokens := strings.Split(ref, "!")
- cr := cellRef{}
- if len(tokens) == 2 { // have a worksheet name
- cr.Sheet = tokens[0]
- // cast to cell reference
- if cr.Col, cr.Row, err = CellNameToCoordinates(tokens[1]); err != nil {
- // cast to column
- if cr.Col, err = ColumnNameToNumber(tokens[1]); err != nil {
- // cast to row
- if cr.Row, err = strconv.Atoi(tokens[1]); err != nil {
- err = newInvalidColumnNameError(tokens[1])
- return
- }
- cr.Col = MaxColumns
- }
- }
- if refs.Len() > 0 {
- e := refs.Back()
- cellRefs.PushBack(e.Value.(cellRef))
- refs.Remove(e)
- }
- refs.PushBack(cr)
- continue
- }
- // cast to cell reference
- if cr.Col, cr.Row, err = CellNameToCoordinates(tokens[0]); err != nil {
- // cast to column
- if cr.Col, err = ColumnNameToNumber(tokens[0]); err != nil {
- // cast to row
- if cr.Row, err = strconv.Atoi(tokens[0]); err != nil {
- err = newInvalidColumnNameError(tokens[0])
- return
- }
- cr.Col = MaxColumns
- }
- cellRanges.PushBack(cellRange{
- From: cellRef{Sheet: sheet, Col: cr.Col, Row: 1},
- To: cellRef{Sheet: sheet, Col: cr.Col, Row: TotalRows},
- })
- cellRefs.Init()
- arg, err = f.rangeResolver(ctx, cellRefs, cellRanges)
- return
- }
- e := refs.Back()
- if e == nil {
- cr.Sheet = sheet
- refs.PushBack(cr)
- continue
- }
- cellRanges.PushBack(cellRange{
- From: e.Value.(cellRef),
- To: cr,
- })
- refs.Remove(e)
- }
- if refs.Len() > 0 {
- e := refs.Back()
- cellRefs.PushBack(e.Value.(cellRef))
- refs.Remove(e)
- }
- arg, err = f.rangeResolver(ctx, cellRefs, cellRanges)
- return
- }
- // prepareValueRange prepare value range.
- func prepareValueRange(cr cellRange, valueRange []int) {
- if cr.From.Row < valueRange[0] || valueRange[0] == 0 {
- valueRange[0] = cr.From.Row
- }
- if cr.From.Col < valueRange[2] || valueRange[2] == 0 {
- valueRange[2] = cr.From.Col
- }
- if cr.To.Row > valueRange[1] || valueRange[1] == 0 {
- valueRange[1] = cr.To.Row
- }
- if cr.To.Col > valueRange[3] || valueRange[3] == 0 {
- valueRange[3] = cr.To.Col
- }
- }
- // prepareValueRef prepare value reference.
- func prepareValueRef(cr cellRef, valueRange []int) {
- if cr.Row < valueRange[0] || valueRange[0] == 0 {
- valueRange[0] = cr.Row
- }
- if cr.Col < valueRange[2] || valueRange[2] == 0 {
- valueRange[2] = cr.Col
- }
- if cr.Row > valueRange[1] || valueRange[1] == 0 {
- valueRange[1] = cr.Row
- }
- if cr.Col > valueRange[3] || valueRange[3] == 0 {
- valueRange[3] = cr.Col
- }
- }
- // cellResolver calc cell value by given worksheet name, cell reference and context.
- func (f *File) cellResolver(ctx *calcContext, sheet, cell string) (formulaArg, error) {
- var (
- arg formulaArg
- value string
- err error
- )
- ref := fmt.Sprintf("%s!%s", sheet, cell)
- if formula, _ := f.GetCellFormula(sheet, cell); len(formula) != 0 {
- ctx.Lock()
- if ctx.entry != ref {
- if ctx.iterations[ref] <= f.options.MaxCalcIterations {
- ctx.iterations[ref]++
- ctx.Unlock()
- arg, _ = f.calcCellValue(ctx, sheet, cell)
- ctx.iterationsCache[ref] = arg
- return arg, nil
- }
- ctx.Unlock()
- return ctx.iterationsCache[ref], nil
- }
- ctx.Unlock()
- }
- if value, err = f.GetCellValue(sheet, cell, Options{RawCellValue: true}); err != nil {
- return arg, err
- }
- arg = newStringFormulaArg(value)
- cellType, _ := f.GetCellType(sheet, cell)
- switch cellType {
- case CellTypeBool:
- return arg.ToBool(), err
- case CellTypeNumber, CellTypeUnset:
- if arg.Value() == "" {
- return newEmptyFormulaArg(), err
- }
- return arg.ToNumber(), err
- case CellTypeInlineString, CellTypeSharedString:
- return arg, err
- default:
- return newEmptyFormulaArg(), err
- }
- }
- // rangeResolver extract value as string from given reference and range list.
- // This function will not ignore the empty cell. For example, A1:A2:A2:B3 will
- // be reference A1:B3.
- func (f *File) rangeResolver(ctx *calcContext, cellRefs, cellRanges *list.List) (arg formulaArg, err error) {
- arg.cellRefs, arg.cellRanges = cellRefs, cellRanges
- // value range order: from row, to row, from column, to column
- valueRange := []int{0, 0, 0, 0}
- var sheet string
- // prepare value range
- for temp := cellRanges.Front(); temp != nil; temp = temp.Next() {
- cr := temp.Value.(cellRange)
- if cr.From.Sheet != cr.To.Sheet {
- err = errors.New(formulaErrorVALUE)
- }
- rng := []int{cr.From.Col, cr.From.Row, cr.To.Col, cr.To.Row}
- _ = sortCoordinates(rng)
- cr.From.Col, cr.From.Row, cr.To.Col, cr.To.Row = rng[0], rng[1], rng[2], rng[3]
- prepareValueRange(cr, valueRange)
- if cr.From.Sheet != "" {
- sheet = cr.From.Sheet
- }
- }
- for temp := cellRefs.Front(); temp != nil; temp = temp.Next() {
- cr := temp.Value.(cellRef)
- if cr.Sheet != "" {
- sheet = cr.Sheet
- }
- prepareValueRef(cr, valueRange)
- }
- // extract value from ranges
- if cellRanges.Len() > 0 {
- arg.Type = ArgMatrix
- for row := valueRange[0]; row <= valueRange[1]; row++ {
- var matrixRow []formulaArg
- for col := valueRange[2]; col <= valueRange[3]; col++ {
- var cell string
- var value formulaArg
- if cell, err = CoordinatesToCellName(col, row); err != nil {
- return
- }
- if value, err = f.cellResolver(ctx, sheet, cell); err != nil {
- return
- }
- matrixRow = append(matrixRow, value)
- }
- arg.Matrix = append(arg.Matrix, matrixRow)
- }
- return
- }
- // extract value from references
- for temp := cellRefs.Front(); temp != nil; temp = temp.Next() {
- cr := temp.Value.(cellRef)
- var cell string
- if cell, err = CoordinatesToCellName(cr.Col, cr.Row); err != nil {
- return
- }
- if arg, err = f.cellResolver(ctx, cr.Sheet, cell); err != nil {
- return
- }
- arg.cellRefs, arg.cellRanges = cellRefs, cellRanges
- }
- return
- }
- // callFuncByName calls the no error or only error return function with
- // reflect by given receiver, name and parameters.
- func callFuncByName(receiver interface{}, name string, params []reflect.Value) (arg formulaArg) {
- function := reflect.ValueOf(receiver).MethodByName(name)
- if function.IsValid() {
- rt := function.Call(params)
- if len(rt) == 0 {
- return
- }
- arg = rt[0].Interface().(formulaArg)
- return
- }
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("not support %s function", name))
- }
- // formulaCriteriaParser parse formula criteria.
- func formulaCriteriaParser(exp string) (fc *formulaCriteria) {
- fc = &formulaCriteria{}
- if exp == "" {
- return
- }
- if match := regexp.MustCompile(`^(\d+)$`).FindStringSubmatch(exp); len(match) > 1 {
- fc.Type, fc.Condition = criteriaEq, match[1]
- return
- }
- if match := regexp.MustCompile(`^=(.*)$`).FindStringSubmatch(exp); len(match) > 1 {
- fc.Type, fc.Condition = criteriaEq, match[1]
- return
- }
- if match := regexp.MustCompile(`^<>(.*)$`).FindStringSubmatch(exp); len(match) > 1 {
- fc.Type, fc.Condition = criteriaNe, match[1]
- return
- }
- if match := regexp.MustCompile(`^<=(.*)$`).FindStringSubmatch(exp); len(match) > 1 {
- fc.Type, fc.Condition = criteriaLe, match[1]
- return
- }
- if match := regexp.MustCompile(`^>=(.*)$`).FindStringSubmatch(exp); len(match) > 1 {
- fc.Type, fc.Condition = criteriaGe, match[1]
- return
- }
- if match := regexp.MustCompile(`^<(.*)$`).FindStringSubmatch(exp); len(match) > 1 {
- fc.Type, fc.Condition = criteriaL, match[1]
- return
- }
- if match := regexp.MustCompile(`^>(.*)$`).FindStringSubmatch(exp); len(match) > 1 {
- fc.Type, fc.Condition = criteriaG, match[1]
- return
- }
- if strings.Contains(exp, "?") {
- exp = strings.ReplaceAll(exp, "?", ".")
- }
- if strings.Contains(exp, "*") {
- exp = strings.ReplaceAll(exp, "*", ".*")
- }
- fc.Type, fc.Condition = criteriaRegexp, exp
- return
- }
- // formulaCriteriaEval evaluate formula criteria expression.
- func formulaCriteriaEval(val string, criteria *formulaCriteria) (result bool, err error) {
- var value, expected float64
- var e error
- prepareValue := func(val, cond string) (value float64, expected float64, err error) {
- percentile := 1.0
- if strings.HasSuffix(cond, "%") {
- cond = strings.TrimSuffix(cond, "%")
- percentile /= 100
- }
- if value, err = strconv.ParseFloat(val, 64); err != nil {
- return
- }
- if expected, err = strconv.ParseFloat(cond, 64); err != nil {
- return
- }
- expected *= percentile
- return
- }
- switch criteria.Type {
- case criteriaEq:
- return val == criteria.Condition, err
- case criteriaLe:
- value, expected, e = prepareValue(val, criteria.Condition)
- return value <= expected && e == nil, err
- case criteriaGe:
- value, expected, e = prepareValue(val, criteria.Condition)
- return value >= expected && e == nil, err
- case criteriaNe:
- return val != criteria.Condition, err
- case criteriaL:
- value, expected, e = prepareValue(val, criteria.Condition)
- return value < expected && e == nil, err
- case criteriaG:
- value, expected, e = prepareValue(val, criteria.Condition)
- return value > expected && e == nil, err
- case criteriaRegexp:
- return regexp.MatchString(criteria.Condition, val)
- }
- return
- }
- // Engineering Functions
- // BESSELI function the modified Bessel function, which is equivalent to the
- // Bessel function evaluated for purely imaginary arguments. The syntax of
- // the Besseli function is:
- //
- // BESSELI(x,n)
- func (fn *formulaFuncs) BESSELI(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "BESSELI requires 2 numeric arguments")
- }
- return fn.bassel(argsList, true)
- }
- // BESSELJ function returns the Bessel function, Jn(x), for a specified order
- // and value of x. The syntax of the function is:
- //
- // BESSELJ(x,n)
- func (fn *formulaFuncs) BESSELJ(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "BESSELJ requires 2 numeric arguments")
- }
- return fn.bassel(argsList, false)
- }
- // bassel is an implementation of the formula functions BESSELI and BESSELJ.
- func (fn *formulaFuncs) bassel(argsList *list.List, modfied bool) formulaArg {
- x, n := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Back().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- if n.Type != ArgNumber {
- return n
- }
- max, x1 := 100, x.Number*0.5
- x2 := x1 * x1
- x1 = math.Pow(x1, n.Number)
- n1, n2, n3, n4, add := fact(n.Number), 1.0, 0.0, n.Number, false
- result := x1 / n1
- t := result * 0.9
- for result != t && max != 0 {
- x1 *= x2
- n3++
- n1 *= n3
- n4++
- n2 *= n4
- t = result
- r := x1 / n1 / n2
- if modfied || add {
- result += r
- } else {
- result -= r
- }
- max--
- add = !add
- }
- return newNumberFormulaArg(result)
- }
- // BESSELK function calculates the modified Bessel functions, Kn(x), which are
- // also known as the hyperbolic Bessel Functions. These are the equivalent of
- // the Bessel functions, evaluated for purely imaginary arguments. The syntax
- // of the function is:
- //
- // BESSELK(x,n)
- func (fn *formulaFuncs) BESSELK(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "BESSELK requires 2 numeric arguments")
- }
- x, n := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Back().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- if n.Type != ArgNumber {
- return n
- }
- if x.Number <= 0 || n.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- var result float64
- switch math.Floor(n.Number) {
- case 0:
- result = fn.besselK0(x)
- case 1:
- result = fn.besselK1(x)
- default:
- result = fn.besselK2(x, n)
- }
- return newNumberFormulaArg(result)
- }
- // besselK0 is an implementation of the formula function BESSELK.
- func (fn *formulaFuncs) besselK0(x formulaArg) float64 {
- var y float64
- if x.Number <= 2 {
- n2 := x.Number * 0.5
- y = n2 * n2
- args := list.New()
- args.PushBack(x)
- args.PushBack(newNumberFormulaArg(0))
- return -math.Log(n2)*fn.BESSELI(args).Number +
- (-0.57721566 + y*(0.42278420+y*(0.23069756+y*(0.3488590e-1+y*(0.262698e-2+y*
- (0.10750e-3+y*0.74e-5))))))
- }
- y = 2 / x.Number
- return math.Exp(-x.Number) / math.Sqrt(x.Number) *
- (1.25331414 + y*(-0.7832358e-1+y*(0.2189568e-1+y*(-0.1062446e-1+y*
- (0.587872e-2+y*(-0.251540e-2+y*0.53208e-3))))))
- }
- // besselK1 is an implementation of the formula function BESSELK.
- func (fn *formulaFuncs) besselK1(x formulaArg) float64 {
- var n2, y float64
- if x.Number <= 2 {
- n2 = x.Number * 0.5
- y = n2 * n2
- args := list.New()
- args.PushBack(x)
- args.PushBack(newNumberFormulaArg(1))
- return math.Log(n2)*fn.BESSELI(args).Number +
- (1+y*(0.15443144+y*(-0.67278579+y*(-0.18156897+y*(-0.1919402e-1+y*(-0.110404e-2+y*(-0.4686e-4)))))))/x.Number
- }
- y = 2 / x.Number
- return math.Exp(-x.Number) / math.Sqrt(x.Number) *
- (1.25331414 + y*(0.23498619+y*(-0.3655620e-1+y*(0.1504268e-1+y*(-0.780353e-2+y*
- (0.325614e-2+y*(-0.68245e-3)))))))
- }
- // besselK2 is an implementation of the formula function BESSELK.
- func (fn *formulaFuncs) besselK2(x, n formulaArg) float64 {
- tox, bkm, bk, bkp := 2/x.Number, fn.besselK0(x), fn.besselK1(x), 0.0
- for i := 1.0; i < n.Number; i++ {
- bkp = bkm + i*tox*bk
- bkm = bk
- bk = bkp
- }
- return bk
- }
- // BESSELY function returns the Bessel function, Yn(x), (also known as the
- // Weber function or the Neumann function), for a specified order and value
- // of x. The syntax of the function is:
- //
- // BESSELY(x,n)
- func (fn *formulaFuncs) BESSELY(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "BESSELY requires 2 numeric arguments")
- }
- x, n := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Back().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- if n.Type != ArgNumber {
- return n
- }
- if x.Number <= 0 || n.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- var result float64
- switch math.Floor(n.Number) {
- case 0:
- result = fn.besselY0(x)
- case 1:
- result = fn.besselY1(x)
- default:
- result = fn.besselY2(x, n)
- }
- return newNumberFormulaArg(result)
- }
- // besselY0 is an implementation of the formula function BESSELY.
- func (fn *formulaFuncs) besselY0(x formulaArg) float64 {
- var y float64
- if x.Number < 8 {
- y = x.Number * x.Number
- f1 := -2957821389.0 + y*(7062834065.0+y*(-512359803.6+y*(10879881.29+y*
- (-86327.92757+y*228.4622733))))
- f2 := 40076544269.0 + y*(745249964.8+y*(7189466.438+y*
- (47447.26470+y*(226.1030244+y))))
- args := list.New()
- args.PushBack(x)
- args.PushBack(newNumberFormulaArg(0))
- return f1/f2 + 0.636619772*fn.BESSELJ(args).Number*math.Log(x.Number)
- }
- z := 8.0 / x.Number
- y = z * z
- xx := x.Number - 0.785398164
- f1 := 1 + y*(-0.1098628627e-2+y*(0.2734510407e-4+y*(-0.2073370639e-5+y*0.2093887211e-6)))
- f2 := -0.1562499995e-1 + y*(0.1430488765e-3+y*(-0.6911147651e-5+y*(0.7621095161e-6+y*
- (-0.934945152e-7))))
- return math.Sqrt(0.636619772/x.Number) * (math.Sin(xx)*f1 + z*math.Cos(xx)*f2)
- }
- // besselY1 is an implementation of the formula function BESSELY.
- func (fn *formulaFuncs) besselY1(x formulaArg) float64 {
- if x.Number < 8 {
- y := x.Number * x.Number
- f1 := x.Number * (-0.4900604943e13 + y*(0.1275274390e13+y*(-0.5153438139e11+y*
- (0.7349264551e9+y*(-0.4237922726e7+y*0.8511937935e4)))))
- f2 := 0.2499580570e14 + y*(0.4244419664e12+y*(0.3733650367e10+y*(0.2245904002e8+y*
- (0.1020426050e6+y*(0.3549632885e3+y)))))
- args := list.New()
- args.PushBack(x)
- args.PushBack(newNumberFormulaArg(1))
- return f1/f2 + 0.636619772*(fn.BESSELJ(args).Number*math.Log(x.Number)-1/x.Number)
- }
- return math.Sqrt(0.636619772/x.Number) * math.Sin(x.Number-2.356194491)
- }
- // besselY2 is an implementation of the formula function BESSELY.
- func (fn *formulaFuncs) besselY2(x, n formulaArg) float64 {
- tox, bym, by, byp := 2/x.Number, fn.besselY0(x), fn.besselY1(x), 0.0
- for i := 1.0; i < n.Number; i++ {
- byp = i*tox*by - bym
- bym = by
- by = byp
- }
- return by
- }
- // BIN2DEC function converts a Binary (a base-2 number) into a decimal number.
- // The syntax of the function is:
- //
- // BIN2DEC(number)
- func (fn *formulaFuncs) BIN2DEC(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "BIN2DEC requires 1 numeric argument")
- }
- token := argsList.Front().Value.(formulaArg)
- number := token.ToNumber()
- if number.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, number.Error)
- }
- return fn.bin2dec(token.Value())
- }
- // BIN2HEX function converts a Binary (Base 2) number into a Hexadecimal
- // (Base 16) number. The syntax of the function is:
- //
- // BIN2HEX(number,[places])
- func (fn *formulaFuncs) BIN2HEX(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "BIN2HEX requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "BIN2HEX allows at most 2 arguments")
- }
- token := argsList.Front().Value.(formulaArg)
- number := token.ToNumber()
- if number.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, number.Error)
- }
- decimal, newList := fn.bin2dec(token.Value()), list.New()
- if decimal.Type != ArgNumber {
- return decimal
- }
- newList.PushBack(decimal)
- if argsList.Len() == 2 {
- newList.PushBack(argsList.Back().Value.(formulaArg))
- }
- return fn.dec2x("BIN2HEX", newList)
- }
- // BIN2OCT function converts a Binary (Base 2) number into an Octal (Base 8)
- // number. The syntax of the function is:
- //
- // BIN2OCT(number,[places])
- func (fn *formulaFuncs) BIN2OCT(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "BIN2OCT requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "BIN2OCT allows at most 2 arguments")
- }
- token := argsList.Front().Value.(formulaArg)
- number := token.ToNumber()
- if number.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, number.Error)
- }
- decimal, newList := fn.bin2dec(token.Value()), list.New()
- if decimal.Type != ArgNumber {
- return decimal
- }
- newList.PushBack(decimal)
- if argsList.Len() == 2 {
- newList.PushBack(argsList.Back().Value.(formulaArg))
- }
- return fn.dec2x("BIN2OCT", newList)
- }
- // bin2dec is an implementation of the formula function BIN2DEC.
- func (fn *formulaFuncs) bin2dec(number string) formulaArg {
- decimal, length := 0.0, len(number)
- for i := length; i > 0; i-- {
- s := string(number[length-i])
- if i == 10 && s == "1" {
- decimal += math.Pow(-2.0, float64(i-1))
- continue
- }
- if s == "1" {
- decimal += math.Pow(2.0, float64(i-1))
- continue
- }
- if s != "0" {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- return newNumberFormulaArg(decimal)
- }
- // BITAND function returns the bitwise 'AND' for two supplied integers. The
- // syntax of the function is:
- //
- // BITAND(number1,number2)
- func (fn *formulaFuncs) BITAND(argsList *list.List) formulaArg {
- return fn.bitwise("BITAND", argsList)
- }
- // BITLSHIFT function returns a supplied integer, shifted left by a specified
- // number of bits. The syntax of the function is:
- //
- // BITLSHIFT(number1,shift_amount)
- func (fn *formulaFuncs) BITLSHIFT(argsList *list.List) formulaArg {
- return fn.bitwise("BITLSHIFT", argsList)
- }
- // BITOR function returns the bitwise 'OR' for two supplied integers. The
- // syntax of the function is:
- //
- // BITOR(number1,number2)
- func (fn *formulaFuncs) BITOR(argsList *list.List) formulaArg {
- return fn.bitwise("BITOR", argsList)
- }
- // BITRSHIFT function returns a supplied integer, shifted right by a specified
- // number of bits. The syntax of the function is:
- //
- // BITRSHIFT(number1,shift_amount)
- func (fn *formulaFuncs) BITRSHIFT(argsList *list.List) formulaArg {
- return fn.bitwise("BITRSHIFT", argsList)
- }
- // BITXOR function returns the bitwise 'XOR' (exclusive 'OR') for two supplied
- // integers. The syntax of the function is:
- //
- // BITXOR(number1,number2)
- func (fn *formulaFuncs) BITXOR(argsList *list.List) formulaArg {
- return fn.bitwise("BITXOR", argsList)
- }
- // bitwise is an implementation of the formula functions BITAND, BITLSHIFT,
- // BITOR, BITRSHIFT and BITXOR.
- func (fn *formulaFuncs) bitwise(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 numeric arguments", name))
- }
- num1, num2 := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Back().Value.(formulaArg).ToNumber()
- if num1.Type != ArgNumber || num2.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- max := math.Pow(2, 48) - 1
- if num1.Number < 0 || num1.Number > max || num2.Number < 0 || num2.Number > max {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- bitwiseFuncMap := map[string]func(a, b int) int{
- "BITAND": func(a, b int) int { return a & b },
- "BITLSHIFT": func(a, b int) int { return a << uint(b) },
- "BITOR": func(a, b int) int { return a | b },
- "BITRSHIFT": func(a, b int) int { return a >> uint(b) },
- "BITXOR": func(a, b int) int { return a ^ b },
- }
- bitwiseFunc := bitwiseFuncMap[name]
- return newNumberFormulaArg(float64(bitwiseFunc(int(num1.Number), int(num2.Number))))
- }
- // COMPLEX function takes two arguments, representing the real and the
- // imaginary coefficients of a complex number, and from these, creates a
- // complex number. The syntax of the function is:
- //
- // COMPLEX(real_num,i_num,[suffix])
- func (fn *formulaFuncs) COMPLEX(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "COMPLEX requires at least 2 arguments")
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "COMPLEX allows at most 3 arguments")
- }
- realNum, i, suffix := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Front().Next().Value.(formulaArg).ToNumber(), "i"
- if realNum.Type != ArgNumber {
- return realNum
- }
- if i.Type != ArgNumber {
- return i
- }
- if argsList.Len() == 3 {
- if suffix = strings.ToLower(argsList.Back().Value.(formulaArg).Value()); suffix != "i" && suffix != "j" {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- return newStringFormulaArg(cmplx2str(complex(realNum.Number, i.Number), suffix))
- }
- // cmplx2str replace complex number string characters.
- func cmplx2str(num complex128, suffix string) string {
- realPart, imagPart := fmt.Sprint(real(num)), fmt.Sprint(imag(num))
- isNum, i, decimal := isNumeric(realPart)
- if isNum && i > 15 {
- realPart = strconv.FormatFloat(decimal, 'G', 15, 64)
- }
- isNum, i, decimal = isNumeric(imagPart)
- if isNum && i > 15 {
- imagPart = strconv.FormatFloat(decimal, 'G', 15, 64)
- }
- c := realPart
- if imag(num) > 0 {
- c += "+"
- }
- if imag(num) != 0 {
- c += imagPart + "i"
- }
- c = strings.TrimPrefix(c, "(")
- c = strings.TrimPrefix(c, "+0+")
- c = strings.TrimPrefix(c, "-0+")
- c = strings.TrimSuffix(c, ")")
- c = strings.TrimPrefix(c, "0+")
- if strings.HasPrefix(c, "0-") {
- c = "-" + strings.TrimPrefix(c, "0-")
- }
- c = strings.TrimPrefix(c, "0+")
- c = strings.TrimSuffix(c, "+0i")
- c = strings.TrimSuffix(c, "-0i")
- c = strings.NewReplacer("+1i", "+i", "-1i", "-i").Replace(c)
- c = strings.ReplaceAll(c, "i", suffix)
- return c
- }
- // str2cmplx convert complex number string characters.
- func str2cmplx(c string) string {
- c = strings.ReplaceAll(c, "j", "i")
- if c == "i" {
- c = "1i"
- }
- c = strings.NewReplacer("+i", "+1i", "-i", "-1i").Replace(c)
- return c
- }
- // conversionUnit defined unit info for conversion.
- type conversionUnit struct {
- group uint8
- allowPrefix bool
- }
- // conversionUnits maps info list for unit conversion, that can be used in
- // formula function CONVERT.
- var conversionUnits = map[string]conversionUnit{
- // weight and mass
- "g": {group: categoryWeightAndMass, allowPrefix: true},
- "sg": {group: categoryWeightAndMass, allowPrefix: false},
- "lbm": {group: categoryWeightAndMass, allowPrefix: false},
- "u": {group: categoryWeightAndMass, allowPrefix: true},
- "ozm": {group: categoryWeightAndMass, allowPrefix: false},
- "grain": {group: categoryWeightAndMass, allowPrefix: false},
- "cwt": {group: categoryWeightAndMass, allowPrefix: false},
- "shweight": {group: categoryWeightAndMass, allowPrefix: false},
- "uk_cwt": {group: categoryWeightAndMass, allowPrefix: false},
- "lcwt": {group: categoryWeightAndMass, allowPrefix: false},
- "hweight": {group: categoryWeightAndMass, allowPrefix: false},
- "stone": {group: categoryWeightAndMass, allowPrefix: false},
- "ton": {group: categoryWeightAndMass, allowPrefix: false},
- "uk_ton": {group: categoryWeightAndMass, allowPrefix: false},
- "LTON": {group: categoryWeightAndMass, allowPrefix: false},
- "brton": {group: categoryWeightAndMass, allowPrefix: false},
- // distance
- "m": {group: categoryDistance, allowPrefix: true},
- "mi": {group: categoryDistance, allowPrefix: false},
- "Nmi": {group: categoryDistance, allowPrefix: false},
- "in": {group: categoryDistance, allowPrefix: false},
- "ft": {group: categoryDistance, allowPrefix: false},
- "yd": {group: categoryDistance, allowPrefix: false},
- "ang": {group: categoryDistance, allowPrefix: true},
- "ell": {group: categoryDistance, allowPrefix: false},
- "ly": {group: categoryDistance, allowPrefix: false},
- "parsec": {group: categoryDistance, allowPrefix: false},
- "pc": {group: categoryDistance, allowPrefix: false},
- "Pica": {group: categoryDistance, allowPrefix: false},
- "Picapt": {group: categoryDistance, allowPrefix: false},
- "pica": {group: categoryDistance, allowPrefix: false},
- "survey_mi": {group: categoryDistance, allowPrefix: false},
- // time
- "yr": {group: categoryTime, allowPrefix: false},
- "day": {group: categoryTime, allowPrefix: false},
- "d": {group: categoryTime, allowPrefix: false},
- "hr": {group: categoryTime, allowPrefix: false},
- "mn": {group: categoryTime, allowPrefix: false},
- "min": {group: categoryTime, allowPrefix: false},
- "sec": {group: categoryTime, allowPrefix: true},
- "s": {group: categoryTime, allowPrefix: true},
- // pressure
- "Pa": {group: categoryPressure, allowPrefix: true},
- "p": {group: categoryPressure, allowPrefix: true},
- "atm": {group: categoryPressure, allowPrefix: true},
- "at": {group: categoryPressure, allowPrefix: true},
- "mmHg": {group: categoryPressure, allowPrefix: true},
- "psi": {group: categoryPressure, allowPrefix: true},
- "Torr": {group: categoryPressure, allowPrefix: true},
- // force
- "N": {group: categoryForce, allowPrefix: true},
- "dyn": {group: categoryForce, allowPrefix: true},
- "dy": {group: categoryForce, allowPrefix: true},
- "lbf": {group: categoryForce, allowPrefix: false},
- "pond": {group: categoryForce, allowPrefix: true},
- // energy
- "J": {group: categoryEnergy, allowPrefix: true},
- "e": {group: categoryEnergy, allowPrefix: true},
- "c": {group: categoryEnergy, allowPrefix: true},
- "cal": {group: categoryEnergy, allowPrefix: true},
- "eV": {group: categoryEnergy, allowPrefix: true},
- "ev": {group: categoryEnergy, allowPrefix: true},
- "HPh": {group: categoryEnergy, allowPrefix: false},
- "hh": {group: categoryEnergy, allowPrefix: false},
- "Wh": {group: categoryEnergy, allowPrefix: true},
- "wh": {group: categoryEnergy, allowPrefix: true},
- "flb": {group: categoryEnergy, allowPrefix: false},
- "BTU": {group: categoryEnergy, allowPrefix: false},
- "btu": {group: categoryEnergy, allowPrefix: false},
- // power
- "HP": {group: categoryPower, allowPrefix: false},
- "h": {group: categoryPower, allowPrefix: false},
- "W": {group: categoryPower, allowPrefix: true},
- "w": {group: categoryPower, allowPrefix: true},
- "PS": {group: categoryPower, allowPrefix: false},
- "T": {group: categoryMagnetism, allowPrefix: true},
- "ga": {group: categoryMagnetism, allowPrefix: true},
- // temperature
- "C": {group: categoryTemperature, allowPrefix: false},
- "cel": {group: categoryTemperature, allowPrefix: false},
- "F": {group: categoryTemperature, allowPrefix: false},
- "fah": {group: categoryTemperature, allowPrefix: false},
- "K": {group: categoryTemperature, allowPrefix: false},
- "kel": {group: categoryTemperature, allowPrefix: false},
- "Rank": {group: categoryTemperature, allowPrefix: false},
- "Reau": {group: categoryTemperature, allowPrefix: false},
- // volume
- "l": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
- "L": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
- "lt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
- "tsp": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "tspm": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "tbs": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "oz": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "cup": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "pt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "us_pt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "uk_pt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "qt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "uk_qt": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "gal": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "uk_gal": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "ang3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
- "ang^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
- "barrel": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "bushel": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "in3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "in^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "ft3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "ft^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "ly3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "ly^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "m3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
- "m^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: true},
- "mi3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "mi^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "yd3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "yd^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "Nmi3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "Nmi^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "Pica3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "Pica^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "Picapt3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "Picapt^3": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "GRT": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "regton": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- "MTON": {group: categoryVolumeAndLiquidMeasure, allowPrefix: false},
- // area
- "ha": {group: categoryArea, allowPrefix: true},
- "uk_acre": {group: categoryArea, allowPrefix: false},
- "us_acre": {group: categoryArea, allowPrefix: false},
- "ang2": {group: categoryArea, allowPrefix: true},
- "ang^2": {group: categoryArea, allowPrefix: true},
- "ar": {group: categoryArea, allowPrefix: true},
- "ft2": {group: categoryArea, allowPrefix: false},
- "ft^2": {group: categoryArea, allowPrefix: false},
- "in2": {group: categoryArea, allowPrefix: false},
- "in^2": {group: categoryArea, allowPrefix: false},
- "ly2": {group: categoryArea, allowPrefix: false},
- "ly^2": {group: categoryArea, allowPrefix: false},
- "m2": {group: categoryArea, allowPrefix: true},
- "m^2": {group: categoryArea, allowPrefix: true},
- "Morgen": {group: categoryArea, allowPrefix: false},
- "mi2": {group: categoryArea, allowPrefix: false},
- "mi^2": {group: categoryArea, allowPrefix: false},
- "Nmi2": {group: categoryArea, allowPrefix: false},
- "Nmi^2": {group: categoryArea, allowPrefix: false},
- "Pica2": {group: categoryArea, allowPrefix: false},
- "Pica^2": {group: categoryArea, allowPrefix: false},
- "Picapt2": {group: categoryArea, allowPrefix: false},
- "Picapt^2": {group: categoryArea, allowPrefix: false},
- "yd2": {group: categoryArea, allowPrefix: false},
- "yd^2": {group: categoryArea, allowPrefix: false},
- // information
- "byte": {group: categoryInformation, allowPrefix: true},
- "bit": {group: categoryInformation, allowPrefix: true},
- // speed
- "m/s": {group: categorySpeed, allowPrefix: true},
- "m/sec": {group: categorySpeed, allowPrefix: true},
- "m/h": {group: categorySpeed, allowPrefix: true},
- "m/hr": {group: categorySpeed, allowPrefix: true},
- "mph": {group: categorySpeed, allowPrefix: false},
- "admkn": {group: categorySpeed, allowPrefix: false},
- "kn": {group: categorySpeed, allowPrefix: false},
- }
- // unitConversions maps details of the Units of measure conversion factors,
- // organised by group.
- var unitConversions = map[byte]map[string]float64{
- // conversion uses gram (g) as an intermediate unit
- categoryWeightAndMass: {
- "g": 1,
- "sg": 6.85217658567918e-05,
- "lbm": 2.20462262184878e-03,
- "u": 6.02214179421676e+23,
- "ozm": 3.52739619495804e-02,
- "grain": 1.54323583529414e+01,
- "cwt": 2.20462262184878e-05,
- "shweight": 2.20462262184878e-05,
- "uk_cwt": 1.96841305522212e-05,
- "lcwt": 1.96841305522212e-05,
- "hweight": 1.96841305522212e-05,
- "stone": 1.57473044417770e-04,
- "ton": 1.10231131092439e-06,
- "uk_ton": 9.84206527611061e-07,
- "LTON": 9.84206527611061e-07,
- "brton": 9.84206527611061e-07,
- },
- // conversion uses meter (m) as an intermediate unit
- categoryDistance: {
- "m": 1,
- "mi": 6.21371192237334e-04,
- "Nmi": 5.39956803455724e-04,
- "in": 3.93700787401575e+01,
- "ft": 3.28083989501312e+00,
- "yd": 1.09361329833771e+00,
- "ang": 1.0e+10,
- "ell": 8.74890638670166e-01,
- "ly": 1.05700083402462e-16,
- "parsec": 3.24077928966473e-17,
- "pc": 3.24077928966473e-17,
- "Pica": 2.83464566929134e+03,
- "Picapt": 2.83464566929134e+03,
- "pica": 2.36220472440945e+02,
- "survey_mi": 6.21369949494950e-04,
- },
- // conversion uses second (s) as an intermediate unit
- categoryTime: {
- "yr": 3.16880878140289e-08,
- "day": 1.15740740740741e-05,
- "d": 1.15740740740741e-05,
- "hr": 2.77777777777778e-04,
- "mn": 1.66666666666667e-02,
- "min": 1.66666666666667e-02,
- "sec": 1,
- "s": 1,
- },
- // conversion uses Pascal (Pa) as an intermediate unit
- categoryPressure: {
- "Pa": 1,
- "p": 1,
- "atm": 9.86923266716013e-06,
- "at": 9.86923266716013e-06,
- "mmHg": 7.50063755419211e-03,
- "psi": 1.45037737730209e-04,
- "Torr": 7.50061682704170e-03,
- },
- // conversion uses Newton (N) as an intermediate unit
- categoryForce: {
- "N": 1,
- "dyn": 1.0e+5,
- "dy": 1.0e+5,
- "lbf": 2.24808923655339e-01,
- "pond": 1.01971621297793e+02,
- },
- // conversion uses Joule (J) as an intermediate unit
- categoryEnergy: {
- "J": 1,
- "e": 9.99999519343231e+06,
- "c": 2.39006249473467e-01,
- "cal": 2.38846190642017e-01,
- "eV": 6.24145700000000e+18,
- "ev": 6.24145700000000e+18,
- "HPh": 3.72506430801000e-07,
- "hh": 3.72506430801000e-07,
- "Wh": 2.77777916238711e-04,
- "wh": 2.77777916238711e-04,
- "flb": 2.37304222192651e+01,
- "BTU": 9.47815067349015e-04,
- "btu": 9.47815067349015e-04,
- },
- // conversion uses Horsepower (HP) as an intermediate unit
- categoryPower: {
- "HP": 1,
- "h": 1,
- "W": 7.45699871582270e+02,
- "w": 7.45699871582270e+02,
- "PS": 1.01386966542400e+00,
- },
- // conversion uses Tesla (T) as an intermediate unit
- categoryMagnetism: {
- "T": 1,
- "ga": 10000,
- },
- // conversion uses litre (l) as an intermediate unit
- categoryVolumeAndLiquidMeasure: {
- "l": 1,
- "L": 1,
- "lt": 1,
- "tsp": 2.02884136211058e+02,
- "tspm": 2.0e+02,
- "tbs": 6.76280454036860e+01,
- "oz": 3.38140227018430e+01,
- "cup": 4.22675283773038e+00,
- "pt": 2.11337641886519e+00,
- "us_pt": 2.11337641886519e+00,
- "uk_pt": 1.75975398639270e+00,
- "qt": 1.05668820943259e+00,
- "uk_qt": 8.79876993196351e-01,
- "gal": 2.64172052358148e-01,
- "uk_gal": 2.19969248299088e-01,
- "ang3": 1.0e+27,
- "ang^3": 1.0e+27,
- "barrel": 6.28981077043211e-03,
- "bushel": 2.83775932584017e-02,
- "in3": 6.10237440947323e+01,
- "in^3": 6.10237440947323e+01,
- "ft3": 3.53146667214886e-02,
- "ft^3": 3.53146667214886e-02,
- "ly3": 1.18093498844171e-51,
- "ly^3": 1.18093498844171e-51,
- "m3": 1.0e-03,
- "m^3": 1.0e-03,
- "mi3": 2.39912758578928e-13,
- "mi^3": 2.39912758578928e-13,
- "yd3": 1.30795061931439e-03,
- "yd^3": 1.30795061931439e-03,
- "Nmi3": 1.57426214685811e-13,
- "Nmi^3": 1.57426214685811e-13,
- "Pica3": 2.27769904358706e+07,
- "Pica^3": 2.27769904358706e+07,
- "Picapt3": 2.27769904358706e+07,
- "Picapt^3": 2.27769904358706e+07,
- "GRT": 3.53146667214886e-04,
- "regton": 3.53146667214886e-04,
- "MTON": 8.82866668037215e-04,
- },
- // conversion uses hectare (ha) as an intermediate unit
- categoryArea: {
- "ha": 1,
- "uk_acre": 2.47105381467165e+00,
- "us_acre": 2.47104393046628e+00,
- "ang2": 1.0e+24,
- "ang^2": 1.0e+24,
- "ar": 1.0e+02,
- "ft2": 1.07639104167097e+05,
- "ft^2": 1.07639104167097e+05,
- "in2": 1.55000310000620e+07,
- "in^2": 1.55000310000620e+07,
- "ly2": 1.11725076312873e-28,
- "ly^2": 1.11725076312873e-28,
- "m2": 1.0e+04,
- "m^2": 1.0e+04,
- "Morgen": 4.0e+00,
- "mi2": 3.86102158542446e-03,
- "mi^2": 3.86102158542446e-03,
- "Nmi2": 2.91553349598123e-03,
- "Nmi^2": 2.91553349598123e-03,
- "Pica2": 8.03521607043214e+10,
- "Pica^2": 8.03521607043214e+10,
- "Picapt2": 8.03521607043214e+10,
- "Picapt^2": 8.03521607043214e+10,
- "yd2": 1.19599004630108e+04,
- "yd^2": 1.19599004630108e+04,
- },
- // conversion uses bit (bit) as an intermediate unit
- categoryInformation: {
- "bit": 1,
- "byte": 0.125,
- },
- // conversion uses Meters per Second (m/s) as an intermediate unit
- categorySpeed: {
- "m/s": 1,
- "m/sec": 1,
- "m/h": 3.60e+03,
- "m/hr": 3.60e+03,
- "mph": 2.23693629205440e+00,
- "admkn": 1.94260256941567e+00,
- "kn": 1.94384449244060e+00,
- },
- }
- // conversionMultipliers maps details of the Multiplier prefixes that can be
- // used with Units of Measure in CONVERT.
- var conversionMultipliers = map[string]float64{
- "Y": 1e24,
- "Z": 1e21,
- "E": 1e18,
- "P": 1e15,
- "T": 1e12,
- "G": 1e9,
- "M": 1e6,
- "k": 1e3,
- "h": 1e2,
- "e": 1e1,
- "da": 1e1,
- "d": 1e-1,
- "c": 1e-2,
- "m": 1e-3,
- "u": 1e-6,
- "n": 1e-9,
- "p": 1e-12,
- "f": 1e-15,
- "a": 1e-18,
- "z": 1e-21,
- "y": 1e-24,
- "Yi": math.Pow(2, 80),
- "Zi": math.Pow(2, 70),
- "Ei": math.Pow(2, 60),
- "Pi": math.Pow(2, 50),
- "Ti": math.Pow(2, 40),
- "Gi": math.Pow(2, 30),
- "Mi": math.Pow(2, 20),
- "ki": math.Pow(2, 10),
- }
- // getUnitDetails check and returns the unit of measure details.
- func getUnitDetails(uom string) (unit string, catgory byte, res float64, ok bool) {
- if len(uom) == 0 {
- ok = false
- return
- }
- if unit, ok := conversionUnits[uom]; ok {
- return uom, unit.group, 1, ok
- }
- // 1 character standard metric multiplier prefixes
- multiplierType := uom[:1]
- uom = uom[1:]
- conversionUnit, ok1 := conversionUnits[uom]
- multiplier, ok2 := conversionMultipliers[multiplierType]
- if ok1 && ok2 {
- if !conversionUnit.allowPrefix {
- ok = false
- return
- }
- unitCategory := conversionUnit.group
- return uom, unitCategory, multiplier, true
- }
- // 2 character standard and binary metric multiplier prefixes
- if len(uom) > 0 {
- multiplierType += uom[:1]
- uom = uom[1:]
- }
- conversionUnit, ok1 = conversionUnits[uom]
- multiplier, ok2 = conversionMultipliers[multiplierType]
- if ok1 && ok2 {
- if !conversionUnit.allowPrefix {
- ok = false
- return
- }
- unitCategory := conversionUnit.group
- return uom, unitCategory, multiplier, true
- }
- ok = false
- return
- }
- // resolveTemperatureSynonyms returns unit of measure according to a given
- // temperature synonyms.
- func resolveTemperatureSynonyms(uom string) string {
- switch uom {
- case "fah":
- return "F"
- case "cel":
- return "C"
- case "kel":
- return "K"
- }
- return uom
- }
- // convertTemperature returns converted temperature by a given unit of measure.
- func convertTemperature(fromUOM, toUOM string, value float64) float64 {
- fromUOM = resolveTemperatureSynonyms(fromUOM)
- toUOM = resolveTemperatureSynonyms(toUOM)
- if fromUOM == toUOM {
- return value
- }
- // convert to Kelvin
- switch fromUOM {
- case "F":
- value = (value-32)/1.8 + 273.15
- case "C":
- value += 273.15
- case "Rank":
- value /= 1.8
- case "Reau":
- value = value*1.25 + 273.15
- }
- // convert from Kelvin
- switch toUOM {
- case "F":
- value = (value-273.15)*1.8 + 32
- case "C":
- value -= 273.15
- case "Rank":
- value *= 1.8
- case "Reau":
- value = (value - 273.15) * 0.8
- }
- return value
- }
- // CONVERT function converts a number from one unit type (e.g. Yards) to
- // another unit type (e.g. Meters). The syntax of the function is:
- //
- // CONVERT(number,from_unit,to_unit)
- func (fn *formulaFuncs) CONVERT(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "CONVERT requires 3 arguments")
- }
- num := argsList.Front().Value.(formulaArg).ToNumber()
- if num.Type != ArgNumber {
- return num
- }
- fromUOM, fromCategory, fromMultiplier, ok1 := getUnitDetails(argsList.Front().Next().Value.(formulaArg).Value())
- toUOM, toCategory, toMultiplier, ok2 := getUnitDetails(argsList.Back().Value.(formulaArg).Value())
- if !ok1 || !ok2 || fromCategory != toCategory {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- val := num.Number * fromMultiplier
- if fromUOM == toUOM && fromMultiplier == toMultiplier {
- return newNumberFormulaArg(val / fromMultiplier)
- } else if fromUOM == toUOM {
- return newNumberFormulaArg(val / toMultiplier)
- } else if fromCategory == categoryTemperature {
- return newNumberFormulaArg(convertTemperature(fromUOM, toUOM, val))
- }
- fromConversion := unitConversions[fromCategory][fromUOM]
- toConversion := unitConversions[fromCategory][toUOM]
- baseValue := val * (1 / fromConversion)
- return newNumberFormulaArg((baseValue * toConversion) / toMultiplier)
- }
- // DEC2BIN function converts a decimal number into a Binary (Base 2) number.
- // The syntax of the function is:
- //
- // DEC2BIN(number,[places])
- func (fn *formulaFuncs) DEC2BIN(argsList *list.List) formulaArg {
- return fn.dec2x("DEC2BIN", argsList)
- }
- // DEC2HEX function converts a decimal number into a Hexadecimal (Base 16)
- // number. The syntax of the function is:
- //
- // DEC2HEX(number,[places])
- func (fn *formulaFuncs) DEC2HEX(argsList *list.List) formulaArg {
- return fn.dec2x("DEC2HEX", argsList)
- }
- // DEC2OCT function converts a decimal number into an Octal (Base 8) number.
- // The syntax of the function is:
- //
- // DEC2OCT(number,[places])
- func (fn *formulaFuncs) DEC2OCT(argsList *list.List) formulaArg {
- return fn.dec2x("DEC2OCT", argsList)
- }
- // dec2x is an implementation of the formula functions DEC2BIN, DEC2HEX and
- // DEC2OCT.
- func (fn *formulaFuncs) dec2x(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s allows at most 2 arguments", name))
- }
- decimal := argsList.Front().Value.(formulaArg).ToNumber()
- if decimal.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, decimal.Error)
- }
- maxLimitMap := map[string]float64{
- "DEC2BIN": 511,
- "HEX2BIN": 511,
- "OCT2BIN": 511,
- "BIN2HEX": 549755813887,
- "DEC2HEX": 549755813887,
- "OCT2HEX": 549755813887,
- "BIN2OCT": 536870911,
- "DEC2OCT": 536870911,
- "HEX2OCT": 536870911,
- }
- minLimitMap := map[string]float64{
- "DEC2BIN": -512,
- "HEX2BIN": -512,
- "OCT2BIN": -512,
- "BIN2HEX": -549755813888,
- "DEC2HEX": -549755813888,
- "OCT2HEX": -549755813888,
- "BIN2OCT": -536870912,
- "DEC2OCT": -536870912,
- "HEX2OCT": -536870912,
- }
- baseMap := map[string]int{
- "DEC2BIN": 2,
- "HEX2BIN": 2,
- "OCT2BIN": 2,
- "BIN2HEX": 16,
- "DEC2HEX": 16,
- "OCT2HEX": 16,
- "BIN2OCT": 8,
- "DEC2OCT": 8,
- "HEX2OCT": 8,
- }
- maxLimit, minLimit := maxLimitMap[name], minLimitMap[name]
- base := baseMap[name]
- if decimal.Number < minLimit || decimal.Number > maxLimit {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- n := int64(decimal.Number)
- binary := strconv.FormatUint(*(*uint64)(unsafe.Pointer(&n)), base)
- if argsList.Len() == 2 {
- places := argsList.Back().Value.(formulaArg).ToNumber()
- if places.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, places.Error)
- }
- binaryPlaces := len(binary)
- if places.Number < 0 || places.Number > 10 || binaryPlaces > int(places.Number) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%s%s", strings.Repeat("0", int(places.Number)-binaryPlaces), binary)))
- }
- if decimal.Number < 0 && len(binary) > 10 {
- return newStringFormulaArg(strings.ToUpper(binary[len(binary)-10:]))
- }
- return newStringFormulaArg(strings.ToUpper(binary))
- }
- // DELTA function tests two numbers for equality and returns the Kronecker
- // Delta. i.e. the function returns 1 if the two supplied numbers are equal
- // and 0 otherwise. The syntax of the function is:
- //
- // DELTA(number1,[number2])
- func (fn *formulaFuncs) DELTA(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "DELTA requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "DELTA allows at most 2 arguments")
- }
- number1 := argsList.Front().Value.(formulaArg).ToNumber()
- if number1.Type != ArgNumber {
- return number1
- }
- number2 := newNumberFormulaArg(0)
- if argsList.Len() == 2 {
- if number2 = argsList.Back().Value.(formulaArg).ToNumber(); number2.Type != ArgNumber {
- return number2
- }
- }
- return newBoolFormulaArg(number1.Number == number2.Number).ToNumber()
- }
- // ERF function calculates the Error Function, integrated between two supplied
- // limits. The syntax of the function is:
- //
- // ERF(lower_limit,[upper_limit])
- func (fn *formulaFuncs) ERF(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ERF requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "ERF allows at most 2 arguments")
- }
- lower := argsList.Front().Value.(formulaArg).ToNumber()
- if lower.Type != ArgNumber {
- return lower
- }
- if argsList.Len() == 2 {
- upper := argsList.Back().Value.(formulaArg).ToNumber()
- if upper.Type != ArgNumber {
- return upper
- }
- return newNumberFormulaArg(math.Erf(upper.Number) - math.Erf(lower.Number))
- }
- return newNumberFormulaArg(math.Erf(lower.Number))
- }
- // ERFdotPRECISE function calculates the Error Function, integrated between a
- // supplied lower or upper limit and 0. The syntax of the function is:
- //
- // ERF.PRECISE(x)
- func (fn *formulaFuncs) ERFdotPRECISE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ERF.PRECISE requires 1 argument")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- return newNumberFormulaArg(math.Erf(x.Number))
- }
- // erfc is an implementation of the formula functions ERFC and ERFC.PRECISE.
- func (fn *formulaFuncs) erfc(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 1 argument", name))
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- return newNumberFormulaArg(math.Erfc(x.Number))
- }
- // ERFC function calculates the Complementary Error Function, integrated
- // between a supplied lower limit and infinity. The syntax of the function
- // is:
- //
- // ERFC(x)
- func (fn *formulaFuncs) ERFC(argsList *list.List) formulaArg {
- return fn.erfc("ERFC", argsList)
- }
- // ERFCdotPRECISE function calculates the Complementary Error Function,
- // integrated between a supplied lower limit and infinity. The syntax of the
- // function is:
- //
- // ERFC(x)
- func (fn *formulaFuncs) ERFCdotPRECISE(argsList *list.List) formulaArg {
- return fn.erfc("ERFC.PRECISE", argsList)
- }
- // GESTEP unction tests whether a supplied number is greater than a supplied
- // step size and returns. The syntax of the function is:
- //
- // GESTEP(number,[step])
- func (fn *formulaFuncs) GESTEP(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "GESTEP requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "GESTEP allows at most 2 arguments")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type != ArgNumber {
- return number
- }
- step := newNumberFormulaArg(0)
- if argsList.Len() == 2 {
- if step = argsList.Back().Value.(formulaArg).ToNumber(); step.Type != ArgNumber {
- return step
- }
- }
- return newBoolFormulaArg(number.Number >= step.Number).ToNumber()
- }
- // HEX2BIN function converts a Hexadecimal (Base 16) number into a Binary
- // (Base 2) number. The syntax of the function is:
- //
- // HEX2BIN(number,[places])
- func (fn *formulaFuncs) HEX2BIN(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "HEX2BIN requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "HEX2BIN allows at most 2 arguments")
- }
- decimal, newList := fn.hex2dec(argsList.Front().Value.(formulaArg).Value()), list.New()
- if decimal.Type != ArgNumber {
- return decimal
- }
- newList.PushBack(decimal)
- if argsList.Len() == 2 {
- newList.PushBack(argsList.Back().Value.(formulaArg))
- }
- return fn.dec2x("HEX2BIN", newList)
- }
- // HEX2DEC function converts a hexadecimal (a base-16 number) into a decimal
- // number. The syntax of the function is:
- //
- // HEX2DEC(number)
- func (fn *formulaFuncs) HEX2DEC(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "HEX2DEC requires 1 numeric argument")
- }
- return fn.hex2dec(argsList.Front().Value.(formulaArg).Value())
- }
- // HEX2OCT function converts a Hexadecimal (Base 16) number into an Octal
- // (Base 8) number. The syntax of the function is:
- //
- // HEX2OCT(number,[places])
- func (fn *formulaFuncs) HEX2OCT(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "HEX2OCT requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "HEX2OCT allows at most 2 arguments")
- }
- decimal, newList := fn.hex2dec(argsList.Front().Value.(formulaArg).Value()), list.New()
- if decimal.Type != ArgNumber {
- return decimal
- }
- newList.PushBack(decimal)
- if argsList.Len() == 2 {
- newList.PushBack(argsList.Back().Value.(formulaArg))
- }
- return fn.dec2x("HEX2OCT", newList)
- }
- // hex2dec is an implementation of the formula function HEX2DEC.
- func (fn *formulaFuncs) hex2dec(number string) formulaArg {
- decimal, length := 0.0, len(number)
- for i := length; i > 0; i-- {
- num, err := strconv.ParseInt(string(number[length-i]), 16, 64)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- if i == 10 && string(number[length-i]) == "F" {
- decimal += math.Pow(-16.0, float64(i-1))
- continue
- }
- decimal += float64(num) * math.Pow(16.0, float64(i-1))
- }
- return newNumberFormulaArg(decimal)
- }
- // IMABS function returns the absolute value (the modulus) of a complex
- // number. The syntax of the function is:
- //
- // IMABS(inumber)
- func (fn *formulaFuncs) IMABS(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMABS requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newNumberFormulaArg(cmplx.Abs(inumber))
- }
- // IMAGINARY function returns the imaginary coefficient of a supplied complex
- // number. The syntax of the function is:
- //
- // IMAGINARY(inumber)
- func (fn *formulaFuncs) IMAGINARY(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMAGINARY requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newNumberFormulaArg(imag(inumber))
- }
- // IMARGUMENT function returns the phase (also called the argument) of a
- // supplied complex number. The syntax of the function is:
- //
- // IMARGUMENT(inumber)
- func (fn *formulaFuncs) IMARGUMENT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMARGUMENT requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newNumberFormulaArg(cmplx.Phase(inumber))
- }
- // IMCONJUGATE function returns the complex conjugate of a supplied complex
- // number. The syntax of the function is:
- //
- // IMCONJUGATE(inumber)
- func (fn *formulaFuncs) IMCONJUGATE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMCONJUGATE requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(cmplx.Conj(inumber), value[len(value)-1:]))
- }
- // IMCOS function returns the cosine of a supplied complex number. The syntax
- // of the function is:
- //
- // IMCOS(inumber)
- func (fn *formulaFuncs) IMCOS(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMCOS requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(cmplx.Cos(inumber), value[len(value)-1:]))
- }
- // IMCOSH function returns the hyperbolic cosine of a supplied complex number. The syntax
- // of the function is:
- //
- // IMCOSH(inumber)
- func (fn *formulaFuncs) IMCOSH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMCOSH requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(cmplx.Cosh(inumber), value[len(value)-1:]))
- }
- // IMCOT function returns the cotangent of a supplied complex number. The syntax
- // of the function is:
- //
- // IMCOT(inumber)
- func (fn *formulaFuncs) IMCOT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMCOT requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(cmplx.Cot(inumber), value[len(value)-1:]))
- }
- // IMCSC function returns the cosecant of a supplied complex number. The syntax
- // of the function is:
- //
- // IMCSC(inumber)
- func (fn *formulaFuncs) IMCSC(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMCSC requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- num := 1 / cmplx.Sin(inumber)
- if cmplx.IsInf(num) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newStringFormulaArg(cmplx2str(num, value[len(value)-1:]))
- }
- // IMCSCH function returns the hyperbolic cosecant of a supplied complex
- // number. The syntax of the function is:
- //
- // IMCSCH(inumber)
- func (fn *formulaFuncs) IMCSCH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMCSCH requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- num := 1 / cmplx.Sinh(inumber)
- if cmplx.IsInf(num) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newStringFormulaArg(cmplx2str(num, value[len(value)-1:]))
- }
- // IMDIV function calculates the quotient of two complex numbers (i.e. divides
- // one complex number by another). The syntax of the function is:
- //
- // IMDIV(inumber1,inumber2)
- func (fn *formulaFuncs) IMDIV(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMDIV requires 2 arguments")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber1, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- inumber2, err := strconv.ParseComplex(str2cmplx(argsList.Back().Value.(formulaArg).Value()), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- num := inumber1 / inumber2
- if cmplx.IsInf(num) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newStringFormulaArg(cmplx2str(num, value[len(value)-1:]))
- }
- // IMEXP function returns the exponential of a supplied complex number. The
- // syntax of the function is:
- //
- // IMEXP(inumber)
- func (fn *formulaFuncs) IMEXP(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMEXP requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(cmplx.Exp(inumber), value[len(value)-1:]))
- }
- // IMLN function returns the natural logarithm of a supplied complex number.
- // The syntax of the function is:
- //
- // IMLN(inumber)
- func (fn *formulaFuncs) IMLN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMLN requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- num := cmplx.Log(inumber)
- if cmplx.IsInf(num) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newStringFormulaArg(cmplx2str(num, value[len(value)-1:]))
- }
- // IMLOG10 function returns the common (base 10) logarithm of a supplied
- // complex number. The syntax of the function is:
- //
- // IMLOG10(inumber)
- func (fn *formulaFuncs) IMLOG10(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMLOG10 requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- num := cmplx.Log10(inumber)
- if cmplx.IsInf(num) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newStringFormulaArg(cmplx2str(num, value[len(value)-1:]))
- }
- // IMLOG2 function calculates the base 2 logarithm of a supplied complex
- // number. The syntax of the function is:
- //
- // IMLOG2(inumber)
- func (fn *formulaFuncs) IMLOG2(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMLOG2 requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- num := cmplx.Log(inumber)
- if cmplx.IsInf(num) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newStringFormulaArg(cmplx2str(num/cmplx.Log(2), value[len(value)-1:]))
- }
- // IMPOWER function returns a supplied complex number, raised to a given
- // power. The syntax of the function is:
- //
- // IMPOWER(inumber,number)
- func (fn *formulaFuncs) IMPOWER(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMPOWER requires 2 arguments")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- number, err := strconv.ParseComplex(str2cmplx(argsList.Back().Value.(formulaArg).Value()), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- if inumber == 0 && number == 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- num := cmplx.Pow(inumber, number)
- if cmplx.IsInf(num) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newStringFormulaArg(cmplx2str(num, value[len(value)-1:]))
- }
- // IMPRODUCT function calculates the product of two or more complex numbers.
- // The syntax of the function is:
- //
- // IMPRODUCT(number1,[number2],...)
- func (fn *formulaFuncs) IMPRODUCT(argsList *list.List) formulaArg {
- product := complex128(1)
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgString:
- if token.Value() == "" {
- continue
- }
- val, err := strconv.ParseComplex(str2cmplx(token.Value()), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- product = product * val
- case ArgNumber:
- product = product * complex(token.Number, 0)
- case ArgMatrix:
- for _, row := range token.Matrix {
- for _, value := range row {
- if value.Value() == "" {
- continue
- }
- val, err := strconv.ParseComplex(str2cmplx(value.Value()), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- product = product * val
- }
- }
- }
- }
- return newStringFormulaArg(cmplx2str(product, "i"))
- }
- // IMREAL function returns the real coefficient of a supplied complex number.
- // The syntax of the function is:
- //
- // IMREAL(inumber)
- func (fn *formulaFuncs) IMREAL(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMREAL requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(fmt.Sprint(real(inumber)))
- }
- // IMSEC function returns the secant of a supplied complex number. The syntax
- // of the function is:
- //
- // IMSEC(inumber)
- func (fn *formulaFuncs) IMSEC(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMSEC requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(1/cmplx.Cos(inumber), value[len(value)-1:]))
- }
- // IMSECH function returns the hyperbolic secant of a supplied complex number.
- // The syntax of the function is:
- //
- // IMSECH(inumber)
- func (fn *formulaFuncs) IMSECH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMSECH requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(1/cmplx.Cosh(inumber), value[len(value)-1:]))
- }
- // IMSIN function returns the Sine of a supplied complex number. The syntax of
- // the function is:
- //
- // IMSIN(inumber)
- func (fn *formulaFuncs) IMSIN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMSIN requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(cmplx.Sin(inumber), value[len(value)-1:]))
- }
- // IMSINH function returns the hyperbolic sine of a supplied complex number.
- // The syntax of the function is:
- //
- // IMSINH(inumber)
- func (fn *formulaFuncs) IMSINH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMSINH requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(cmplx.Sinh(inumber), value[len(value)-1:]))
- }
- // IMSQRT function returns the square root of a supplied complex number. The
- // syntax of the function is:
- //
- // IMSQRT(inumber)
- func (fn *formulaFuncs) IMSQRT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMSQRT requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(cmplx.Sqrt(inumber), value[len(value)-1:]))
- }
- // IMSUB function calculates the difference between two complex numbers
- // (i.e. subtracts one complex number from another). The syntax of the
- // function is:
- //
- // IMSUB(inumber1,inumber2)
- func (fn *formulaFuncs) IMSUB(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMSUB requires 2 arguments")
- }
- i1, err := strconv.ParseComplex(str2cmplx(argsList.Front().Value.(formulaArg).Value()), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- i2, err := strconv.ParseComplex(str2cmplx(argsList.Back().Value.(formulaArg).Value()), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(i1-i2, "i"))
- }
- // IMSUM function calculates the sum of two or more complex numbers. The
- // syntax of the function is:
- //
- // IMSUM(inumber1,inumber2,...)
- func (fn *formulaFuncs) IMSUM(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMSUM requires at least 1 argument")
- }
- var result complex128
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- num, err := strconv.ParseComplex(str2cmplx(token.Value()), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- result += num
- }
- return newStringFormulaArg(cmplx2str(result, "i"))
- }
- // IMTAN function returns the tangent of a supplied complex number. The syntax
- // of the function is:
- //
- // IMTAN(inumber)
- func (fn *formulaFuncs) IMTAN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IMTAN requires 1 argument")
- }
- value := argsList.Front().Value.(formulaArg).Value()
- inumber, err := strconv.ParseComplex(str2cmplx(value), 128)
- if err != nil {
- return newErrorFormulaArg(formulaErrorNUM, err.Error())
- }
- return newStringFormulaArg(cmplx2str(cmplx.Tan(inumber), value[len(value)-1:]))
- }
- // OCT2BIN function converts an Octal (Base 8) number into a Binary (Base 2)
- // number. The syntax of the function is:
- //
- // OCT2BIN(number,[places])
- func (fn *formulaFuncs) OCT2BIN(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "OCT2BIN requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "OCT2BIN allows at most 2 arguments")
- }
- token := argsList.Front().Value.(formulaArg)
- number := token.ToNumber()
- if number.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, number.Error)
- }
- decimal, newList := fn.oct2dec(token.Value()), list.New()
- newList.PushBack(decimal)
- if argsList.Len() == 2 {
- newList.PushBack(argsList.Back().Value.(formulaArg))
- }
- return fn.dec2x("OCT2BIN", newList)
- }
- // OCT2DEC function converts an Octal (a base-8 number) into a decimal number.
- // The syntax of the function is:
- //
- // OCT2DEC(number)
- func (fn *formulaFuncs) OCT2DEC(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "OCT2DEC requires 1 numeric argument")
- }
- token := argsList.Front().Value.(formulaArg)
- number := token.ToNumber()
- if number.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, number.Error)
- }
- return fn.oct2dec(token.Value())
- }
- // OCT2HEX function converts an Octal (Base 8) number into a Hexadecimal
- // (Base 16) number. The syntax of the function is:
- //
- // OCT2HEX(number,[places])
- func (fn *formulaFuncs) OCT2HEX(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "OCT2HEX requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "OCT2HEX allows at most 2 arguments")
- }
- token := argsList.Front().Value.(formulaArg)
- number := token.ToNumber()
- if number.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, number.Error)
- }
- decimal, newList := fn.oct2dec(token.Value()), list.New()
- newList.PushBack(decimal)
- if argsList.Len() == 2 {
- newList.PushBack(argsList.Back().Value.(formulaArg))
- }
- return fn.dec2x("OCT2HEX", newList)
- }
- // oct2dec is an implementation of the formula function OCT2DEC.
- func (fn *formulaFuncs) oct2dec(number string) formulaArg {
- decimal, length := 0.0, len(number)
- for i := length; i > 0; i-- {
- num, _ := strconv.Atoi(string(number[length-i]))
- if i == 10 && string(number[length-i]) == "7" {
- decimal += math.Pow(-8.0, float64(i-1))
- continue
- }
- decimal += float64(num) * math.Pow(8.0, float64(i-1))
- }
- return newNumberFormulaArg(decimal)
- }
- // Math and Trigonometric Functions
- // ABS function returns the absolute value of any supplied number. The syntax
- // of the function is:
- //
- // ABS(number)
- func (fn *formulaFuncs) ABS(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ABS requires 1 numeric argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type == ArgError {
- return arg
- }
- return newNumberFormulaArg(math.Abs(arg.Number))
- }
- // ACOS function calculates the arccosine (i.e. the inverse cosine) of a given
- // number, and returns an angle, in radians, between 0 and π. The syntax of
- // the function is:
- //
- // ACOS(number)
- func (fn *formulaFuncs) ACOS(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ACOS requires 1 numeric argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type == ArgError {
- return arg
- }
- return newNumberFormulaArg(math.Acos(arg.Number))
- }
- // ACOSH function calculates the inverse hyperbolic cosine of a supplied number.
- // of the function is:
- //
- // ACOSH(number)
- func (fn *formulaFuncs) ACOSH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ACOSH requires 1 numeric argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type == ArgError {
- return arg
- }
- return newNumberFormulaArg(math.Acosh(arg.Number))
- }
- // ACOT function calculates the arccotangent (i.e. the inverse cotangent) of a
- // given number, and returns an angle, in radians, between 0 and π. The syntax
- // of the function is:
- //
- // ACOT(number)
- func (fn *formulaFuncs) ACOT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ACOT requires 1 numeric argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type == ArgError {
- return arg
- }
- return newNumberFormulaArg(math.Pi/2 - math.Atan(arg.Number))
- }
- // ACOTH function calculates the hyperbolic arccotangent (coth) of a supplied
- // value. The syntax of the function is:
- //
- // ACOTH(number)
- func (fn *formulaFuncs) ACOTH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ACOTH requires 1 numeric argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type == ArgError {
- return arg
- }
- return newNumberFormulaArg(math.Atanh(1 / arg.Number))
- }
- // AGGREGATE function returns the result of a specified operation or function,
- // applied to a list or database of values. The syntax of the function is:
- //
- // AGGREGATE(function_num,options,ref1,[ref2],...)
- func (fn *formulaFuncs) AGGREGATE(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "AGGREGATE requires at least 3 arguments")
- }
- var fnNum, opts formulaArg
- if fnNum = argsList.Front().Value.(formulaArg).ToNumber(); fnNum.Type != ArgNumber {
- return fnNum
- }
- subFn, ok := map[int]func(argsList *list.List) formulaArg{
- 1: fn.AVERAGE,
- 2: fn.COUNT,
- 3: fn.COUNTA,
- 4: fn.MAX,
- 5: fn.MIN,
- 6: fn.PRODUCT,
- 7: fn.STDEVdotS,
- 8: fn.STDEVdotP,
- 9: fn.SUM,
- 10: fn.VARdotS,
- 11: fn.VARdotP,
- 12: fn.MEDIAN,
- 13: fn.MODEdotSNGL,
- 14: fn.LARGE,
- 15: fn.SMALL,
- 16: fn.PERCENTILEdotINC,
- 17: fn.QUARTILEdotINC,
- 18: fn.PERCENTILEdotEXC,
- 19: fn.QUARTILEdotEXC,
- }[int(fnNum.Number)]
- if !ok {
- return newErrorFormulaArg(formulaErrorVALUE, "AGGREGATE has invalid function_num")
- }
- if opts = argsList.Front().Next().Value.(formulaArg).ToNumber(); opts.Type != ArgNumber {
- return opts
- }
- // TODO: apply option argument values to be ignored during the calculation
- if int(opts.Number) < 0 || int(opts.Number) > 7 {
- return newErrorFormulaArg(formulaErrorVALUE, "AGGREGATE has invalid options")
- }
- subArgList := list.New().Init()
- for arg := argsList.Front().Next().Next(); arg != nil; arg = arg.Next() {
- subArgList.PushBack(arg.Value.(formulaArg))
- }
- return subFn(subArgList)
- }
- // ARABIC function converts a Roman numeral into an Arabic numeral. The syntax
- // of the function is:
- //
- // ARABIC(text)
- func (fn *formulaFuncs) ARABIC(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ARABIC requires 1 numeric argument")
- }
- text := argsList.Front().Value.(formulaArg).Value()
- if len(text) > MaxFieldLength {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- text = strings.ToUpper(text)
- number, actualStart, index, isNegative := 0, 0, len(text)-1, false
- startIndex, subtractNumber, currentPartValue, currentCharValue, prevCharValue := 0, 0, 0, 0, -1
- for index >= 0 && text[index] == ' ' {
- index--
- }
- for actualStart <= index && text[actualStart] == ' ' {
- actualStart++
- }
- if actualStart <= index && text[actualStart] == '-' {
- isNegative = true
- actualStart++
- }
- charMap := map[rune]int{'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
- for index >= actualStart {
- startIndex = index
- startChar := text[startIndex]
- index--
- for index >= actualStart && (text[index]|' ') == startChar {
- index--
- }
- currentCharValue = charMap[rune(startChar)]
- currentPartValue = (startIndex - index) * currentCharValue
- if currentCharValue >= prevCharValue {
- number += currentPartValue - subtractNumber
- prevCharValue = currentCharValue
- subtractNumber = 0
- continue
- }
- subtractNumber += currentPartValue
- }
- if subtractNumber != 0 {
- number -= subtractNumber
- }
- if isNegative {
- number = -number
- }
- return newNumberFormulaArg(float64(number))
- }
- // ASIN function calculates the arcsine (i.e. the inverse sine) of a given
- // number, and returns an angle, in radians, between -π/2 and π/2. The syntax
- // of the function is:
- //
- // ASIN(number)
- func (fn *formulaFuncs) ASIN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ASIN requires 1 numeric argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type == ArgError {
- return arg
- }
- return newNumberFormulaArg(math.Asin(arg.Number))
- }
- // ASINH function calculates the inverse hyperbolic sine of a supplied number.
- // The syntax of the function is:
- //
- // ASINH(number)
- func (fn *formulaFuncs) ASINH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ASINH requires 1 numeric argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type == ArgError {
- return arg
- }
- return newNumberFormulaArg(math.Asinh(arg.Number))
- }
- // ATAN function calculates the arctangent (i.e. the inverse tangent) of a
- // given number, and returns an angle, in radians, between -π/2 and +π/2. The
- // syntax of the function is:
- //
- // ATAN(number)
- func (fn *formulaFuncs) ATAN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ATAN requires 1 numeric argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type == ArgError {
- return arg
- }
- return newNumberFormulaArg(math.Atan(arg.Number))
- }
- // ATANH function calculates the inverse hyperbolic tangent of a supplied
- // number. The syntax of the function is:
- //
- // ATANH(number)
- func (fn *formulaFuncs) ATANH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ATANH requires 1 numeric argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type == ArgError {
- return arg
- }
- return newNumberFormulaArg(math.Atanh(arg.Number))
- }
- // ATAN2 function calculates the arctangent (i.e. the inverse tangent) of a
- // given set of x and y coordinates, and returns an angle, in radians, between
- // -π/2 and +π/2. The syntax of the function is:
- //
- // ATAN2(x_num,y_num)
- func (fn *formulaFuncs) ATAN2(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "ATAN2 requires 2 numeric arguments")
- }
- x := argsList.Back().Value.(formulaArg).ToNumber()
- if x.Type == ArgError {
- return x
- }
- y := argsList.Front().Value.(formulaArg).ToNumber()
- if y.Type == ArgError {
- return y
- }
- return newNumberFormulaArg(math.Atan2(x.Number, y.Number))
- }
- // BASE function converts a number into a supplied base (radix), and returns a
- // text representation of the calculated value. The syntax of the function is:
- //
- // BASE(number,radix,[min_length])
- func (fn *formulaFuncs) BASE(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "BASE requires at least 2 arguments")
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "BASE allows at most 3 arguments")
- }
- var minLength int
- var err error
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- radix := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if radix.Type == ArgError {
- return radix
- }
- if int(radix.Number) < 2 || int(radix.Number) > 36 {
- return newErrorFormulaArg(formulaErrorVALUE, "radix must be an integer >= 2 and <= 36")
- }
- if argsList.Len() > 2 {
- if minLength, err = strconv.Atoi(argsList.Back().Value.(formulaArg).Value()); err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- }
- result := strconv.FormatInt(int64(number.Number), int(radix.Number))
- if len(result) < minLength {
- result = strings.Repeat("0", minLength-len(result)) + result
- }
- return newStringFormulaArg(strings.ToUpper(result))
- }
- // CEILING function rounds a supplied number away from zero, to the nearest
- // multiple of a given number. The syntax of the function is:
- //
- // CEILING(number,significance)
- func (fn *formulaFuncs) CEILING(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "CEILING requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CEILING allows at most 2 arguments")
- }
- number, significance, res := 0.0, 1.0, 0.0
- n := argsList.Front().Value.(formulaArg).ToNumber()
- if n.Type == ArgError {
- return n
- }
- number = n.Number
- if number < 0 {
- significance = -1
- }
- if argsList.Len() > 1 {
- s := argsList.Back().Value.(formulaArg).ToNumber()
- if s.Type == ArgError {
- return s
- }
- significance = s.Number
- }
- if significance < 0 && number > 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "negative sig to CEILING invalid")
- }
- if argsList.Len() == 1 {
- return newNumberFormulaArg(math.Ceil(number))
- }
- number, res = math.Modf(number / significance)
- if res > 0 {
- number++
- }
- return newNumberFormulaArg(number * significance)
- }
- // CEILINGdotMATH function rounds a supplied number up to a supplied multiple
- // of significance. The syntax of the function is:
- //
- // CEILING.MATH(number,[significance],[mode])
- func (fn *formulaFuncs) CEILINGdotMATH(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "CEILING.MATH requires at least 1 argument")
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "CEILING.MATH allows at most 3 arguments")
- }
- number, significance, mode := 0.0, 1.0, 1.0
- n := argsList.Front().Value.(formulaArg).ToNumber()
- if n.Type == ArgError {
- return n
- }
- number = n.Number
- if number < 0 {
- significance = -1
- }
- if argsList.Len() > 1 {
- s := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if s.Type == ArgError {
- return s
- }
- significance = s.Number
- }
- if argsList.Len() == 1 {
- return newNumberFormulaArg(math.Ceil(number))
- }
- if argsList.Len() > 2 {
- m := argsList.Back().Value.(formulaArg).ToNumber()
- if m.Type == ArgError {
- return m
- }
- mode = m.Number
- }
- val, res := math.Modf(number / significance)
- if res != 0 {
- if number > 0 {
- val++
- } else if mode < 0 {
- val--
- }
- }
- return newNumberFormulaArg(val * significance)
- }
- // CEILINGdotPRECISE function rounds a supplied number up (regardless of the
- // number's sign), to the nearest multiple of a given number. The syntax of
- // the function is:
- //
- // CEILING.PRECISE(number,[significance])
- func (fn *formulaFuncs) CEILINGdotPRECISE(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "CEILING.PRECISE requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CEILING.PRECISE allows at most 2 arguments")
- }
- number, significance := 0.0, 1.0
- n := argsList.Front().Value.(formulaArg).ToNumber()
- if n.Type == ArgError {
- return n
- }
- number = n.Number
- if number < 0 {
- significance = -1
- }
- if argsList.Len() == 1 {
- return newNumberFormulaArg(math.Ceil(number))
- }
- if argsList.Len() > 1 {
- s := argsList.Back().Value.(formulaArg).ToNumber()
- if s.Type == ArgError {
- return s
- }
- significance = s.Number
- significance = math.Abs(significance)
- if significance == 0 {
- return newNumberFormulaArg(significance)
- }
- }
- val, res := math.Modf(number / significance)
- if res != 0 {
- if number > 0 {
- val++
- }
- }
- return newNumberFormulaArg(val * significance)
- }
- // COMBIN function calculates the number of combinations (in any order) of a
- // given number objects from a set. The syntax of the function is:
- //
- // COMBIN(number,number_chosen)
- func (fn *formulaFuncs) COMBIN(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "COMBIN requires 2 argument")
- }
- number, chosen, val := 0.0, 0.0, 1.0
- n := argsList.Front().Value.(formulaArg).ToNumber()
- if n.Type == ArgError {
- return n
- }
- number = n.Number
- c := argsList.Back().Value.(formulaArg).ToNumber()
- if c.Type == ArgError {
- return c
- }
- chosen = c.Number
- number, chosen = math.Trunc(number), math.Trunc(chosen)
- if chosen > number {
- return newErrorFormulaArg(formulaErrorVALUE, "COMBIN requires number >= number_chosen")
- }
- if chosen == number || chosen == 0 {
- return newNumberFormulaArg(1)
- }
- for c := float64(1); c <= chosen; c++ {
- val *= (number + 1 - c) / c
- }
- return newNumberFormulaArg(math.Ceil(val))
- }
- // COMBINA function calculates the number of combinations, with repetitions,
- // of a given number objects from a set. The syntax of the function is:
- //
- // COMBINA(number,number_chosen)
- func (fn *formulaFuncs) COMBINA(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "COMBINA requires 2 argument")
- }
- var number, chosen float64
- n := argsList.Front().Value.(formulaArg).ToNumber()
- if n.Type == ArgError {
- return n
- }
- number = n.Number
- c := argsList.Back().Value.(formulaArg).ToNumber()
- if c.Type == ArgError {
- return c
- }
- chosen = c.Number
- number, chosen = math.Trunc(number), math.Trunc(chosen)
- if number < chosen {
- return newErrorFormulaArg(formulaErrorVALUE, "COMBINA requires number > number_chosen")
- }
- if number == 0 {
- return newNumberFormulaArg(number)
- }
- args := list.New()
- args.PushBack(formulaArg{
- String: fmt.Sprintf("%g", number+chosen-1),
- Type: ArgString,
- })
- args.PushBack(formulaArg{
- String: fmt.Sprintf("%g", number-1),
- Type: ArgString,
- })
- return fn.COMBIN(args)
- }
- // COS function calculates the cosine of a given angle. The syntax of the
- // function is:
- //
- // COS(number)
- func (fn *formulaFuncs) COS(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "COS requires 1 numeric argument")
- }
- val := argsList.Front().Value.(formulaArg).ToNumber()
- if val.Type == ArgError {
- return val
- }
- return newNumberFormulaArg(math.Cos(val.Number))
- }
- // COSH function calculates the hyperbolic cosine (cosh) of a supplied number.
- // The syntax of the function is:
- //
- // COSH(number)
- func (fn *formulaFuncs) COSH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "COSH requires 1 numeric argument")
- }
- val := argsList.Front().Value.(formulaArg).ToNumber()
- if val.Type == ArgError {
- return val
- }
- return newNumberFormulaArg(math.Cosh(val.Number))
- }
- // COT function calculates the cotangent of a given angle. The syntax of the
- // function is:
- //
- // COT(number)
- func (fn *formulaFuncs) COT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "COT requires 1 numeric argument")
- }
- val := argsList.Front().Value.(formulaArg).ToNumber()
- if val.Type == ArgError {
- return val
- }
- if val.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(1 / math.Tan(val.Number))
- }
- // COTH function calculates the hyperbolic cotangent (coth) of a supplied
- // angle. The syntax of the function is:
- //
- // COTH(number)
- func (fn *formulaFuncs) COTH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "COTH requires 1 numeric argument")
- }
- val := argsList.Front().Value.(formulaArg).ToNumber()
- if val.Type == ArgError {
- return val
- }
- if val.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg((math.Exp(val.Number) + math.Exp(-val.Number)) / (math.Exp(val.Number) - math.Exp(-val.Number)))
- }
- // CSC function calculates the cosecant of a given angle. The syntax of the
- // function is:
- //
- // CSC(number)
- func (fn *formulaFuncs) CSC(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "CSC requires 1 numeric argument")
- }
- val := argsList.Front().Value.(formulaArg).ToNumber()
- if val.Type == ArgError {
- return val
- }
- if val.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(1 / math.Sin(val.Number))
- }
- // CSCH function calculates the hyperbolic cosecant (csch) of a supplied
- // angle. The syntax of the function is:
- //
- // CSCH(number)
- func (fn *formulaFuncs) CSCH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "CSCH requires 1 numeric argument")
- }
- val := argsList.Front().Value.(formulaArg).ToNumber()
- if val.Type == ArgError {
- return val
- }
- if val.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(1 / math.Sinh(val.Number))
- }
- // DECIMAL function converts a text representation of a number in a specified
- // base, into a decimal value. The syntax of the function is:
- //
- // DECIMAL(text,radix)
- func (fn *formulaFuncs) DECIMAL(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "DECIMAL requires 2 numeric arguments")
- }
- text := argsList.Front().Value.(formulaArg).Value()
- var err error
- radix := argsList.Back().Value.(formulaArg).ToNumber()
- if radix.Type != ArgNumber {
- return radix
- }
- if len(text) > 2 && (strings.HasPrefix(text, "0x") || strings.HasPrefix(text, "0X")) {
- text = text[2:]
- }
- val, err := strconv.ParseInt(text, int(radix.Number), 64)
- if err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- return newNumberFormulaArg(float64(val))
- }
- // DEGREES function converts radians into degrees. The syntax of the function
- // is:
- //
- // DEGREES(angle)
- func (fn *formulaFuncs) DEGREES(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "DEGREES requires 1 numeric argument")
- }
- val := argsList.Front().Value.(formulaArg).ToNumber()
- if val.Type == ArgError {
- return val
- }
- if val.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(180.0 / math.Pi * val.Number)
- }
- // EVEN function rounds a supplied number away from zero (i.e. rounds a
- // positive number up and a negative number down), to the next even number.
- // The syntax of the function is:
- //
- // EVEN(number)
- func (fn *formulaFuncs) EVEN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "EVEN requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- sign := math.Signbit(number.Number)
- m, frac := math.Modf(number.Number / 2)
- val := m * 2
- if frac != 0 {
- if !sign {
- val += 2
- } else {
- val -= 2
- }
- }
- return newNumberFormulaArg(val)
- }
- // EXP function calculates the value of the mathematical constant e, raised to
- // the power of a given number. The syntax of the function is:
- //
- // EXP(number)
- func (fn *formulaFuncs) EXP(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "EXP requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", math.Exp(number.Number))))
- }
- // fact returns the factorial of a supplied number.
- func fact(number float64) float64 {
- val := float64(1)
- for i := float64(2); i <= number; i++ {
- val *= i
- }
- return val
- }
- // FACT function returns the factorial of a supplied number. The syntax of the
- // function is:
- //
- // FACT(number)
- func (fn *formulaFuncs) FACT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "FACT requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- if number.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(fact(number.Number))
- }
- // FACTDOUBLE function returns the double factorial of a supplied number. The
- // syntax of the function is:
- //
- // FACTDOUBLE(number)
- func (fn *formulaFuncs) FACTDOUBLE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "FACTDOUBLE requires 1 numeric argument")
- }
- val := 1.0
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- if number.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- for i := math.Trunc(number.Number); i > 1; i -= 2 {
- val *= i
- }
- return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", val)))
- }
- // FLOOR function rounds a supplied number towards zero to the nearest
- // multiple of a specified significance. The syntax of the function is:
- //
- // FLOOR(number,significance)
- func (fn *formulaFuncs) FLOOR(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "FLOOR requires 2 numeric arguments")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- significance := argsList.Back().Value.(formulaArg).ToNumber()
- if significance.Type == ArgError {
- return significance
- }
- if significance.Number < 0 && number.Number >= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "invalid arguments to FLOOR")
- }
- val := number.Number
- val, res := math.Modf(val / significance.Number)
- if res != 0 {
- if number.Number < 0 && res < 0 {
- val--
- }
- }
- return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", val*significance.Number)))
- }
- // FLOORdotMATH function rounds a supplied number down to a supplied multiple
- // of significance. The syntax of the function is:
- //
- // FLOOR.MATH(number,[significance],[mode])
- func (fn *formulaFuncs) FLOORdotMATH(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.MATH requires at least 1 argument")
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.MATH allows at most 3 arguments")
- }
- significance, mode := 1.0, 1.0
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- if number.Number < 0 {
- significance = -1
- }
- if argsList.Len() > 1 {
- s := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if s.Type == ArgError {
- return s
- }
- significance = s.Number
- }
- if argsList.Len() == 1 {
- return newNumberFormulaArg(math.Floor(number.Number))
- }
- if argsList.Len() > 2 {
- m := argsList.Back().Value.(formulaArg).ToNumber()
- if m.Type == ArgError {
- return m
- }
- mode = m.Number
- }
- val, res := math.Modf(number.Number / significance)
- if res != 0 && number.Number < 0 && mode > 0 {
- val--
- }
- return newNumberFormulaArg(val * significance)
- }
- // FLOORdotPRECISE function rounds a supplied number down to a supplied
- // multiple of significance. The syntax of the function is:
- //
- // FLOOR.PRECISE(number,[significance])
- func (fn *formulaFuncs) FLOORdotPRECISE(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.PRECISE requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "FLOOR.PRECISE allows at most 2 arguments")
- }
- var significance float64
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- if number.Number < 0 {
- significance = -1
- }
- if argsList.Len() == 1 {
- return newNumberFormulaArg(math.Floor(number.Number))
- }
- if argsList.Len() > 1 {
- s := argsList.Back().Value.(formulaArg).ToNumber()
- if s.Type == ArgError {
- return s
- }
- significance = s.Number
- significance = math.Abs(significance)
- if significance == 0 {
- return newNumberFormulaArg(significance)
- }
- }
- val, res := math.Modf(number.Number / significance)
- if res != 0 {
- if number.Number < 0 {
- val--
- }
- }
- return newNumberFormulaArg(val * significance)
- }
- // gcd returns the greatest common divisor of two supplied integers.
- func gcd(x, y float64) float64 {
- x, y = math.Trunc(x), math.Trunc(y)
- if x == 0 {
- return y
- }
- if y == 0 {
- return x
- }
- for x != y {
- if x > y {
- x = x - y
- } else {
- y = y - x
- }
- }
- return x
- }
- // GCD function returns the greatest common divisor of two or more supplied
- // integers. The syntax of the function is:
- //
- // GCD(number1,[number2],...)
- func (fn *formulaFuncs) GCD(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "GCD requires at least 1 argument")
- }
- var (
- val float64
- nums []float64
- )
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgString:
- num := token.ToNumber()
- if num.Type == ArgError {
- return num
- }
- val = num.Number
- case ArgNumber:
- val = token.Number
- }
- nums = append(nums, val)
- }
- if nums[0] < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "GCD only accepts positive arguments")
- }
- if len(nums) == 1 {
- return newNumberFormulaArg(nums[0])
- }
- cd := nums[0]
- for i := 1; i < len(nums); i++ {
- if nums[i] < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "GCD only accepts positive arguments")
- }
- cd = gcd(cd, nums[i])
- }
- return newNumberFormulaArg(cd)
- }
- // INT function truncates a supplied number down to the closest integer. The
- // syntax of the function is:
- //
- // INT(number)
- func (fn *formulaFuncs) INT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "INT requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- val, frac := math.Modf(number.Number)
- if frac < 0 {
- val--
- }
- return newNumberFormulaArg(val)
- }
- // ISOdotCEILING function rounds a supplied number up (regardless of the
- // number's sign), to the nearest multiple of a supplied significance. The
- // syntax of the function is:
- //
- // ISO.CEILING(number,[significance])
- func (fn *formulaFuncs) ISOdotCEILING(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISO.CEILING requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISO.CEILING allows at most 2 arguments")
- }
- var significance float64
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- if number.Number < 0 {
- significance = -1
- }
- if argsList.Len() == 1 {
- return newNumberFormulaArg(math.Ceil(number.Number))
- }
- if argsList.Len() > 1 {
- s := argsList.Back().Value.(formulaArg).ToNumber()
- if s.Type == ArgError {
- return s
- }
- significance = s.Number
- significance = math.Abs(significance)
- if significance == 0 {
- return newNumberFormulaArg(significance)
- }
- }
- val, res := math.Modf(number.Number / significance)
- if res != 0 {
- if number.Number > 0 {
- val++
- }
- }
- return newNumberFormulaArg(val * significance)
- }
- // lcm returns the least common multiple of two supplied integers.
- func lcm(a, b float64) float64 {
- a = math.Trunc(a)
- b = math.Trunc(b)
- if a == 0 && b == 0 {
- return 0
- }
- return a * b / gcd(a, b)
- }
- // LCM function returns the least common multiple of two or more supplied
- // integers. The syntax of the function is:
- //
- // LCM(number1,[number2],...)
- func (fn *formulaFuncs) LCM(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "LCM requires at least 1 argument")
- }
- var (
- val float64
- nums []float64
- err error
- )
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgString:
- if token.String == "" {
- continue
- }
- if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- case ArgNumber:
- val = token.Number
- }
- nums = append(nums, val)
- }
- if nums[0] < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "LCM only accepts positive arguments")
- }
- if len(nums) == 1 {
- return newNumberFormulaArg(nums[0])
- }
- cm := nums[0]
- for i := 1; i < len(nums); i++ {
- if nums[i] < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "LCM only accepts positive arguments")
- }
- cm = lcm(cm, nums[i])
- }
- return newNumberFormulaArg(cm)
- }
- // LN function calculates the natural logarithm of a given number. The syntax
- // of the function is:
- //
- // LN(number)
- func (fn *formulaFuncs) LN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "LN requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newNumberFormulaArg(math.Log(number.Number))
- }
- // LOG function calculates the logarithm of a given number, to a supplied
- // base. The syntax of the function is:
- //
- // LOG(number,[base])
- func (fn *formulaFuncs) LOG(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOG requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOG allows at most 2 arguments")
- }
- base := 10.0
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- if argsList.Len() > 1 {
- b := argsList.Back().Value.(formulaArg).ToNumber()
- if b.Type == ArgError {
- return b
- }
- base = b.Number
- }
- if number.Number == 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorDIV)
- }
- if base == 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorDIV)
- }
- if base == 1 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(math.Log(number.Number) / math.Log(base))
- }
- // LOG10 function calculates the base 10 logarithm of a given number. The
- // syntax of the function is:
- //
- // LOG10(number)
- func (fn *formulaFuncs) LOG10(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOG10 requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newNumberFormulaArg(math.Log10(number.Number))
- }
- // minor function implement a minor of a matrix A is the determinant of some
- // smaller square matrix.
- func minor(sqMtx [][]float64, idx int) [][]float64 {
- var ret [][]float64
- for i := range sqMtx {
- if i == 0 {
- continue
- }
- var row []float64
- for j := range sqMtx {
- if j == idx {
- continue
- }
- row = append(row, sqMtx[i][j])
- }
- ret = append(ret, row)
- }
- return ret
- }
- // det determinant of the 2x2 matrix.
- func det(sqMtx [][]float64) float64 {
- if len(sqMtx) == 2 {
- m00 := sqMtx[0][0]
- m01 := sqMtx[0][1]
- m10 := sqMtx[1][0]
- m11 := sqMtx[1][1]
- return m00*m11 - m10*m01
- }
- var res, sgn float64 = 0, 1
- for j := range sqMtx {
- res += sgn * sqMtx[0][j] * det(minor(sqMtx, j))
- sgn *= -1
- }
- return res
- }
- // newNumberMatrix converts a formula arguments matrix to a number matrix.
- func newNumberMatrix(arg formulaArg, phalanx bool) (numMtx [][]float64, ele formulaArg) {
- rows := len(arg.Matrix)
- for r, row := range arg.Matrix {
- if phalanx && len(row) != rows {
- ele = newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- return
- }
- numMtx = append(numMtx, make([]float64, len(row)))
- for c, cell := range row {
- if cell.Type != ArgNumber {
- ele = newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- return
- }
- numMtx[r][c] = cell.Number
- }
- }
- return
- }
- // newFormulaArgMatrix converts the number formula arguments matrix to a
- // formula arguments matrix.
- func newFormulaArgMatrix(numMtx [][]float64) (arg [][]formulaArg) {
- for r, row := range numMtx {
- arg = append(arg, make([]formulaArg, len(row)))
- for c, cell := range row {
- arg[r][c] = newNumberFormulaArg(cell)
- }
- }
- return
- }
- // MDETERM calculates the determinant of a square matrix. The
- // syntax of the function is:
- //
- // MDETERM(array)
- func (fn *formulaFuncs) MDETERM(argsList *list.List) (result formulaArg) {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "MDETERM requires 1 argument")
- }
- numMtx, errArg := newNumberMatrix(argsList.Front().Value.(formulaArg), true)
- if errArg.Type == ArgError {
- return errArg
- }
- return newNumberFormulaArg(det(numMtx))
- }
- // cofactorMatrix returns the matrix A of cofactors.
- func cofactorMatrix(i, j int, A [][]float64) float64 {
- N, sign := len(A), -1.0
- if (i+j)%2 == 0 {
- sign = 1
- }
- var B [][]float64
- B = append(B, A...)
- for m := 0; m < N; m++ {
- for n := j + 1; n < N; n++ {
- B[m][n-1] = B[m][n]
- }
- B[m] = B[m][:len(B[m])-1]
- }
- for k := i + 1; k < N; k++ {
- B[k-1] = B[k]
- }
- B = B[:len(B)-1]
- return sign * det(B)
- }
- // adjugateMatrix returns transpose of the cofactor matrix A with Cramer's
- // rule.
- func adjugateMatrix(A [][]float64) (adjA [][]float64) {
- N := len(A)
- var B [][]float64
- for i := 0; i < N; i++ {
- adjA = append(adjA, make([]float64, N))
- for j := 0; j < N; j++ {
- for m := 0; m < N; m++ {
- for n := 0; n < N; n++ {
- for x := len(B); x <= m; x++ {
- B = append(B, []float64{})
- }
- for k := len(B[m]); k <= n; k++ {
- B[m] = append(B[m], 0)
- }
- B[m][n] = A[m][n]
- }
- }
- adjA[i][j] = cofactorMatrix(j, i, B)
- }
- }
- return
- }
- // MINVERSE function calculates the inverse of a square matrix. The syntax of
- // the function is:
- //
- // MINVERSE(array)
- func (fn *formulaFuncs) MINVERSE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "MINVERSE requires 1 argument")
- }
- numMtx, errArg := newNumberMatrix(argsList.Front().Value.(formulaArg), true)
- if errArg.Type == ArgError {
- return errArg
- }
- if detM := det(numMtx); detM != 0 {
- datM, invertM := 1/detM, adjugateMatrix(numMtx)
- for i := 0; i < len(invertM); i++ {
- for j := 0; j < len(invertM[i]); j++ {
- invertM[i][j] *= datM
- }
- }
- return newMatrixFormulaArg(newFormulaArgMatrix(invertM))
- }
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- // MMULT function calculates the matrix product of two arrays
- // (representing matrices). The syntax of the function is:
- //
- // MMULT(array1,array2)
- func (fn *formulaFuncs) MMULT(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "MMULT requires 2 argument")
- }
- numMtx1, errArg1 := newNumberMatrix(argsList.Front().Value.(formulaArg), false)
- if errArg1.Type == ArgError {
- return errArg1
- }
- numMtx2, errArg2 := newNumberMatrix(argsList.Back().Value.(formulaArg), false)
- if errArg2.Type == ArgError {
- return errArg2
- }
- array2Rows, array2Cols := len(numMtx2), len(numMtx2[0])
- if len(numMtx1[0]) != array2Rows {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- var numMtx [][]float64
- var row1, row []float64
- var sum float64
- for i := 0; i < len(numMtx1); i++ {
- numMtx = append(numMtx, []float64{})
- row = []float64{}
- row1 = numMtx1[i]
- for j := 0; j < array2Cols; j++ {
- sum = 0
- for k := 0; k < array2Rows; k++ {
- sum += row1[k] * numMtx2[k][j]
- }
- for l := len(row); l <= j; l++ {
- row = append(row, 0)
- }
- row[j] = sum
- numMtx[i] = row
- }
- }
- return newMatrixFormulaArg(newFormulaArgMatrix(numMtx))
- }
- // MOD function returns the remainder of a division between two supplied
- // numbers. The syntax of the function is:
- //
- // MOD(number,divisor)
- func (fn *formulaFuncs) MOD(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "MOD requires 2 numeric arguments")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- divisor := argsList.Back().Value.(formulaArg).ToNumber()
- if divisor.Type == ArgError {
- return divisor
- }
- if divisor.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, "MOD divide by zero")
- }
- trunc, rem := math.Modf(number.Number / divisor.Number)
- if rem < 0 {
- trunc--
- }
- return newNumberFormulaArg(number.Number - divisor.Number*trunc)
- }
- // MROUND function rounds a supplied number up or down to the nearest multiple
- // of a given number. The syntax of the function is:
- //
- // MROUND(number,multiple)
- func (fn *formulaFuncs) MROUND(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "MROUND requires 2 numeric arguments")
- }
- n := argsList.Front().Value.(formulaArg).ToNumber()
- if n.Type == ArgError {
- return n
- }
- multiple := argsList.Back().Value.(formulaArg).ToNumber()
- if multiple.Type == ArgError {
- return multiple
- }
- if multiple.Number == 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if multiple.Number < 0 && n.Number > 0 ||
- multiple.Number > 0 && n.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- number, res := math.Modf(n.Number / multiple.Number)
- if math.Trunc(res+0.5) > 0 {
- number++
- }
- return newNumberFormulaArg(number * multiple.Number)
- }
- // MULTINOMIAL function calculates the ratio of the factorial of a sum of
- // supplied values to the product of factorials of those values. The syntax of
- // the function is:
- //
- // MULTINOMIAL(number1,[number2],...)
- func (fn *formulaFuncs) MULTINOMIAL(argsList *list.List) formulaArg {
- val, num, denom := 0.0, 0.0, 1.0
- var err error
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgString:
- if token.String == "" {
- continue
- }
- if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- case ArgNumber:
- val = token.Number
- }
- num += val
- denom *= fact(val)
- }
- return newNumberFormulaArg(fact(num) / denom)
- }
- // MUNIT function returns the unit matrix for a specified dimension. The
- // syntax of the function is:
- //
- // MUNIT(dimension)
- func (fn *formulaFuncs) MUNIT(argsList *list.List) (result formulaArg) {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "MUNIT requires 1 numeric argument")
- }
- dimension := argsList.Back().Value.(formulaArg).ToNumber()
- if dimension.Type == ArgError || dimension.Number < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, dimension.Error)
- }
- matrix := make([][]formulaArg, 0, int(dimension.Number))
- for i := 0; i < int(dimension.Number); i++ {
- row := make([]formulaArg, int(dimension.Number))
- for j := 0; j < int(dimension.Number); j++ {
- if i == j {
- row[j] = newNumberFormulaArg(1.0)
- } else {
- row[j] = newNumberFormulaArg(0.0)
- }
- }
- matrix = append(matrix, row)
- }
- return newMatrixFormulaArg(matrix)
- }
- // ODD function ounds a supplied number away from zero (i.e. rounds a positive
- // number up and a negative number down), to the next odd number. The syntax
- // of the function is:
- //
- // ODD(number)
- func (fn *formulaFuncs) ODD(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ODD requires 1 numeric argument")
- }
- number := argsList.Back().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- if number.Number == 0 {
- return newNumberFormulaArg(1)
- }
- sign := math.Signbit(number.Number)
- m, frac := math.Modf((number.Number - 1) / 2)
- val := m*2 + 1
- if frac != 0 {
- if !sign {
- val += 2
- } else {
- val -= 2
- }
- }
- return newNumberFormulaArg(val)
- }
- // PI function returns the value of the mathematical constant π (pi), accurate
- // to 15 digits (14 decimal places). The syntax of the function is:
- //
- // PI()
- func (fn *formulaFuncs) PI(argsList *list.List) formulaArg {
- if argsList.Len() != 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "PI accepts no arguments")
- }
- return newNumberFormulaArg(math.Pi)
- }
- // POWER function calculates a given number, raised to a supplied power.
- // The syntax of the function is:
- //
- // POWER(number,power)
- func (fn *formulaFuncs) POWER(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "POWER requires 2 numeric arguments")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type == ArgError {
- return x
- }
- y := argsList.Back().Value.(formulaArg).ToNumber()
- if y.Type == ArgError {
- return y
- }
- if x.Number == 0 && y.Number == 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if x.Number == 0 && y.Number < 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(math.Pow(x.Number, y.Number))
- }
- // PRODUCT function returns the product (multiplication) of a supplied set of
- // numerical values. The syntax of the function is:
- //
- // PRODUCT(number1,[number2],...)
- func (fn *formulaFuncs) PRODUCT(argsList *list.List) formulaArg {
- product := 1.0
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgString:
- num := token.ToNumber()
- if num.Type != ArgNumber {
- return num
- }
- product = product * num.Number
- case ArgNumber:
- product = product * token.Number
- case ArgMatrix:
- for _, row := range token.Matrix {
- for _, cell := range row {
- if cell.Type == ArgNumber {
- product *= cell.Number
- }
- }
- }
- }
- }
- return newNumberFormulaArg(product)
- }
- // QUOTIENT function returns the integer portion of a division between two
- // supplied numbers. The syntax of the function is:
- //
- // QUOTIENT(numerator,denominator)
- func (fn *formulaFuncs) QUOTIENT(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "QUOTIENT requires 2 numeric arguments")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type == ArgError {
- return x
- }
- y := argsList.Back().Value.(formulaArg).ToNumber()
- if y.Type == ArgError {
- return y
- }
- if y.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(math.Trunc(x.Number / y.Number))
- }
- // RADIANS function converts radians into degrees. The syntax of the function is:
- //
- // RADIANS(angle)
- func (fn *formulaFuncs) RADIANS(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "RADIANS requires 1 numeric argument")
- }
- angle := argsList.Front().Value.(formulaArg).ToNumber()
- if angle.Type == ArgError {
- return angle
- }
- return newNumberFormulaArg(math.Pi / 180.0 * angle.Number)
- }
- // RAND function generates a random real number between 0 and 1. The syntax of
- // the function is:
- //
- // RAND()
- func (fn *formulaFuncs) RAND(argsList *list.List) formulaArg {
- if argsList.Len() != 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "RAND accepts no arguments")
- }
- return newNumberFormulaArg(rand.New(rand.NewSource(time.Now().UnixNano())).Float64())
- }
- // RANDBETWEEN function generates a random integer between two supplied
- // integers. The syntax of the function is:
- //
- // RANDBETWEEN(bottom,top)
- func (fn *formulaFuncs) RANDBETWEEN(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "RANDBETWEEN requires 2 numeric arguments")
- }
- bottom := argsList.Front().Value.(formulaArg).ToNumber()
- if bottom.Type == ArgError {
- return bottom
- }
- top := argsList.Back().Value.(formulaArg).ToNumber()
- if top.Type == ArgError {
- return top
- }
- if top.Number < bottom.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- num := rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(int64(top.Number - bottom.Number + 1))
- return newNumberFormulaArg(float64(num + int64(bottom.Number)))
- }
- // romanNumerals defined a numeral system that originated in ancient Rome and
- // remained the usual way of writing numbers throughout Europe well into the
- // Late Middle Ages.
- type romanNumerals struct {
- n float64
- s string
- }
- var romanTable = [][]romanNumerals{
- {
- {1000, "M"},
- {900, "CM"},
- {500, "D"},
- {400, "CD"},
- {100, "C"},
- {90, "XC"},
- {50, "L"},
- {40, "XL"},
- {10, "X"},
- {9, "IX"},
- {5, "V"},
- {4, "IV"},
- {1, "I"},
- },
- {
- {1000, "M"},
- {950, "LM"},
- {900, "CM"},
- {500, "D"},
- {450, "LD"},
- {400, "CD"},
- {100, "C"},
- {95, "VC"},
- {90, "XC"},
- {50, "L"},
- {45, "VL"},
- {40, "XL"},
- {10, "X"},
- {9, "IX"},
- {5, "V"},
- {4, "IV"},
- {1, "I"},
- },
- {
- {1000, "M"},
- {990, "XM"},
- {950, "LM"},
- {900, "CM"},
- {500, "D"},
- {490, "XD"},
- {450, "LD"},
- {400, "CD"},
- {100, "C"},
- {99, "IC"},
- {90, "XC"},
- {50, "L"},
- {45, "VL"},
- {40, "XL"},
- {10, "X"},
- {9, "IX"},
- {5, "V"},
- {4, "IV"},
- {1, "I"},
- },
- {
- {1000, "M"},
- {995, "VM"},
- {990, "XM"},
- {950, "LM"},
- {900, "CM"},
- {500, "D"},
- {495, "VD"},
- {490, "XD"},
- {450, "LD"},
- {400, "CD"},
- {100, "C"},
- {99, "IC"},
- {90, "XC"},
- {50, "L"},
- {45, "VL"},
- {40, "XL"},
- {10, "X"},
- {9, "IX"},
- {5, "V"},
- {4, "IV"},
- {1, "I"},
- },
- {
- {1000, "M"},
- {999, "IM"},
- {995, "VM"},
- {990, "XM"},
- {950, "LM"},
- {900, "CM"},
- {500, "D"},
- {499, "ID"},
- {495, "VD"},
- {490, "XD"},
- {450, "LD"},
- {400, "CD"},
- {100, "C"},
- {99, "IC"},
- {90, "XC"},
- {50, "L"},
- {45, "VL"},
- {40, "XL"},
- {10, "X"},
- {9, "IX"},
- {5, "V"},
- {4, "IV"},
- {1, "I"},
- },
- }
- // ROMAN function converts an arabic number to Roman. I.e. for a supplied
- // integer, the function returns a text string depicting the roman numeral
- // form of the number. The syntax of the function is:
- //
- // ROMAN(number,[form])
- func (fn *formulaFuncs) ROMAN(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "ROMAN requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "ROMAN allows at most 2 arguments")
- }
- var form int
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- if argsList.Len() > 1 {
- f := argsList.Back().Value.(formulaArg).ToNumber()
- if f.Type == ArgError {
- return f
- }
- form = int(f.Number)
- if form < 0 {
- form = 0
- } else if form > 4 {
- form = 4
- }
- }
- decimalTable := romanTable[0]
- switch form {
- case 1:
- decimalTable = romanTable[1]
- case 2:
- decimalTable = romanTable[2]
- case 3:
- decimalTable = romanTable[3]
- case 4:
- decimalTable = romanTable[4]
- }
- val := math.Trunc(number.Number)
- buf := bytes.Buffer{}
- for _, r := range decimalTable {
- for val >= r.n {
- buf.WriteString(r.s)
- val -= r.n
- }
- }
- return newStringFormulaArg(buf.String())
- }
- type roundMode byte
- const (
- closest roundMode = iota
- down
- up
- )
- // round rounds a supplied number up or down.
- func (fn *formulaFuncs) round(number, digits float64, mode roundMode) float64 {
- var significance float64
- if digits > 0 {
- significance = math.Pow(1/10.0, digits)
- } else {
- significance = math.Pow(10.0, -digits)
- }
- val, res := math.Modf(number / significance)
- switch mode {
- case closest:
- const eps = 0.499999999
- if res >= eps {
- val++
- } else if res <= -eps {
- val--
- }
- case down:
- case up:
- if res > 0 {
- val++
- } else if res < 0 {
- val--
- }
- }
- return val * significance
- }
- // ROUND function rounds a supplied number up or down, to a specified number
- // of decimal places. The syntax of the function is:
- //
- // ROUND(number,num_digits)
- func (fn *formulaFuncs) ROUND(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "ROUND requires 2 numeric arguments")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- digits := argsList.Back().Value.(formulaArg).ToNumber()
- if digits.Type == ArgError {
- return digits
- }
- return newNumberFormulaArg(fn.round(number.Number, digits.Number, closest))
- }
- // ROUNDDOWN function rounds a supplied number down towards zero, to a
- // specified number of decimal places. The syntax of the function is:
- //
- // ROUNDDOWN(number,num_digits)
- func (fn *formulaFuncs) ROUNDDOWN(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "ROUNDDOWN requires 2 numeric arguments")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- digits := argsList.Back().Value.(formulaArg).ToNumber()
- if digits.Type == ArgError {
- return digits
- }
- return newNumberFormulaArg(fn.round(number.Number, digits.Number, down))
- }
- // ROUNDUP function rounds a supplied number up, away from zero, to a
- // specified number of decimal places. The syntax of the function is:
- //
- // ROUNDUP(number,num_digits)
- func (fn *formulaFuncs) ROUNDUP(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "ROUNDUP requires 2 numeric arguments")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- digits := argsList.Back().Value.(formulaArg).ToNumber()
- if digits.Type == ArgError {
- return digits
- }
- return newNumberFormulaArg(fn.round(number.Number, digits.Number, up))
- }
- // SEC function calculates the secant of a given angle. The syntax of the
- // function is:
- //
- // SEC(number)
- func (fn *formulaFuncs) SEC(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SEC requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newNumberFormulaArg(math.Cos(number.Number))
- }
- // SECH function calculates the hyperbolic secant (sech) of a supplied angle.
- // The syntax of the function is:
- //
- // SECH(number)
- func (fn *formulaFuncs) SECH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SECH requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newNumberFormulaArg(1 / math.Cosh(number.Number))
- }
- // SERIESSUM function returns the sum of a power series. The syntax of the
- // function is:
- //
- // SERIESSUM(x,n,m,coefficients)
- func (fn *formulaFuncs) SERIESSUM(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "SERIESSUM requires 4 arguments")
- }
- var x, n, m formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if n = argsList.Front().Next().Value.(formulaArg).ToNumber(); n.Type != ArgNumber {
- return n
- }
- if m = argsList.Front().Next().Next().Value.(formulaArg).ToNumber(); m.Type != ArgNumber {
- return m
- }
- var result, i float64
- for _, coefficient := range argsList.Back().Value.(formulaArg).ToList() {
- if coefficient.Value() == "" {
- continue
- }
- num := coefficient.ToNumber()
- if num.Type != ArgNumber {
- return num
- }
- result += num.Number * math.Pow(x.Number, n.Number+(m.Number*i))
- i++
- }
- return newNumberFormulaArg(result)
- }
- // SIGN function returns the arithmetic sign (+1, -1 or 0) of a supplied
- // number. I.e. if the number is positive, the Sign function returns +1, if
- // the number is negative, the function returns -1 and if the number is 0
- // (zero), the function returns 0. The syntax of the function is:
- //
- // SIGN(number)
- func (fn *formulaFuncs) SIGN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SIGN requires 1 numeric argument")
- }
- val := argsList.Front().Value.(formulaArg).ToNumber()
- if val.Type == ArgError {
- return val
- }
- if val.Number < 0 {
- return newNumberFormulaArg(-1)
- }
- if val.Number > 0 {
- return newNumberFormulaArg(1)
- }
- return newNumberFormulaArg(0)
- }
- // SIN function calculates the sine of a given angle. The syntax of the
- // function is:
- //
- // SIN(number)
- func (fn *formulaFuncs) SIN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SIN requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newNumberFormulaArg(math.Sin(number.Number))
- }
- // SINH function calculates the hyperbolic sine (sinh) of a supplied number.
- // The syntax of the function is:
- //
- // SINH(number)
- func (fn *formulaFuncs) SINH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SINH requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newNumberFormulaArg(math.Sinh(number.Number))
- }
- // SQRT function calculates the positive square root of a supplied number. The
- // syntax of the function is:
- //
- // SQRT(number)
- func (fn *formulaFuncs) SQRT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SQRT requires 1 numeric argument")
- }
- value := argsList.Front().Value.(formulaArg).ToNumber()
- if value.Type == ArgError {
- return value
- }
- if value.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(math.Sqrt(value.Number))
- }
- // SQRTPI function returns the square root of a supplied number multiplied by
- // the mathematical constant, π. The syntax of the function is:
- //
- // SQRTPI(number)
- func (fn *formulaFuncs) SQRTPI(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SQRTPI requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newNumberFormulaArg(math.Sqrt(number.Number * math.Pi))
- }
- // STDEV function calculates the sample standard deviation of a supplied set
- // of values. The syntax of the function is:
- //
- // STDEV(number1,[number2],...)
- func (fn *formulaFuncs) STDEV(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "STDEV requires at least 1 argument")
- }
- return fn.stdev(false, argsList)
- }
- // STDEVdotS function calculates the sample standard deviation of a supplied
- // set of values. The syntax of the function is:
- //
- // STDEV.S(number1,[number2],...)
- func (fn *formulaFuncs) STDEVdotS(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "STDEV.S requires at least 1 argument")
- }
- return fn.stdev(false, argsList)
- }
- // STDEVA function estimates standard deviation based on a sample. The
- // standard deviation is a measure of how widely values are dispersed from
- // the average value (the mean). The syntax of the function is:
- //
- // STDEVA(number1,[number2],...)
- func (fn *formulaFuncs) STDEVA(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "STDEVA requires at least 1 argument")
- }
- return fn.stdev(true, argsList)
- }
- // calcStdevPow is part of the implementation stdev.
- func calcStdevPow(result, count float64, n, m formulaArg) (float64, float64) {
- if result == -1 {
- result = math.Pow(n.Number-m.Number, 2)
- } else {
- result += math.Pow(n.Number-m.Number, 2)
- }
- count++
- return result, count
- }
- // calcStdev is part of the implementation stdev.
- func calcStdev(stdeva bool, result, count float64, mean, token formulaArg) (float64, float64) {
- for _, row := range token.ToList() {
- if row.Type == ArgNumber || row.Type == ArgString {
- if !stdeva && (row.Value() == "TRUE" || row.Value() == "FALSE") {
- continue
- } else if stdeva && (row.Value() == "TRUE" || row.Value() == "FALSE") {
- num := row.ToBool()
- if num.Type == ArgNumber {
- result, count = calcStdevPow(result, count, num, mean)
- continue
- }
- } else {
- num := row.ToNumber()
- if num.Type == ArgNumber {
- result, count = calcStdevPow(result, count, num, mean)
- }
- }
- }
- }
- return result, count
- }
- // stdev is an implementation of the formula functions STDEV and STDEVA.
- func (fn *formulaFuncs) stdev(stdeva bool, argsList *list.List) formulaArg {
- count, result := -1.0, -1.0
- var mean formulaArg
- if stdeva {
- mean = fn.AVERAGEA(argsList)
- } else {
- mean = fn.AVERAGE(argsList)
- }
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgString, ArgNumber:
- if !stdeva && (token.Value() == "TRUE" || token.Value() == "FALSE") {
- continue
- } else if stdeva && (token.Value() == "TRUE" || token.Value() == "FALSE") {
- num := token.ToBool()
- if num.Type == ArgNumber {
- result, count = calcStdevPow(result, count, num, mean)
- continue
- }
- } else {
- num := token.ToNumber()
- if num.Type == ArgNumber {
- result, count = calcStdevPow(result, count, num, mean)
- }
- }
- case ArgList, ArgMatrix:
- result, count = calcStdev(stdeva, result, count, mean, token)
- }
- }
- if count > 0 && result >= 0 {
- return newNumberFormulaArg(math.Sqrt(result / count))
- }
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- // POISSONdotDIST function calculates the Poisson Probability Mass Function or
- // the Cumulative Poisson Probability Function for a supplied set of
- // parameters. The syntax of the function is:
- //
- // POISSON.DIST(x,mean,cumulative)
- func (fn *formulaFuncs) POISSONdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "POISSON.DIST requires 3 arguments")
- }
- return fn.POISSON(argsList)
- }
- // POISSON function calculates the Poisson Probability Mass Function or the
- // Cumulative Poisson Probability Function for a supplied set of parameters.
- // The syntax of the function is:
- //
- // POISSON(x,mean,cumulative)
- func (fn *formulaFuncs) POISSON(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "POISSON requires 3 arguments")
- }
- var x, mean, cumulative formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if mean = argsList.Front().Next().Value.(formulaArg).ToNumber(); mean.Type != ArgNumber {
- return mean
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError {
- return cumulative
- }
- if x.Number < 0 || mean.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if cumulative.Number == 1 {
- summer := 0.0
- floor := math.Floor(x.Number)
- for i := 0; i <= int(floor); i++ {
- summer += math.Pow(mean.Number, float64(i)) / fact(float64(i))
- }
- return newNumberFormulaArg(math.Exp(0-mean.Number) * summer)
- }
- return newNumberFormulaArg(math.Exp(0-mean.Number) * math.Pow(mean.Number, x.Number) / fact(x.Number))
- }
- // SUBTOTAL function performs a specified calculation (e.g. the sum, product,
- // average, etc.) for a supplied set of values. The syntax of the function is:
- //
- // SUBTOTAL(function_num,ref1,[ref2],...)
- func (fn *formulaFuncs) SUBTOTAL(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "SUBTOTAL requires at least 2 arguments")
- }
- var fnNum formulaArg
- if fnNum = argsList.Front().Value.(formulaArg).ToNumber(); fnNum.Type != ArgNumber {
- return fnNum
- }
- subFn, ok := map[int]func(argsList *list.List) formulaArg{
- 1: fn.AVERAGE, 101: fn.AVERAGE,
- 2: fn.COUNT, 102: fn.COUNT,
- 3: fn.COUNTA, 103: fn.COUNTA,
- 4: fn.MAX, 104: fn.MAX,
- 5: fn.MIN, 105: fn.MIN,
- 6: fn.PRODUCT, 106: fn.PRODUCT,
- 7: fn.STDEV, 107: fn.STDEV,
- 8: fn.STDEVP, 108: fn.STDEVP,
- 9: fn.SUM, 109: fn.SUM,
- 10: fn.VAR, 110: fn.VAR,
- 11: fn.VARP, 111: fn.VARP,
- }[int(fnNum.Number)]
- if !ok {
- return newErrorFormulaArg(formulaErrorVALUE, "SUBTOTAL has invalid function_num")
- }
- subArgList := list.New().Init()
- for arg := argsList.Front().Next(); arg != nil; arg = arg.Next() {
- subArgList.PushBack(arg.Value.(formulaArg))
- }
- return subFn(subArgList)
- }
- // SUM function adds together a supplied set of numbers and returns the sum of
- // these values. The syntax of the function is:
- //
- // SUM(number1,[number2],...)
- func (fn *formulaFuncs) SUM(argsList *list.List) formulaArg {
- var sum float64
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgError:
- return token
- case ArgString:
- if num := token.ToNumber(); num.Type == ArgNumber {
- sum += num.Number
- }
- case ArgNumber:
- sum += token.Number
- case ArgMatrix:
- for _, row := range token.Matrix {
- for _, value := range row {
- if num := value.ToNumber(); num.Type == ArgNumber {
- sum += num.Number
- }
- }
- }
- }
- }
- return newNumberFormulaArg(sum)
- }
- // SUMIF function finds the values in a supplied array, that satisfy a given
- // criteria, and returns the sum of the corresponding values in a second
- // supplied array. The syntax of the function is:
- //
- // SUMIF(range,criteria,[sum_range])
- func (fn *formulaFuncs) SUMIF(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "SUMIF requires at least 2 arguments")
- }
- criteria := formulaCriteriaParser(argsList.Front().Next().Value.(formulaArg).String)
- rangeMtx := argsList.Front().Value.(formulaArg).Matrix
- var sumRange [][]formulaArg
- if argsList.Len() == 3 {
- sumRange = argsList.Back().Value.(formulaArg).Matrix
- }
- var sum float64
- var arg formulaArg
- for rowIdx, row := range rangeMtx {
- for colIdx, cell := range row {
- arg = cell
- if arg.Type == ArgEmpty {
- continue
- }
- if ok, _ := formulaCriteriaEval(arg.Value(), criteria); ok {
- if argsList.Len() == 3 {
- if len(sumRange) > rowIdx && len(sumRange[rowIdx]) > colIdx {
- arg = sumRange[rowIdx][colIdx]
- }
- }
- if arg.Type == ArgNumber {
- sum += arg.Number
- }
- }
- }
- }
- return newNumberFormulaArg(sum)
- }
- // SUMIFS function finds values in one or more supplied arrays, that satisfy a
- // set of criteria, and returns the sum of the corresponding values in a
- // further supplied array. The syntax of the function is:
- //
- // SUMIFS(sum_range,criteria_range1,criteria1,[criteria_range2,criteria2],...)
- func (fn *formulaFuncs) SUMIFS(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "SUMIFS requires at least 3 arguments")
- }
- if argsList.Len()%2 != 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var args []formulaArg
- sum, sumRange := 0.0, argsList.Front().Value.(formulaArg).Matrix
- for arg := argsList.Front().Next(); arg != nil; arg = arg.Next() {
- args = append(args, arg.Value.(formulaArg))
- }
- for _, ref := range formulaIfsMatch(args) {
- if ref.Row >= len(sumRange) || ref.Col >= len(sumRange[ref.Row]) {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if num := sumRange[ref.Row][ref.Col].ToNumber(); num.Type == ArgNumber {
- sum += num.Number
- }
- }
- return newNumberFormulaArg(sum)
- }
- // sumproduct is an implementation of the formula function SUMPRODUCT.
- func (fn *formulaFuncs) sumproduct(argsList *list.List) formulaArg {
- var (
- argType ArgType
- n int
- res []float64
- sum float64
- )
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- if argType == ArgUnknown {
- argType = token.Type
- }
- if token.Type != argType {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- switch token.Type {
- case ArgString, ArgNumber:
- if num := token.ToNumber(); num.Type == ArgNumber {
- sum = fn.PRODUCT(argsList).Number
- continue
- }
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- case ArgMatrix:
- args := token.ToList()
- if res == nil {
- n = len(args)
- res = make([]float64, n)
- for i := range res {
- res[i] = 1.0
- }
- }
- if len(args) != n {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- for i, value := range args {
- num := value.ToNumber()
- if num.Type != ArgNumber && value.Value() != "" {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- res[i] = res[i] * num.Number
- }
- }
- }
- for _, r := range res {
- sum += r
- }
- return newNumberFormulaArg(sum)
- }
- // SUMPRODUCT function returns the sum of the products of the corresponding
- // values in a set of supplied arrays. The syntax of the function is:
- //
- // SUMPRODUCT(array1,[array2],[array3],...)
- func (fn *formulaFuncs) SUMPRODUCT(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SUMPRODUCT requires at least 1 argument")
- }
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- if token := arg.Value.(formulaArg); token.Type == ArgError {
- return token
- }
- }
- return fn.sumproduct(argsList)
- }
- // SUMSQ function returns the sum of squares of a supplied set of values. The
- // syntax of the function is:
- //
- // SUMSQ(number1,[number2],...)
- func (fn *formulaFuncs) SUMSQ(argsList *list.List) formulaArg {
- var val, sq float64
- var err error
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgString:
- if token.String == "" {
- continue
- }
- if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- sq += val * val
- case ArgNumber:
- sq += token.Number * token.Number
- case ArgMatrix:
- for _, row := range token.Matrix {
- for _, value := range row {
- if value.Value() == "" {
- continue
- }
- if val, err = strconv.ParseFloat(value.Value(), 64); err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- sq += val * val
- }
- }
- }
- }
- return newNumberFormulaArg(sq)
- }
- // sumx is an implementation of the formula functions SUMX2MY2, SUMX2PY2 and
- // SUMXMY2.
- func (fn *formulaFuncs) sumx(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name))
- }
- array1 := argsList.Front().Value.(formulaArg)
- array2 := argsList.Back().Value.(formulaArg)
- left, right := array1.ToList(), array2.ToList()
- n := len(left)
- if n != len(right) {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- result := 0.0
- for i := 0; i < n; i++ {
- if lhs, rhs := left[i].ToNumber(), right[i].ToNumber(); lhs.Number != 0 && rhs.Number != 0 {
- switch name {
- case "SUMX2MY2":
- result += lhs.Number*lhs.Number - rhs.Number*rhs.Number
- case "SUMX2PY2":
- result += lhs.Number*lhs.Number + rhs.Number*rhs.Number
- default:
- result += (lhs.Number - rhs.Number) * (lhs.Number - rhs.Number)
- }
- }
- }
- return newNumberFormulaArg(result)
- }
- // SUMX2MY2 function returns the sum of the differences of squares of two
- // supplied sets of values. The syntax of the function is:
- //
- // SUMX2MY2(array_x,array_y)
- func (fn *formulaFuncs) SUMX2MY2(argsList *list.List) formulaArg {
- return fn.sumx("SUMX2MY2", argsList)
- }
- // SUMX2PY2 function returns the sum of the sum of squares of two supplied sets
- // of values. The syntax of the function is:
- //
- // SUMX2PY2(array_x,array_y)
- func (fn *formulaFuncs) SUMX2PY2(argsList *list.List) formulaArg {
- return fn.sumx("SUMX2PY2", argsList)
- }
- // SUMXMY2 function returns the sum of the squares of differences between
- // corresponding values in two supplied arrays. The syntax of the function
- // is:
- //
- // SUMXMY2(array_x,array_y)
- func (fn *formulaFuncs) SUMXMY2(argsList *list.List) formulaArg {
- return fn.sumx("SUMXMY2", argsList)
- }
- // TAN function calculates the tangent of a given angle. The syntax of the
- // function is:
- //
- // TAN(number)
- func (fn *formulaFuncs) TAN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "TAN requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newNumberFormulaArg(math.Tan(number.Number))
- }
- // TANH function calculates the hyperbolic tangent (tanh) of a supplied
- // number. The syntax of the function is:
- //
- // TANH(number)
- func (fn *formulaFuncs) TANH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "TANH requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- return newNumberFormulaArg(math.Tanh(number.Number))
- }
- // TRUNC function truncates a supplied number to a specified number of decimal
- // places. The syntax of the function is:
- //
- // TRUNC(number,[number_digits])
- func (fn *formulaFuncs) TRUNC(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "TRUNC requires at least 1 argument")
- }
- var digits, adjust, rtrim float64
- var err error
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type == ArgError {
- return number
- }
- if argsList.Len() > 1 {
- d := argsList.Back().Value.(formulaArg).ToNumber()
- if d.Type == ArgError {
- return d
- }
- digits = d.Number
- digits = math.Floor(digits)
- }
- adjust = math.Pow(10, digits)
- x := int((math.Abs(number.Number) - math.Abs(float64(int(number.Number)))) * adjust)
- if x != 0 {
- if rtrim, err = strconv.ParseFloat(strings.TrimRight(strconv.Itoa(x), "0"), 64); err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- }
- if (digits > 0) && (rtrim < adjust/10) {
- return newNumberFormulaArg(number.Number)
- }
- return newNumberFormulaArg(float64(int(number.Number*adjust)) / adjust)
- }
- // Statistical Functions
- // AVEDEV function calculates the average deviation of a supplied set of
- // values. The syntax of the function is:
- //
- // AVEDEV(number1,[number2],...)
- func (fn *formulaFuncs) AVEDEV(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "AVEDEV requires at least 1 argument")
- }
- average := fn.AVERAGE(argsList)
- if average.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- result, count := 0.0, 0.0
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- num := arg.Value.(formulaArg).ToNumber()
- if num.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- result += math.Abs(num.Number - average.Number)
- count++
- }
- return newNumberFormulaArg(result / count)
- }
- // AVERAGE function returns the arithmetic mean of a list of supplied numbers.
- // The syntax of the function is:
- //
- // AVERAGE(number1,[number2],...)
- func (fn *formulaFuncs) AVERAGE(argsList *list.List) formulaArg {
- var args []formulaArg
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- args = append(args, arg.Value.(formulaArg))
- }
- count, sum := fn.countSum(false, args)
- if count == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(sum / count)
- }
- // AVERAGEA function returns the arithmetic mean of a list of supplied numbers
- // with text cell and zero values. The syntax of the function is:
- //
- // AVERAGEA(number1,[number2],...)
- func (fn *formulaFuncs) AVERAGEA(argsList *list.List) formulaArg {
- var args []formulaArg
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- args = append(args, arg.Value.(formulaArg))
- }
- count, sum := fn.countSum(true, args)
- if count == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(sum / count)
- }
- // AVERAGEIF function finds the values in a supplied array that satisfy a
- // specified criteria, and returns the average (i.e. the statistical mean) of
- // the corresponding values in a second supplied array. The syntax of the
- // function is:
- //
- // AVERAGEIF(range,criteria,[average_range])
- func (fn *formulaFuncs) AVERAGEIF(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "AVERAGEIF requires at least 2 arguments")
- }
- var (
- criteria = formulaCriteriaParser(argsList.Front().Next().Value.(formulaArg).Value())
- rangeMtx = argsList.Front().Value.(formulaArg).Matrix
- cellRange [][]formulaArg
- args []formulaArg
- val float64
- err error
- ok bool
- )
- if argsList.Len() == 3 {
- cellRange = argsList.Back().Value.(formulaArg).Matrix
- }
- for rowIdx, row := range rangeMtx {
- for colIdx, col := range row {
- fromVal := col.Value()
- if col.Value() == "" {
- continue
- }
- ok, _ = formulaCriteriaEval(fromVal, criteria)
- if ok {
- if argsList.Len() == 3 {
- if len(cellRange) > rowIdx && len(cellRange[rowIdx]) > colIdx {
- fromVal = cellRange[rowIdx][colIdx].Value()
- }
- }
- if val, err = strconv.ParseFloat(fromVal, 64); err != nil {
- continue
- }
- args = append(args, newNumberFormulaArg(val))
- }
- }
- }
- count, sum := fn.countSum(false, args)
- if count == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(sum / count)
- }
- // AVERAGEIFS function finds entries in one or more arrays, that satisfy a set
- // of supplied criteria, and returns the average (i.e. the statistical mean)
- // of the corresponding values in a further supplied array. The syntax of the
- // function is:
- //
- // AVERAGEIFS(average_range,criteria_range1,criteria1,[criteria_range2,criteria2],...)
- func (fn *formulaFuncs) AVERAGEIFS(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "AVERAGEIFS requires at least 3 arguments")
- }
- if argsList.Len()%2 != 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var args []formulaArg
- sum, sumRange := 0.0, argsList.Front().Value.(formulaArg).Matrix
- for arg := argsList.Front().Next(); arg != nil; arg = arg.Next() {
- args = append(args, arg.Value.(formulaArg))
- }
- count := 0.0
- for _, ref := range formulaIfsMatch(args) {
- if num := sumRange[ref.Row][ref.Col].ToNumber(); num.Type == ArgNumber {
- sum += num.Number
- count++
- }
- }
- if count == 0 {
- return newErrorFormulaArg(formulaErrorDIV, "AVERAGEIF divide by zero")
- }
- return newNumberFormulaArg(sum / count)
- }
- // getBetaHelperContFrac continued fractions for the beta function.
- func getBetaHelperContFrac(fX, fA, fB float64) float64 {
- var a1, b1, a2, b2, fnorm, cfnew, cf, rm float64
- a1, b1, b2 = 1, 1, 1-(fA+fB)/(fA+1)*fX
- if b2 == 0 {
- a2, fnorm, cf = 0, 1, 1
- } else {
- a2, fnorm = 1, 1/b2
- cf = a2 * fnorm
- }
- cfnew, rm = 1, 1
- fMaxIter, fMachEps := 50000.0, 2.22045e-016
- bfinished := false
- for rm < fMaxIter && !bfinished {
- apl2m := fA + 2*rm
- d2m := rm * (fB - rm) * fX / ((apl2m - 1) * apl2m)
- d2m1 := -(fA + rm) * (fA + fB + rm) * fX / (apl2m * (apl2m + 1))
- a1 = (a2 + d2m*a1) * fnorm
- b1 = (b2 + d2m*b1) * fnorm
- a2 = a1 + d2m1*a2*fnorm
- b2 = b1 + d2m1*b2*fnorm
- if b2 != 0 {
- fnorm = 1 / b2
- cfnew = a2 * fnorm
- bfinished = math.Abs(cf-cfnew) < math.Abs(cf)*fMachEps
- }
- cf = cfnew
- rm++
- }
- return cf
- }
- // getLanczosSum uses a variant of the Lanczos sum with a rational function.
- func getLanczosSum(fZ float64) float64 {
- num := []float64{
- 23531376880.41075968857200767445163675473,
- 42919803642.64909876895789904700198885093,
- 35711959237.35566804944018545154716670596,
- 17921034426.03720969991975575445893111267,
- 6039542586.35202800506429164430729792107,
- 1439720407.311721673663223072794912393972,
- 248874557.8620541565114603864132294232163,
- 31426415.58540019438061423162831820536287,
- 2876370.628935372441225409051620849613599,
- 186056.2653952234950402949897160456992822,
- 8071.672002365816210638002902272250613822,
- 210.8242777515793458725097339207133627117,
- 2.506628274631000270164908177133837338626,
- }
- denom := []float64{
- 0,
- 39916800,
- 120543840,
- 150917976,
- 105258076,
- 45995730,
- 13339535,
- 2637558,
- 357423,
- 32670,
- 1925,
- 66,
- 1,
- }
- var sumNum, sumDenom, zInv float64
- if fZ <= 1 {
- sumNum = num[12]
- sumDenom = denom[12]
- for i := 11; i >= 0; i-- {
- sumNum *= fZ
- sumNum += num[i]
- sumDenom *= fZ
- sumDenom += denom[i]
- }
- } else {
- zInv = 1 / fZ
- sumNum = num[0]
- sumDenom = denom[0]
- for i := 1; i <= 12; i++ {
- sumNum *= zInv
- sumNum += num[i]
- sumDenom *= zInv
- sumDenom += denom[i]
- }
- }
- return sumNum / sumDenom
- }
- // getBeta return beta distribution.
- func getBeta(fAlpha, fBeta float64) float64 {
- var fA, fB float64
- if fAlpha > fBeta {
- fA = fAlpha
- fB = fBeta
- } else {
- fA = fBeta
- fB = fAlpha
- }
- const maxGammaArgument = 171.624376956302
- if fA+fB < maxGammaArgument {
- return math.Gamma(fA) / math.Gamma(fA+fB) * math.Gamma(fB)
- }
- fg := 6.024680040776729583740234375
- fgm := fg - 0.5
- fLanczos := getLanczosSum(fA)
- fLanczos /= getLanczosSum(fA + fB)
- fLanczos *= getLanczosSum(fB)
- fABgm := fA + fB + fgm
- fLanczos *= math.Sqrt((fABgm / (fA + fgm)) / (fB + fgm))
- fTempA := fB / (fA + fgm)
- fTempB := fA / (fB + fgm)
- fResult := math.Exp(-fA*math.Log1p(fTempA) - fB*math.Log1p(fTempB) - fgm)
- fResult *= fLanczos
- return fResult
- }
- // getBetaDistPDF is an implementation for the Beta probability density
- // function.
- func getBetaDistPDF(fX, fA, fB float64) float64 {
- if fX <= 0 || fX >= 1 {
- return 0
- }
- fLogDblMax, fLogDblMin := math.Log(1.79769e+308), math.Log(2.22507e-308)
- fLogY := math.Log(0.5 - fX + 0.5)
- if fX < 0.1 {
- fLogY = math.Log1p(-fX)
- }
- fLogX := math.Log(fX)
- fAm1LogX := (fA - 1) * fLogX
- fBm1LogY := (fB - 1) * fLogY
- fLogBeta := getLogBeta(fA, fB)
- if fAm1LogX < fLogDblMax && fAm1LogX > fLogDblMin && fBm1LogY < fLogDblMax &&
- fBm1LogY > fLogDblMin && fLogBeta < fLogDblMax && fLogBeta > fLogDblMin &&
- fAm1LogX+fBm1LogY < fLogDblMax && fAm1LogX+fBm1LogY > fLogDblMin {
- return math.Pow(fX, fA-1) * math.Pow(0.5-fX+0.5, fB-1) / getBeta(fA, fB)
- }
- return math.Exp(fAm1LogX + fBm1LogY - fLogBeta)
- }
- // getLogBeta return beta with logarithm.
- func getLogBeta(fAlpha, fBeta float64) float64 {
- var fA, fB float64
- if fAlpha > fBeta {
- fA, fB = fAlpha, fBeta
- } else {
- fA, fB = fBeta, fAlpha
- }
- fg := 6.024680040776729583740234375
- fgm := fg - 0.5
- fLanczos := getLanczosSum(fA)
- fLanczos /= getLanczosSum(fA + fB)
- fLanczos *= getLanczosSum(fB)
- fLogLanczos := math.Log(fLanczos)
- fABgm := fA + fB + fgm
- fLogLanczos += 0.5 * (math.Log(fABgm) - math.Log(fA+fgm) - math.Log(fB+fgm))
- fTempA := fB / (fA + fgm)
- fTempB := fA / (fB + fgm)
- fResult := -fA*math.Log1p(fTempA) - fB*math.Log1p(fTempB) - fgm
- fResult += fLogLanczos
- return fResult
- }
- // getBetaDist is an implementation for the beta distribution function.
- func getBetaDist(fXin, fAlpha, fBeta float64) float64 {
- if fXin <= 0 {
- return 0
- }
- if fXin >= 1 {
- return 1
- }
- if fBeta == 1 {
- return math.Pow(fXin, fAlpha)
- }
- if fAlpha == 1 {
- return -math.Expm1(fBeta * math.Log1p(-fXin))
- }
- var fResult float64
- fY, flnY := (0.5-fXin)+0.5, math.Log1p(-fXin)
- fX, flnX := fXin, math.Log(fXin)
- fA, fB := fAlpha, fBeta
- bReflect := fXin > fAlpha/(fAlpha+fBeta)
- if bReflect {
- fA = fBeta
- fB = fAlpha
- fX = fY
- fY = fXin
- flnX = flnY
- flnY = math.Log(fXin)
- }
- fResult = getBetaHelperContFrac(fX, fA, fB) / fA
- fP, fQ := fA/(fA+fB), fB/(fA+fB)
- var fTemp float64
- if fA > 1 && fB > 1 && fP < 0.97 && fQ < 0.97 {
- fTemp = getBetaDistPDF(fX, fA, fB) * fX * fY
- } else {
- fTemp = math.Exp(fA*flnX + fB*flnY - getLogBeta(fA, fB))
- }
- fResult *= fTemp
- if bReflect {
- fResult = 0.5 - fResult + 0.5
- }
- return fResult
- }
- // prepareBETAdotDISTArgs checking and prepare arguments for the formula
- // function BETA.DIST.
- func (fn *formulaFuncs) prepareBETAdotDISTArgs(argsList *list.List) formulaArg {
- if argsList.Len() < 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "BETA.DIST requires at least 4 arguments")
- }
- if argsList.Len() > 6 {
- return newErrorFormulaArg(formulaErrorVALUE, "BETA.DIST requires at most 6 arguments")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- alpha := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if alpha.Type != ArgNumber {
- return alpha
- }
- beta := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if beta.Type != ArgNumber {
- return beta
- }
- if alpha.Number <= 0 || beta.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- cumulative := argsList.Front().Next().Next().Next().Value.(formulaArg).ToBool()
- if cumulative.Type != ArgNumber {
- return cumulative
- }
- a, b := newNumberFormulaArg(0), newNumberFormulaArg(1)
- if argsList.Len() > 4 {
- if a = argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber(); a.Type != ArgNumber {
- return a
- }
- }
- if argsList.Len() == 6 {
- if b = argsList.Back().Value.(formulaArg).ToNumber(); b.Type != ArgNumber {
- return b
- }
- }
- return newListFormulaArg([]formulaArg{x, alpha, beta, cumulative, a, b})
- }
- // BETAdotDIST function calculates the cumulative beta distribution function
- // or the probability density function of the Beta distribution, for a
- // supplied set of parameters. The syntax of the function is:
- //
- // BETA.DIST(x,alpha,beta,cumulative,[A],[B])
- func (fn *formulaFuncs) BETAdotDIST(argsList *list.List) formulaArg {
- args := fn.prepareBETAdotDISTArgs(argsList)
- if args.Type != ArgList {
- return args
- }
- x, alpha, beta, cumulative, a, b := args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5]
- if x.Number < a.Number || x.Number > b.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if a.Number == b.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- scale := b.Number - a.Number
- x.Number = (x.Number - a.Number) / scale
- if cumulative.Number == 1 {
- return newNumberFormulaArg(getBetaDist(x.Number, alpha.Number, beta.Number))
- }
- return newNumberFormulaArg(getBetaDistPDF(x.Number, alpha.Number, beta.Number) / scale)
- }
- // BETADIST function calculates the cumulative beta probability density
- // function for a supplied set of parameters. The syntax of the function is:
- //
- // BETADIST(x,alpha,beta,[A],[B])
- func (fn *formulaFuncs) BETADIST(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "BETADIST requires at least 3 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "BETADIST requires at most 5 arguments")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- alpha := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if alpha.Type != ArgNumber {
- return alpha
- }
- beta := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if beta.Type != ArgNumber {
- return beta
- }
- if alpha.Number <= 0 || beta.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- a, b := newNumberFormulaArg(0), newNumberFormulaArg(1)
- if argsList.Len() > 3 {
- if a = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); a.Type != ArgNumber {
- return a
- }
- }
- if argsList.Len() == 5 {
- if b = argsList.Back().Value.(formulaArg).ToNumber(); b.Type != ArgNumber {
- return b
- }
- }
- if x.Number < a.Number || x.Number > b.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if a.Number == b.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(getBetaDist((x.Number-a.Number)/(b.Number-a.Number), alpha.Number, beta.Number))
- }
- // d1mach returns double precision real machine constants.
- func d1mach(i int) float64 {
- arr := []float64{
- 2.2250738585072014e-308,
- 1.7976931348623158e+308,
- 1.1102230246251565e-16,
- 2.2204460492503131e-16,
- 0.301029995663981195,
- }
- if i > len(arr) {
- return 0
- }
- return arr[i-1]
- }
- // chebyshevInit determines the number of terms for the double precision
- // orthogonal series "dos" needed to insure the error is no larger
- // than "eta". Ordinarily eta will be chosen to be one-tenth machine
- // precision.
- func chebyshevInit(nos int, eta float64, dos []float64) int {
- i, e := 0, 0.0
- if nos < 1 {
- return 0
- }
- for ii := 1; ii <= nos; ii++ {
- i = nos - ii
- e += math.Abs(dos[i])
- if e > eta {
- return i
- }
- }
- return i
- }
- // chebyshevEval evaluates the n-term Chebyshev series "a" at "x".
- func chebyshevEval(n int, x float64, a []float64) float64 {
- if n < 1 || n > 1000 || x < -1.1 || x > 1.1 {
- return math.NaN()
- }
- twox, b0, b1, b2 := x*2, 0.0, 0.0, 0.0
- for i := 1; i <= n; i++ {
- b2 = b1
- b1 = b0
- b0 = twox*b1 - b2 + a[n-i]
- }
- return (b0 - b2) * 0.5
- }
- // lgammacor is an implementation for the log(gamma) correction.
- func lgammacor(x float64) float64 {
- algmcs := []float64{
- 0.1666389480451863247205729650822, -0.1384948176067563840732986059135e-4,
- 0.9810825646924729426157171547487e-8, -0.1809129475572494194263306266719e-10,
- 0.6221098041892605227126015543416e-13, -0.3399615005417721944303330599666e-15,
- 0.2683181998482698748957538846666e-17, -0.2868042435334643284144622399999e-19,
- 0.3962837061046434803679306666666e-21, -0.6831888753985766870111999999999e-23,
- 0.1429227355942498147573333333333e-24, -0.3547598158101070547199999999999e-26,
- 0.1025680058010470912000000000000e-27, -0.3401102254316748799999999999999e-29,
- 0.1276642195630062933333333333333e-30,
- }
- nalgm := chebyshevInit(15, d1mach(3), algmcs)
- xbig := 1.0 / math.Sqrt(d1mach(3))
- xmax := math.Exp(math.Min(math.Log(d1mach(2)/12.0), -math.Log(12.0*d1mach(1))))
- if x < 10.0 {
- return math.NaN()
- } else if x >= xmax {
- return 4.930380657631324e-32
- } else if x < xbig {
- tmp := 10.0 / x
- return chebyshevEval(nalgm, tmp*tmp*2.0-1.0, algmcs) / x
- }
- return 1.0 / (x * 12.0)
- }
- // logrelerr compute the relative error logarithm.
- func logrelerr(x float64) float64 {
- alnrcs := []float64{
- 0.10378693562743769800686267719098e+1, -0.13364301504908918098766041553133,
- 0.19408249135520563357926199374750e-1, -0.30107551127535777690376537776592e-2,
- 0.48694614797154850090456366509137e-3, -0.81054881893175356066809943008622e-4,
- 0.13778847799559524782938251496059e-4, -0.23802210894358970251369992914935e-5,
- 0.41640416213865183476391859901989e-6, -0.73595828378075994984266837031998e-7,
- 0.13117611876241674949152294345011e-7, -0.23546709317742425136696092330175e-8,
- 0.42522773276034997775638052962567e-9, -0.77190894134840796826108107493300e-10,
- 0.14075746481359069909215356472191e-10, -0.25769072058024680627537078627584e-11,
- 0.47342406666294421849154395005938e-12, -0.87249012674742641745301263292675e-13,
- 0.16124614902740551465739833119115e-13, -0.29875652015665773006710792416815e-14,
- 0.55480701209082887983041321697279e-15, -0.10324619158271569595141333961932e-15,
- 0.19250239203049851177878503244868e-16, -0.35955073465265150011189707844266e-17,
- 0.67264542537876857892194574226773e-18, -0.12602624168735219252082425637546e-18,
- 0.23644884408606210044916158955519e-19, -0.44419377050807936898878389179733e-20,
- 0.83546594464034259016241293994666e-21, -0.15731559416479562574899253521066e-21,
- 0.29653128740247422686154369706666e-22, -0.55949583481815947292156013226666e-23,
- 0.10566354268835681048187284138666e-23, -0.19972483680670204548314999466666e-24,
- 0.37782977818839361421049855999999e-25, -0.71531586889081740345038165333333e-26,
- 0.13552488463674213646502024533333e-26, -0.25694673048487567430079829333333e-27,
- 0.48747756066216949076459519999999e-28, -0.92542112530849715321132373333333e-29,
- 0.17578597841760239233269760000000e-29, -0.33410026677731010351377066666666e-30,
- 0.63533936180236187354180266666666e-31,
- }
- nlnrel := chebyshevInit(43, 0.1*d1mach(3), alnrcs)
- if x <= -1 {
- return math.NaN()
- }
- if math.Abs(x) <= 0.375 {
- return x * (1.0 - x*chebyshevEval(nlnrel, x/0.375, alnrcs))
- }
- return math.Log(x + 1.0)
- }
- // logBeta is an implementation for the log of the beta distribution
- // function.
- func logBeta(a, b float64) float64 {
- corr, p, q := 0.0, a, a
- if b < p {
- p = b
- }
- if b > q {
- q = b
- }
- if p < 0 {
- return math.NaN()
- }
- if p == 0 {
- return math.MaxFloat64
- }
- if p >= 10.0 {
- corr = lgammacor(p) + lgammacor(q) - lgammacor(p+q)
- f1 := q * logrelerr(-p/(p+q))
- return math.Log(q)*-0.5 + 0.918938533204672741780329736406 + corr + (p-0.5)*math.Log(p/(p+q)) + math.Nextafter(f1, f1)
- }
- if q >= 10 {
- corr = lgammacor(q) - lgammacor(p+q)
- val, _ := math.Lgamma(p)
- return val + corr + p - p*math.Log(p+q) + (q-0.5)*logrelerr(-p/(p+q))
- }
- return math.Log(math.Gamma(p) * (math.Gamma(q) / math.Gamma(p+q)))
- }
- // pbetaRaw is a part of pbeta for the beta distribution.
- func pbetaRaw(alnsml, ans, eps, p, pin, q, sml, x, y float64) float64 {
- if q > 1.0 {
- xb := p*math.Log(y) + q*math.Log(1.0-y) - logBeta(p, q) - math.Log(q)
- ib := int(math.Max(xb/alnsml, 0.0))
- term := math.Exp(xb - float64(ib)*alnsml)
- c := 1.0 / (1.0 - y)
- p1 := q * c / (p + q - 1.0)
- finsum := 0.0
- n := int(q)
- if q == float64(n) {
- n = n - 1
- }
- for i := 1; i <= n; i++ {
- if p1 <= 1 && term/eps <= finsum {
- break
- }
- xi := float64(i)
- term = (q - xi + 1.0) * c * term / (p + q - xi)
- if term > 1.0 {
- ib = ib - 1
- term = term * sml
- }
- if ib == 0 {
- finsum = finsum + term
- }
- }
- ans = ans + finsum
- }
- if y != x || p != pin {
- ans = 1.0 - ans
- }
- ans = math.Max(math.Min(ans, 1.0), 0.0)
- return ans
- }
- // pbeta returns distribution function of the beta distribution.
- func pbeta(x, pin, qin float64) (ans float64) {
- eps := d1mach(3)
- alneps := math.Log(eps)
- sml := d1mach(1)
- alnsml := math.Log(sml)
- y := x
- p := pin
- q := qin
- if p/(p+q) < x {
- y = 1.0 - y
- p = qin
- q = pin
- }
- if (p+q)*y/(p+1.0) < eps {
- xb := p*math.Log(math.Max(y, sml)) - math.Log(p) - logBeta(p, q)
- if xb > alnsml && y != 0.0 {
- ans = math.Exp(xb)
- }
- if y != x || p != pin {
- ans = 1.0 - ans
- }
- } else {
- ps := q - math.Floor(q)
- if ps == 0.0 {
- ps = 1.0
- }
- xb := p*math.Log(y) - logBeta(ps, p) - math.Log(p)
- if xb >= alnsml {
- ans = math.Exp(xb)
- term := ans * p
- if ps != 1.0 {
- n := int(math.Max(alneps/math.Log(y), 4.0))
- for i := 1; i <= n; i++ {
- xi := float64(i)
- term = term * (xi - ps) * y / xi
- ans = ans + term/(p+xi)
- }
- }
- }
- ans = pbetaRaw(alnsml, ans, eps, p, pin, q, sml, x, y)
- }
- return ans
- }
- // betainvProbIterator is a part of betainv for the inverse of the beta
- // function.
- func betainvProbIterator(alpha1, alpha3, beta1, beta2, beta3, logBeta, maxCumulative, prob1, prob2 float64) float64 {
- var i, j, prev, prop4 float64
- j = 1
- for prob := 0; prob < 1000; prob++ {
- prop3 := pbeta(beta3, alpha1, beta1)
- prop3 = (prop3 - prob1) * math.Exp(logBeta+prob2*math.Log(beta3)+beta2*math.Log(1.0-beta3))
- if prop3*prop4 <= 0 {
- prev = math.Max(math.Abs(j), maxCumulative)
- }
- h := 1.0
- for iteratorCount := 0; iteratorCount < 1000; iteratorCount++ {
- j = h * prop3
- if math.Abs(j) < prev {
- i = beta3 - j
- if i >= 0 && i <= 1.0 {
- if prev <= alpha3 {
- return beta3
- }
- if math.Abs(prop3) <= alpha3 {
- return beta3
- }
- if i != 0 && i != 1.0 {
- break
- }
- }
- }
- h /= 3.0
- }
- if i == beta3 {
- return beta3
- }
- beta3, prop4 = i, prop3
- }
- return beta3
- }
- // calcBetainv is an implementation for the quantile of the beta
- // distribution.
- func calcBetainv(probability, alpha, beta, lower, upper float64) float64 {
- minCumulative, maxCumulative := 1.0e-300, 3.0e-308
- lowerBound, upperBound := maxCumulative, 1.0-2.22e-16
- needSwap := false
- var alpha1, alpha2, beta1, beta2, beta3, prob1, x, y float64
- if probability <= 0.5 {
- prob1, alpha1, beta1 = probability, alpha, beta
- } else {
- prob1, alpha1, beta1, needSwap = 1.0-probability, beta, alpha, true
- }
- logBetaNum := logBeta(alpha, beta)
- prob2 := math.Sqrt(-math.Log(prob1 * prob1))
- prob3 := prob2 - (prob2*0.27061+2.3075)/(prob2*(prob2*0.04481+0.99229)+1)
- if alpha1 > 1 && beta1 > 1 {
- alpha2, beta2, prob2 = 1/(alpha1+alpha1-1), 1/(beta1+beta1-1), (prob3*prob3-3)/6
- x = 2 / (alpha2 + beta2)
- y = prob3*math.Sqrt(x+prob2)/x - (beta2-alpha2)*(prob2+5/6.0-2/(x*3))
- beta3 = alpha1 / (alpha1 + beta1*math.Exp(y+y))
- } else {
- beta2, prob2 = 1/(beta1*9), beta1+beta1
- beta2 = prob2 * math.Pow(1-beta2+prob3*math.Sqrt(beta2), 3)
- if beta2 <= 0 {
- beta3 = 1 - math.Exp((math.Log((1-prob1)*beta1)+logBetaNum)/beta1)
- } else {
- beta2 = (prob2 + alpha1*4 - 2) / beta2
- if beta2 <= 1 {
- beta3 = math.Exp((logBetaNum + math.Log(alpha1*prob1)) / alpha1)
- } else {
- beta3 = 1 - 2/(beta2+1)
- }
- }
- }
- beta2, prob2 = 1-beta1, 1-alpha1
- if beta3 < lowerBound {
- beta3 = lowerBound
- } else if beta3 > upperBound {
- beta3 = upperBound
- }
- alpha3 := math.Max(minCumulative, math.Pow(10.0, -13.0-2.5/(alpha1*alpha1)-0.5/(prob1*prob1)))
- beta3 = betainvProbIterator(alpha1, alpha3, beta1, beta2, beta3, logBetaNum, maxCumulative, prob1, prob2)
- if needSwap {
- beta3 = 1.0 - beta3
- }
- return (upper-lower)*beta3 + lower
- }
- // betainv is an implementation of the formula functions BETAINV and
- // BETA.INV.
- func (fn *formulaFuncs) betainv(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 3 arguments", name))
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at most 5 arguments", name))
- }
- probability := argsList.Front().Value.(formulaArg).ToNumber()
- if probability.Type != ArgNumber {
- return probability
- }
- if probability.Number <= 0 || probability.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- alpha := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if alpha.Type != ArgNumber {
- return alpha
- }
- beta := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if beta.Type != ArgNumber {
- return beta
- }
- if alpha.Number <= 0 || beta.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- a, b := newNumberFormulaArg(0), newNumberFormulaArg(1)
- if argsList.Len() > 3 {
- if a = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); a.Type != ArgNumber {
- return a
- }
- }
- if argsList.Len() == 5 {
- if b = argsList.Back().Value.(formulaArg).ToNumber(); b.Type != ArgNumber {
- return b
- }
- }
- if a.Number == b.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(calcBetainv(probability.Number, alpha.Number, beta.Number, a.Number, b.Number))
- }
- // BETAINV function uses an iterative procedure to calculate the inverse of
- // the cumulative beta probability density function for a supplied
- // probability. The syntax of the function is:
- //
- // BETAINV(probability,alpha,beta,[A],[B])
- func (fn *formulaFuncs) BETAINV(argsList *list.List) formulaArg {
- return fn.betainv("BETAINV", argsList)
- }
- // BETAdotINV function uses an iterative procedure to calculate the inverse of
- // the cumulative beta probability density function for a supplied
- // probability. The syntax of the function is:
- //
- // BETA.INV(probability,alpha,beta,[A],[B])
- func (fn *formulaFuncs) BETAdotINV(argsList *list.List) formulaArg {
- return fn.betainv("BETA.INV", argsList)
- }
- // incompleteGamma is an implementation of the incomplete gamma function.
- func incompleteGamma(a, x float64) float64 {
- max := 32
- summer := 0.0
- for n := 0; n <= max; n++ {
- divisor := a
- for i := 1; i <= n; i++ {
- divisor *= a + float64(i)
- }
- summer += math.Pow(x, float64(n)) / divisor
- }
- return math.Pow(x, a) * math.Exp(0-x) * summer
- }
- // binomCoeff implement binomial coefficient calculation.
- func binomCoeff(n, k float64) float64 {
- return fact(n) / (fact(k) * fact(n-k))
- }
- // binomdist implement binomial distribution calculation.
- func binomdist(x, n, p float64) float64 {
- return binomCoeff(n, x) * math.Pow(p, x) * math.Pow(1-p, n-x)
- }
- // BINOMdotDIST function returns the Binomial Distribution probability for a
- // given number of successes from a specified number of trials. The syntax of
- // the function is:
- //
- // BINOM.DIST(number_s,trials,probability_s,cumulative)
- func (fn *formulaFuncs) BINOMdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "BINOM.DIST requires 4 arguments")
- }
- return fn.BINOMDIST(argsList)
- }
- // BINOMDIST function returns the Binomial Distribution probability of a
- // specified number of successes out of a specified number of trials. The
- // syntax of the function is:
- //
- // BINOMDIST(number_s,trials,probability_s,cumulative)
- func (fn *formulaFuncs) BINOMDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "BINOMDIST requires 4 arguments")
- }
- var s, trials, probability, cumulative formulaArg
- if s = argsList.Front().Value.(formulaArg).ToNumber(); s.Type != ArgNumber {
- return s
- }
- if trials = argsList.Front().Next().Value.(formulaArg).ToNumber(); trials.Type != ArgNumber {
- return trials
- }
- if s.Number < 0 || s.Number > trials.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if probability = argsList.Back().Prev().Value.(formulaArg).ToNumber(); probability.Type != ArgNumber {
- return probability
- }
- if probability.Number < 0 || probability.Number > 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError {
- return cumulative
- }
- if cumulative.Number == 1 {
- bm := 0.0
- for i := 0; i <= int(s.Number); i++ {
- bm += binomdist(float64(i), trials.Number, probability.Number)
- }
- return newNumberFormulaArg(bm)
- }
- return newNumberFormulaArg(binomdist(s.Number, trials.Number, probability.Number))
- }
- // BINOMdotDISTdotRANGE function returns the Binomial Distribution probability
- // for the number of successes from a specified number of trials falling into
- // a specified range.
- //
- // BINOM.DIST.RANGE(trials,probability_s,number_s,[number_s2])
- func (fn *formulaFuncs) BINOMdotDISTdotRANGE(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "BINOM.DIST.RANGE requires at least 3 arguments")
- }
- if argsList.Len() > 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "BINOM.DIST.RANGE requires at most 4 arguments")
- }
- trials := argsList.Front().Value.(formulaArg).ToNumber()
- if trials.Type != ArgNumber {
- return trials
- }
- probability := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if probability.Type != ArgNumber {
- return probability
- }
- if probability.Number < 0 || probability.Number > 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- num1 := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if num1.Type != ArgNumber {
- return num1
- }
- if num1.Number < 0 || num1.Number > trials.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- num2 := num1
- if argsList.Len() > 3 {
- if num2 = argsList.Back().Value.(formulaArg).ToNumber(); num2.Type != ArgNumber {
- return num2
- }
- }
- if num2.Number < 0 || num2.Number > trials.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- sum := 0.0
- for i := num1.Number; i <= num2.Number; i++ {
- sum += binomdist(i, trials.Number, probability.Number)
- }
- return newNumberFormulaArg(sum)
- }
- // binominv implement inverse of the binomial distribution calculation.
- func binominv(n, p, alpha float64) float64 {
- q, i, sum, max := 1-p, 0.0, 0.0, 0.0
- n = math.Floor(n)
- if q > p {
- factor := math.Pow(q, n)
- sum = factor
- for i = 0; i < n && sum < alpha; i++ {
- factor *= (n - i) / (i + 1) * p / q
- sum += factor
- }
- return i
- }
- factor := math.Pow(p, n)
- sum, max = 1-factor, n
- for i = 0; i < max && sum >= alpha; i++ {
- factor *= (n - i) / (i + 1) * q / p
- sum -= factor
- }
- return n - i
- }
- // BINOMdotINV function returns the inverse of the Cumulative Binomial
- // Distribution. The syntax of the function is:
- //
- // BINOM.INV(trials,probability_s,alpha)
- func (fn *formulaFuncs) BINOMdotINV(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "BINOM.INV requires 3 numeric arguments")
- }
- trials := argsList.Front().Value.(formulaArg).ToNumber()
- if trials.Type != ArgNumber {
- return trials
- }
- if trials.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- probability := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if probability.Type != ArgNumber {
- return probability
- }
- if probability.Number <= 0 || probability.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- alpha := argsList.Back().Value.(formulaArg).ToNumber()
- if alpha.Type != ArgNumber {
- return alpha
- }
- if alpha.Number <= 0 || alpha.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(binominv(trials.Number, probability.Number, alpha.Number))
- }
- // CHIDIST function calculates the right-tailed probability of the chi-square
- // distribution. The syntax of the function is:
- //
- // CHIDIST(x,degrees_freedom)
- func (fn *formulaFuncs) CHIDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHIDIST requires 2 numeric arguments")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- degrees := argsList.Back().Value.(formulaArg).ToNumber()
- if degrees.Type != ArgNumber {
- return degrees
- }
- logSqrtPi, sqrtPi := math.Log(math.Sqrt(math.Pi)), 1/math.Sqrt(math.Pi)
- var e, s, z, c, y float64
- a, x1, even := x.Number/2, x.Number, int(degrees.Number)%2 == 0
- if degrees.Number > 1 {
- y = math.Exp(-a)
- }
- args := list.New()
- args.PushBack(newNumberFormulaArg(-math.Sqrt(x1)))
- o := fn.NORMSDIST(args)
- s = 2 * o.Number
- if even {
- s = y
- }
- if degrees.Number > 2 {
- x1 = (degrees.Number - 1) / 2
- z = 0.5
- if even {
- z = 1
- }
- if a > 20 {
- e = logSqrtPi
- if even {
- e = 0
- }
- c = math.Log(a)
- for z <= x1 {
- e = math.Log(z) + e
- s += math.Exp(c*z - a - e)
- z++
- }
- return newNumberFormulaArg(s)
- }
- e = sqrtPi / math.Sqrt(a)
- if even {
- e = 1
- }
- c = 0
- for z <= x1 {
- e = e * (a / z)
- c = c + e
- z++
- }
- return newNumberFormulaArg(c*y + s)
- }
- return newNumberFormulaArg(s)
- }
- // CHIINV function calculates the inverse of the right-tailed probability of
- // the Chi-Square Distribution. The syntax of the function is:
- //
- // CHIINV(probability,deg_freedom)
- func (fn *formulaFuncs) CHIINV(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHIINV requires 2 numeric arguments")
- }
- probability := argsList.Front().Value.(formulaArg).ToNumber()
- if probability.Type != ArgNumber {
- return probability
- }
- if probability.Number <= 0 || probability.Number > 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- deg := argsList.Back().Value.(formulaArg).ToNumber()
- if deg.Type != ArgNumber {
- return deg
- }
- if deg.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(gammainv(1-probability.Number, 0.5*deg.Number, 2.0))
- }
- // CHITEST function uses the chi-square test to calculate the probability that
- // the differences between two supplied data sets (of observed and expected
- // frequencies), are likely to be simply due to sampling error, or if they are
- // likely to be real. The syntax of the function is:
- //
- // CHITEST(actual_range,expected_range)
- func (fn *formulaFuncs) CHITEST(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHITEST requires 2 arguments")
- }
- actual, expected := argsList.Front().Value.(formulaArg), argsList.Back().Value.(formulaArg)
- actualList, expectedList := actual.ToList(), expected.ToList()
- rows := len(actual.Matrix)
- columns := len(actualList) / rows
- if len(actualList) != len(expectedList) || len(actualList) == 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var result float64
- var degrees int
- for i := 0; i < len(actualList); i++ {
- a, e := actualList[i].ToNumber(), expectedList[i].ToNumber()
- if a.Type == ArgNumber && e.Type == ArgNumber {
- if e.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- if e.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- result += (a.Number - e.Number) * (a.Number - e.Number) / e.Number
- }
- }
- if rows == 1 {
- degrees = columns - 1
- } else if columns == 1 {
- degrees = rows - 1
- } else {
- degrees = (columns - 1) * (rows - 1)
- }
- args := list.New()
- args.PushBack(newNumberFormulaArg(result))
- args.PushBack(newNumberFormulaArg(float64(degrees)))
- return fn.CHIDIST(args)
- }
- // getGammaSeries calculates a power-series of the gamma function.
- func getGammaSeries(fA, fX float64) float64 {
- var (
- fHalfMachEps = 2.22045e-016 / 2
- fDenomfactor = fA
- fSummand = 1 / fA
- fSum = fSummand
- nCount = 1
- )
- for fSummand/fSum > fHalfMachEps && nCount <= 10000 {
- fDenomfactor = fDenomfactor + 1
- fSummand = fSummand * fX / fDenomfactor
- fSum = fSum + fSummand
- nCount = nCount + 1
- }
- return fSum
- }
- // getGammaContFraction returns continued fraction with odd items of the gamma
- // function.
- func getGammaContFraction(fA, fX float64) float64 {
- var (
- fBigInv = 2.22045e-016
- fHalfMachEps = fBigInv / 2
- fBig = 1 / fBigInv
- fCount = 0.0
- fY = 1 - fA
- fDenom = fX + 2 - fA
- fPkm1 = fX + 1
- fPkm2 = 1.0
- fQkm1 = fDenom * fX
- fQkm2 = fX
- fApprox = fPkm1 / fQkm1
- bFinished = false
- )
- for !bFinished && fCount < 10000 {
- fCount = fCount + 1
- fY = fY + 1
- fDenom = fDenom + 2
- var (
- fNum = fY * fCount
- f1 = fPkm1 * fDenom
- f2 = fPkm2 * fNum
- fPk = math.Nextafter(f1, f1) - math.Nextafter(f2, f2)
- f3 = fQkm1 * fDenom
- f4 = fQkm2 * fNum
- fQk = math.Nextafter(f3, f3) - math.Nextafter(f4, f4)
- )
- if fQk != 0 {
- fR := fPk / fQk
- bFinished = math.Abs((fApprox-fR)/fR) <= fHalfMachEps
- fApprox = fR
- }
- fPkm2, fPkm1, fQkm2, fQkm1 = fPkm1, fPk, fQkm1, fQk
- if math.Abs(fPk) > fBig {
- // reduce a fraction does not change the value
- fPkm2 = fPkm2 * fBigInv
- fPkm1 = fPkm1 * fBigInv
- fQkm2 = fQkm2 * fBigInv
- fQkm1 = fQkm1 * fBigInv
- }
- }
- return fApprox
- }
- // getLogGammaHelper is a part of implementation of the function getLogGamma.
- func getLogGammaHelper(fZ float64) float64 {
- _fg := 6.024680040776729583740234375
- zgHelp := fZ + _fg - 0.5
- return math.Log(getLanczosSum(fZ)) + (fZ-0.5)*math.Log(zgHelp) - zgHelp
- }
- // getGammaHelper is a part of implementation of the function getLogGamma.
- func getGammaHelper(fZ float64) float64 {
- var (
- gamma = getLanczosSum(fZ)
- fg = 6.024680040776729583740234375
- zgHelp = fZ + fg - 0.5
- // avoid intermediate overflow
- halfpower = math.Pow(zgHelp, fZ/2-0.25)
- )
- gamma *= halfpower
- gamma /= math.Exp(zgHelp)
- gamma *= halfpower
- if fZ <= 20 && fZ == math.Floor(fZ) {
- gamma = math.Round(gamma)
- }
- return gamma
- }
- // getLogGamma calculates the natural logarithm of the gamma function.
- func getLogGamma(fZ float64) float64 {
- fMaxGammaArgument := 171.624376956302
- if fZ >= fMaxGammaArgument {
- return getLogGammaHelper(fZ)
- }
- if fZ >= 1.0 {
- return math.Log(getGammaHelper(fZ))
- }
- if fZ >= 0.5 {
- return math.Log(getGammaHelper(fZ+1) / fZ)
- }
- return getLogGammaHelper(fZ+2) - math.Log(fZ+1) - math.Log(fZ)
- }
- // getLowRegIGamma returns lower regularized incomplete gamma function.
- func getLowRegIGamma(fA, fX float64) float64 {
- lnFactor := fA*math.Log(fX) - fX - getLogGamma(fA)
- factor := math.Exp(lnFactor)
- if fX > fA+1 {
- return 1 - factor*getGammaContFraction(fA, fX)
- }
- return factor * getGammaSeries(fA, fX)
- }
- // getChiSqDistCDF returns left tail for the Chi-Square distribution.
- func getChiSqDistCDF(fX, fDF float64) float64 {
- if fX <= 0 {
- return 0
- }
- return getLowRegIGamma(fDF/2, fX/2)
- }
- // getChiSqDistPDF calculates the probability density function for the
- // Chi-Square distribution.
- func getChiSqDistPDF(fX, fDF float64) float64 {
- if fDF*fX > 1391000 {
- return math.Exp((0.5*fDF-1)*math.Log(fX*0.5) - 0.5*fX - math.Log(2) - getLogGamma(0.5*fDF))
- }
- var fCount, fValue float64
- if math.Mod(fDF, 2) < 0.5 {
- fValue = 0.5
- fCount = 2
- } else {
- fValue = 1 / math.Sqrt(fX*2*math.Pi)
- fCount = 1
- }
- for fCount < fDF {
- fValue *= fX / fCount
- fCount += 2
- }
- if fX >= 1425 {
- fValue = math.Exp(math.Log(fValue) - fX/2)
- } else {
- fValue *= math.Exp(-fX / 2)
- }
- return fValue
- }
- // CHISQdotDIST function calculates the Probability Density Function or the
- // Cumulative Distribution Function for the Chi-Square Distribution. The
- // syntax of the function is:
- //
- // CHISQ.DIST(x,degrees_freedom,cumulative)
- func (fn *formulaFuncs) CHISQdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHISQ.DIST requires 3 arguments")
- }
- var x, degrees, cumulative formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if degrees = argsList.Front().Next().Value.(formulaArg).ToNumber(); degrees.Type != ArgNumber {
- return degrees
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError {
- return cumulative
- }
- if x.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- maxDeg := math.Pow10(10)
- if degrees.Number < 1 || degrees.Number >= maxDeg {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if cumulative.Number == 1 {
- return newNumberFormulaArg(getChiSqDistCDF(x.Number, degrees.Number))
- }
- return newNumberFormulaArg(getChiSqDistPDF(x.Number, degrees.Number))
- }
- // CHISQdotDISTdotRT function calculates the right-tailed probability of the
- // Chi-Square Distribution. The syntax of the function is:
- //
- // CHISQ.DIST.RT(x,degrees_freedom)
- func (fn *formulaFuncs) CHISQdotDISTdotRT(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHISQ.DIST.RT requires 2 numeric arguments")
- }
- return fn.CHIDIST(argsList)
- }
- // CHISQdotTEST function performs the chi-square test on two supplied data sets
- // (of observed and expected frequencies), and returns the probability that
- // the differences between the sets are simply due to sampling error. The
- // syntax of the function is:
- //
- // CHISQ.TEST(actual_range,expected_range)
- func (fn *formulaFuncs) CHISQdotTEST(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHISQ.TEST requires 2 arguments")
- }
- return fn.CHITEST(argsList)
- }
- // hasChangeOfSign check if the sign has been changed.
- func hasChangeOfSign(u, w float64) bool {
- return (u < 0 && w > 0) || (u > 0 && w < 0)
- }
- // calcInverseIterator directly maps the required parameters for inverse
- // distribution functions.
- type calcInverseIterator struct {
- name string
- fp, fDF, nT float64
- }
- // callBack implements the callback function for the inverse iterator.
- func (iterator *calcInverseIterator) callBack(x float64) float64 {
- if iterator.name == "CHISQ.INV" {
- return iterator.fp - getChiSqDistCDF(x, iterator.fDF)
- }
- return iterator.fp - getTDist(x, iterator.fDF, iterator.nT)
- }
- // inverseQuadraticInterpolation inverse quadratic interpolation with
- // additional brackets.
- func inverseQuadraticInterpolation(iterator calcInverseIterator, fAx, fAy, fBx, fBy float64) float64 {
- fYEps := 1.0e-307
- fXEps := 2.22045e-016
- fPx, fPy, fQx, fQy, fRx, fRy := fAx, fAy, fBx, fBy, fAx, fAy
- fSx := 0.5 * (fAx + fBx)
- bHasToInterpolate := true
- nCount := 0
- for nCount < 500 && math.Abs(fRy) > fYEps && (fBx-fAx) > math.Max(math.Abs(fAx), math.Abs(fBx))*fXEps {
- if bHasToInterpolate {
- if fPy != fQy && fQy != fRy && fRy != fPy {
- fSx = fPx*fRy*fQy/(fRy-fPy)/(fQy-fPy) + fRx*fQy*fPy/(fQy-fRy)/(fPy-fRy) +
- fQx*fPy*fRy/(fPy-fQy)/(fRy-fQy)
- bHasToInterpolate = (fAx < fSx) && (fSx < fBx)
- } else {
- bHasToInterpolate = false
- }
- }
- if !bHasToInterpolate {
- fSx = 0.5 * (fAx + fBx)
- fQx, fQy = fBx, fBy
- bHasToInterpolate = true
- }
- fPx, fQx, fRx, fPy, fQy = fQx, fRx, fSx, fQy, fRy
- fRy = iterator.callBack(fSx)
- if hasChangeOfSign(fAy, fRy) {
- fBx, fBy = fRx, fRy
- } else {
- fAx, fAy = fRx, fRy
- }
- bHasToInterpolate = bHasToInterpolate && (math.Abs(fRy)*2 <= math.Abs(fQy))
- nCount++
- }
- return fRx
- }
- // calcIterateInverse function calculates the iteration for inverse
- // distributions.
- func calcIterateInverse(iterator calcInverseIterator, fAx, fBx float64) float64 {
- fAy, fBy := iterator.callBack(fAx), iterator.callBack(fBx)
- var fTemp float64
- var nCount int
- for nCount = 0; nCount < 1000 && !hasChangeOfSign(fAy, fBy); nCount++ {
- if math.Abs(fAy) <= math.Abs(fBy) {
- fTemp = fAx
- fAx += 2 * (fAx - fBx)
- if fAx < 0 {
- fAx = 0
- }
- fBx = fTemp
- fBy = fAy
- fAy = iterator.callBack(fAx)
- } else {
- fTemp = fBx
- fBx += 2 * (fBx - fAx)
- fAx = fTemp
- fAy = fBy
- fBy = iterator.callBack(fBx)
- }
- }
- if fAy == 0 || fBy == 0 {
- return 0
- }
- return inverseQuadraticInterpolation(iterator, fAx, fAy, fBx, fBy)
- }
- // CHISQdotINV function calculates the inverse of the left-tailed probability
- // of the Chi-Square Distribution. The syntax of the function is:
- //
- // CHISQ.INV(probability,degrees_freedom)
- func (fn *formulaFuncs) CHISQdotINV(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHISQ.INV requires 2 numeric arguments")
- }
- var probability, degrees formulaArg
- if probability = argsList.Front().Value.(formulaArg).ToNumber(); probability.Type != ArgNumber {
- return probability
- }
- if degrees = argsList.Back().Value.(formulaArg).ToNumber(); degrees.Type != ArgNumber {
- return degrees
- }
- if probability.Number < 0 || probability.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if degrees.Number < 1 || degrees.Number > math.Pow10(10) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(calcIterateInverse(calcInverseIterator{
- name: "CHISQ.INV",
- fp: probability.Number,
- fDF: degrees.Number,
- }, degrees.Number/2, degrees.Number))
- }
- // CHISQdotINVdotRT function calculates the inverse of the right-tailed
- // probability of the Chi-Square Distribution. The syntax of the function is:
- //
- // CHISQ.INV.RT(probability,degrees_freedom)
- func (fn *formulaFuncs) CHISQdotINVdotRT(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHISQ.INV.RT requires 2 numeric arguments")
- }
- return fn.CHIINV(argsList)
- }
- // confidence is an implementation of the formula functions CONFIDENCE and
- // CONFIDENCE.NORM.
- func (fn *formulaFuncs) confidence(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 3 numeric arguments", name))
- }
- alpha := argsList.Front().Value.(formulaArg).ToNumber()
- if alpha.Type != ArgNumber {
- return alpha
- }
- if alpha.Number <= 0 || alpha.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- stdDev := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if stdDev.Type != ArgNumber {
- return stdDev
- }
- if stdDev.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- size := argsList.Back().Value.(formulaArg).ToNumber()
- if size.Type != ArgNumber {
- return size
- }
- if size.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- args := list.New()
- args.Init()
- args.PushBack(newNumberFormulaArg(alpha.Number / 2))
- args.PushBack(newNumberFormulaArg(0))
- args.PushBack(newNumberFormulaArg(1))
- return newNumberFormulaArg(-fn.NORMINV(args).Number * (stdDev.Number / math.Sqrt(size.Number)))
- }
- // CONFIDENCE function uses a Normal Distribution to calculate a confidence
- // value that can be used to construct the Confidence Interval for a
- // population mean, for a supplied probability and sample size. It is assumed
- // that the standard deviation of the population is known. The syntax of the
- // function is:
- //
- // CONFIDENCE(alpha,standard_dev,size)
- func (fn *formulaFuncs) CONFIDENCE(argsList *list.List) formulaArg {
- return fn.confidence("CONFIDENCE", argsList)
- }
- // CONFIDENCEdotNORM function uses a Normal Distribution to calculate a
- // confidence value that can be used to construct the confidence interval for
- // a population mean, for a supplied probability and sample size. It is
- // assumed that the standard deviation of the population is known. The syntax
- // of the function is:
- //
- // CONFIDENCE.NORM(alpha,standard_dev,size)
- func (fn *formulaFuncs) CONFIDENCEdotNORM(argsList *list.List) formulaArg {
- return fn.confidence("CONFIDENCE.NORM", argsList)
- }
- // CONFIDENCEdotT function uses a Student's T-Distribution to calculate a
- // confidence value that can be used to construct the confidence interval for
- // a population mean, for a supplied probablity and supplied sample size. It
- // is assumed that the standard deviation of the population is known. The
- // syntax of the function is:
- //
- // CONFIDENCE.T(alpha,standard_dev,size)
- func (fn *formulaFuncs) CONFIDENCEdotT(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "CONFIDENCE.T requires 3 arguments")
- }
- var alpha, standardDev, size formulaArg
- if alpha = argsList.Front().Value.(formulaArg).ToNumber(); alpha.Type != ArgNumber {
- return alpha
- }
- if standardDev = argsList.Front().Next().Value.(formulaArg).ToNumber(); standardDev.Type != ArgNumber {
- return standardDev
- }
- if size = argsList.Back().Value.(formulaArg).ToNumber(); size.Type != ArgNumber {
- return size
- }
- if alpha.Number <= 0 || alpha.Number >= 1 || standardDev.Number <= 0 || size.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if size.Number == 1 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(standardDev.Number * calcIterateInverse(calcInverseIterator{
- name: "CONFIDENCE.T",
- fp: alpha.Number,
- fDF: size.Number - 1,
- nT: 2,
- }, size.Number/2, size.Number) / math.Sqrt(size.Number))
- }
- // covar is an implementation of the formula functions COVAR, COVARIANCE.P and
- // COVARIANCE.S.
- func (fn *formulaFuncs) covar(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name))
- }
- array1 := argsList.Front().Value.(formulaArg)
- array2 := argsList.Back().Value.(formulaArg)
- left, right := array1.ToList(), array2.ToList()
- n := len(left)
- if n != len(right) {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- l1, l2 := list.New(), list.New()
- l1.PushBack(array1)
- l2.PushBack(array2)
- result, skip := 0.0, 0
- mean1, mean2 := fn.AVERAGE(l1), fn.AVERAGE(l2)
- for i := 0; i < n; i++ {
- arg1 := left[i].ToNumber()
- arg2 := right[i].ToNumber()
- if arg1.Type == ArgError || arg2.Type == ArgError {
- skip++
- continue
- }
- result += (arg1.Number - mean1.Number) * (arg2.Number - mean2.Number)
- }
- if name == "COVARIANCE.S" {
- return newNumberFormulaArg(result / float64(n-skip-1))
- }
- return newNumberFormulaArg(result / float64(n-skip))
- }
- // COVAR function calculates the covariance of two supplied sets of values. The
- // syntax of the function is:
- //
- // COVAR(array1,array2)
- func (fn *formulaFuncs) COVAR(argsList *list.List) formulaArg {
- return fn.covar("COVAR", argsList)
- }
- // COVARIANCEdotP function calculates the population covariance of two supplied
- // sets of values. The syntax of the function is:
- //
- // COVARIANCE.P(array1,array2)
- func (fn *formulaFuncs) COVARIANCEdotP(argsList *list.List) formulaArg {
- return fn.covar("COVARIANCE.P", argsList)
- }
- // COVARIANCEdotS function calculates the sample covariance of two supplied
- // sets of values. The syntax of the function is:
- //
- // COVARIANCE.S(array1,array2)
- func (fn *formulaFuncs) COVARIANCEdotS(argsList *list.List) formulaArg {
- return fn.covar("COVARIANCE.S", argsList)
- }
- // calcStringCountSum is part of the implementation countSum.
- func calcStringCountSum(countText bool, count, sum float64, num, arg formulaArg) (float64, float64) {
- if countText && num.Type == ArgError && arg.String != "" {
- count++
- }
- if num.Type == ArgNumber {
- sum += num.Number
- count++
- }
- return count, sum
- }
- // countSum get count and sum for a formula arguments array.
- func (fn *formulaFuncs) countSum(countText bool, args []formulaArg) (count, sum float64) {
- for _, arg := range args {
- switch arg.Type {
- case ArgNumber:
- if countText || !arg.Boolean {
- sum += arg.Number
- count++
- }
- case ArgString:
- if !countText && (arg.Value() == "TRUE" || arg.Value() == "FALSE") {
- continue
- } else if countText && (arg.Value() == "TRUE" || arg.Value() == "FALSE") {
- num := arg.ToBool()
- if num.Type == ArgNumber {
- count++
- sum += num.Number
- continue
- }
- }
- num := arg.ToNumber()
- count, sum = calcStringCountSum(countText, count, sum, num, arg)
- case ArgList, ArgMatrix:
- cnt, summary := fn.countSum(countText, arg.ToList())
- sum += summary
- count += cnt
- }
- }
- return
- }
- // CORREL function calculates the Pearson Product-Moment Correlation
- // Coefficient for two sets of values. The syntax of the function is:
- //
- // CORREL(array1,array2)
- func (fn *formulaFuncs) CORREL(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CORREL requires 2 arguments")
- }
- array1 := argsList.Front().Value.(formulaArg)
- array2 := argsList.Back().Value.(formulaArg)
- left, right := array1.ToList(), array2.ToList()
- n := len(left)
- if n != len(right) {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- l1, l2, l3 := list.New(), list.New(), list.New()
- for i := 0; i < n; i++ {
- if lhs, rhs := left[i].ToNumber(), right[i].ToNumber(); lhs.Number != 0 && rhs.Number != 0 {
- l1.PushBack(lhs)
- l2.PushBack(rhs)
- }
- }
- stdev1, stdev2 := fn.STDEV(l1), fn.STDEV(l2)
- if stdev1.Number == 0 || stdev2.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- mean1, mean2, skip := fn.AVERAGE(l1), fn.AVERAGE(l2), 0
- for i := 0; i < n; i++ {
- lhs, rhs := left[i].ToNumber(), right[i].ToNumber()
- if lhs.Number == 0 || rhs.Number == 0 {
- skip++
- continue
- }
- l3.PushBack(newNumberFormulaArg((lhs.Number - mean1.Number) * (rhs.Number - mean2.Number)))
- }
- return newNumberFormulaArg(fn.SUM(l3).Number / float64(n-skip-1) / stdev1.Number / stdev2.Number)
- }
- // COUNT function returns the count of numeric values in a supplied set of
- // cells or values. This count includes both numbers and dates. The syntax of
- // the function is:
- //
- // COUNT(value1,[value2],...)
- func (fn *formulaFuncs) COUNT(argsList *list.List) formulaArg {
- var count int
- for token := argsList.Front(); token != nil; token = token.Next() {
- arg := token.Value.(formulaArg)
- switch arg.Type {
- case ArgString:
- if num := arg.ToNumber(); num.Type == ArgNumber {
- count++
- }
- case ArgNumber:
- count++
- case ArgMatrix:
- for _, row := range arg.Matrix {
- for _, cell := range row {
- if cell.Type == ArgNumber {
- count++
- }
- }
- }
- }
- }
- return newNumberFormulaArg(float64(count))
- }
- // COUNTA function returns the number of non-blanks within a supplied set of
- // cells or values. The syntax of the function is:
- //
- // COUNTA(value1,[value2],...)
- func (fn *formulaFuncs) COUNTA(argsList *list.List) formulaArg {
- var count int
- for token := argsList.Front(); token != nil; token = token.Next() {
- arg := token.Value.(formulaArg)
- switch arg.Type {
- case ArgString:
- if arg.String != "" {
- count++
- }
- case ArgNumber:
- count++
- case ArgMatrix:
- for _, row := range arg.ToList() {
- switch row.Type {
- case ArgString:
- if row.String != "" {
- count++
- }
- case ArgNumber:
- count++
- }
- }
- }
- }
- return newNumberFormulaArg(float64(count))
- }
- // COUNTBLANK function returns the number of blank cells in a supplied range.
- // The syntax of the function is:
- //
- // COUNTBLANK(range)
- func (fn *formulaFuncs) COUNTBLANK(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "COUNTBLANK requires 1 argument")
- }
- var count float64
- for _, cell := range argsList.Front().Value.(formulaArg).ToList() {
- if cell.Type == ArgEmpty {
- count++
- }
- }
- return newNumberFormulaArg(count)
- }
- // COUNTIF function returns the number of cells within a supplied range, that
- // satisfy a given criteria. The syntax of the function is:
- //
- // COUNTIF(range,criteria)
- func (fn *formulaFuncs) COUNTIF(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "COUNTIF requires 2 arguments")
- }
- var (
- criteria = formulaCriteriaParser(argsList.Front().Next().Value.(formulaArg).String)
- count float64
- )
- for _, cell := range argsList.Front().Value.(formulaArg).ToList() {
- if ok, _ := formulaCriteriaEval(cell.Value(), criteria); ok {
- count++
- }
- }
- return newNumberFormulaArg(count)
- }
- // formulaIfsMatch function returns cells reference array which match criteria.
- func formulaIfsMatch(args []formulaArg) (cellRefs []cellRef) {
- for i := 0; i < len(args)-1; i += 2 {
- var match []cellRef
- matrix, criteria := args[i].Matrix, formulaCriteriaParser(args[i+1].Value())
- if i == 0 {
- for rowIdx, row := range matrix {
- for colIdx, col := range row {
- if ok, _ := formulaCriteriaEval(col.Value(), criteria); ok {
- match = append(match, cellRef{Col: colIdx, Row: rowIdx})
- }
- }
- }
- } else {
- for _, ref := range cellRefs {
- value := matrix[ref.Row][ref.Col]
- if ok, _ := formulaCriteriaEval(value.Value(), criteria); ok {
- match = append(match, ref)
- }
- }
- }
- if len(match) == 0 {
- return
- }
- cellRefs = match[:]
- }
- return
- }
- // COUNTIFS function returns the number of rows within a table, that satisfy a
- // set of given criteria. The syntax of the function is:
- //
- // COUNTIFS(criteria_range1,criteria1,[criteria_range2,criteria2],...)
- func (fn *formulaFuncs) COUNTIFS(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "COUNTIFS requires at least 2 arguments")
- }
- if argsList.Len()%2 != 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var args []formulaArg
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- args = append(args, arg.Value.(formulaArg))
- }
- return newNumberFormulaArg(float64(len(formulaIfsMatch(args))))
- }
- // CRITBINOM function returns the inverse of the Cumulative Binomial
- // Distribution. I.e. for a specific number of independent trials, the
- // function returns the smallest value (number of successes) for which the
- // cumulative binomial distribution is greater than or equal to a specified
- // value. The syntax of the function is:
- //
- // CRITBINOM(trials,probability_s,alpha)
- func (fn *formulaFuncs) CRITBINOM(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "CRITBINOM requires 3 numeric arguments")
- }
- return fn.BINOMdotINV(argsList)
- }
- // DEVSQ function calculates the sum of the squared deviations from the sample
- // mean. The syntax of the function is:
- //
- // DEVSQ(number1,[number2],...)
- func (fn *formulaFuncs) DEVSQ(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "DEVSQ requires at least 1 numeric argument")
- }
- avg, count, result := fn.AVERAGE(argsList), -1, 0.0
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- for _, cell := range arg.Value.(formulaArg).ToList() {
- if cell.Type != ArgNumber {
- continue
- }
- count++
- if count == 0 {
- result = math.Pow(cell.Number-avg.Number, 2)
- continue
- }
- result += math.Pow(cell.Number-avg.Number, 2)
- }
- }
- if count == -1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(result)
- }
- // FISHER function calculates the Fisher Transformation for a supplied value.
- // The syntax of the function is:
- //
- // FISHER(x)
- func (fn *formulaFuncs) FISHER(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "FISHER requires 1 numeric argument")
- }
- token := argsList.Front().Value.(formulaArg)
- switch token.Type {
- case ArgString:
- arg := token.ToNumber()
- if arg.Type == ArgNumber {
- if arg.Number <= -1 || arg.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(0.5 * math.Log((1+arg.Number)/(1-arg.Number)))
- }
- case ArgNumber:
- if token.Number <= -1 || token.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(0.5 * math.Log((1+token.Number)/(1-token.Number)))
- }
- return newErrorFormulaArg(formulaErrorVALUE, "FISHER requires 1 numeric argument")
- }
- // FISHERINV function calculates the inverse of the Fisher Transformation and
- // returns a value between -1 and +1. The syntax of the function is:
- //
- // FISHERINV(y)
- func (fn *formulaFuncs) FISHERINV(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "FISHERINV requires 1 numeric argument")
- }
- token := argsList.Front().Value.(formulaArg)
- switch token.Type {
- case ArgString:
- arg := token.ToNumber()
- if arg.Type == ArgNumber {
- return newNumberFormulaArg((math.Exp(2*arg.Number) - 1) / (math.Exp(2*arg.Number) + 1))
- }
- case ArgNumber:
- return newNumberFormulaArg((math.Exp(2*token.Number) - 1) / (math.Exp(2*token.Number) + 1))
- }
- return newErrorFormulaArg(formulaErrorVALUE, "FISHERINV requires 1 numeric argument")
- }
- // GAMMA function returns the value of the Gamma Function, Γ(n), for a
- // specified number, n. The syntax of the function is:
- //
- // GAMMA(number)
- func (fn *formulaFuncs) GAMMA(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "GAMMA requires 1 numeric argument")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, "GAMMA requires 1 numeric argument")
- }
- if number.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(math.Gamma(number.Number))
- }
- // GAMMAdotDIST function returns the Gamma Distribution, which is frequently
- // used to provide probabilities for values that may have a skewed
- // distribution, such as queuing analysis.
- //
- // GAMMA.DIST(x,alpha,beta,cumulative)
- func (fn *formulaFuncs) GAMMAdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "GAMMA.DIST requires 4 arguments")
- }
- return fn.GAMMADIST(argsList)
- }
- // GAMMADIST function returns the Gamma Distribution, which is frequently used
- // to provide probabilities for values that may have a skewed distribution,
- // such as queuing analysis.
- //
- // GAMMADIST(x,alpha,beta,cumulative)
- func (fn *formulaFuncs) GAMMADIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "GAMMADIST requires 4 arguments")
- }
- var x, alpha, beta, cumulative formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if x.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if alpha = argsList.Front().Next().Value.(formulaArg).ToNumber(); alpha.Type != ArgNumber {
- return alpha
- }
- if beta = argsList.Back().Prev().Value.(formulaArg).ToNumber(); beta.Type != ArgNumber {
- return beta
- }
- if alpha.Number <= 0 || beta.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError {
- return cumulative
- }
- if cumulative.Number == 1 {
- return newNumberFormulaArg(incompleteGamma(alpha.Number, x.Number/beta.Number) / math.Gamma(alpha.Number))
- }
- return newNumberFormulaArg((1 / (math.Pow(beta.Number, alpha.Number) * math.Gamma(alpha.Number))) * math.Pow(x.Number, alpha.Number-1) * math.Exp(0-(x.Number/beta.Number)))
- }
- // gammainv returns the inverse of the Gamma distribution for the specified
- // value.
- func gammainv(probability, alpha, beta float64) float64 {
- xLo, xHi := 0.0, alpha*beta*5
- dx, x, xNew, result := 1024.0, 1.0, 1.0, 0.0
- for i := 0; math.Abs(dx) > 8.88e-016 && i <= 256; i++ {
- result = incompleteGamma(alpha, x/beta) / math.Gamma(alpha)
- e := result - probability
- if e == 0 {
- dx = 0
- } else if e < 0 {
- xLo = x
- } else {
- xHi = x
- }
- pdf := (1 / (math.Pow(beta, alpha) * math.Gamma(alpha))) * math.Pow(x, alpha-1) * math.Exp(0-(x/beta))
- if pdf != 0 {
- dx = e / pdf
- xNew = x - dx
- }
- if xNew < xLo || xNew > xHi || pdf == 0 {
- xNew = (xLo + xHi) / 2
- dx = xNew - x
- }
- x = xNew
- }
- return x
- }
- // GAMMAdotINV function returns the inverse of the Gamma Cumulative
- // Distribution. The syntax of the function is:
- //
- // GAMMA.INV(probability,alpha,beta)
- func (fn *formulaFuncs) GAMMAdotINV(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "GAMMA.INV requires 3 arguments")
- }
- return fn.GAMMAINV(argsList)
- }
- // GAMMAINV function returns the inverse of the Gamma Cumulative Distribution.
- // The syntax of the function is:
- //
- // GAMMAINV(probability,alpha,beta)
- func (fn *formulaFuncs) GAMMAINV(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "GAMMAINV requires 3 arguments")
- }
- var probability, alpha, beta formulaArg
- if probability = argsList.Front().Value.(formulaArg).ToNumber(); probability.Type != ArgNumber {
- return probability
- }
- if probability.Number < 0 || probability.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if alpha = argsList.Front().Next().Value.(formulaArg).ToNumber(); alpha.Type != ArgNumber {
- return alpha
- }
- if beta = argsList.Back().Value.(formulaArg).ToNumber(); beta.Type != ArgNumber {
- return beta
- }
- if alpha.Number <= 0 || beta.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(gammainv(probability.Number, alpha.Number, beta.Number))
- }
- // GAMMALN function returns the natural logarithm of the Gamma Function, Γ
- // (n). The syntax of the function is:
- //
- // GAMMALN(x)
- func (fn *formulaFuncs) GAMMALN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "GAMMALN requires 1 numeric argument")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, "GAMMALN requires 1 numeric argument")
- }
- if x.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(math.Log(math.Gamma(x.Number)))
- }
- // GAMMALNdotPRECISE function returns the natural logarithm of the Gamma
- // Function, Γ(n). The syntax of the function is:
- //
- // GAMMALN.PRECISE(x)
- func (fn *formulaFuncs) GAMMALNdotPRECISE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "GAMMALN.PRECISE requires 1 numeric argument")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- if x.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(getLogGamma(x.Number))
- }
- // GAUSS function returns the probability that a member of a standard normal
- // population will fall between the mean and a specified number of standard
- // deviations from the mean. The syntax of the function is:
- //
- // GAUSS(z)
- func (fn *formulaFuncs) GAUSS(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "GAUSS requires 1 numeric argument")
- }
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- args.PushBack(formulaArg{Type: ArgNumber, Number: 0})
- args.PushBack(formulaArg{Type: ArgNumber, Number: 1})
- args.PushBack(newBoolFormulaArg(true))
- normdist := fn.NORMDIST(args)
- if normdist.Type != ArgNumber {
- return normdist
- }
- return newNumberFormulaArg(normdist.Number - 0.5)
- }
- // GEOMEAN function calculates the geometric mean of a supplied set of values.
- // The syntax of the function is:
- //
- // GEOMEAN(number1,[number2],...)
- func (fn *formulaFuncs) GEOMEAN(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "GEOMEAN requires at least 1 numeric argument")
- }
- product := fn.PRODUCT(argsList)
- if product.Type != ArgNumber {
- return product
- }
- count := fn.COUNT(argsList)
- min := fn.MIN(argsList)
- if product.Number > 0 && min.Number > 0 {
- return newNumberFormulaArg(math.Pow(product.Number, 1/count.Number))
- }
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- // getNewMatrix create matrix by given columns and rows.
- func getNewMatrix(c, r int) (matrix [][]float64) {
- for i := 0; i < c; i++ {
- for j := 0; j < r; j++ {
- for x := len(matrix); x <= i; x++ {
- matrix = append(matrix, []float64{})
- }
- for y := len(matrix[i]); y <= j; y++ {
- matrix[i] = append(matrix[i], 0)
- }
- matrix[i][j] = 0
- }
- }
- return
- }
- // approxSub subtract two values, if signs are identical and the values are
- // equal, will be returns 0 instead of calculating the subtraction.
- func approxSub(a, b float64) float64 {
- if ((a < 0 && b < 0) || (a > 0 && b > 0)) && math.Abs(a-b) < 2.22045e-016 {
- return 0
- }
- return a - b
- }
- // matrixClone return a copy of all elements of the original matrix.
- func matrixClone(matrix [][]float64) (cloneMatrix [][]float64) {
- for i := 0; i < len(matrix); i++ {
- for j := 0; j < len(matrix[i]); j++ {
- for x := len(cloneMatrix); x <= i; x++ {
- cloneMatrix = append(cloneMatrix, []float64{})
- }
- for k := len(cloneMatrix[i]); k <= j; k++ {
- cloneMatrix[i] = append(cloneMatrix[i], 0)
- }
- cloneMatrix[i][j] = matrix[i][j]
- }
- }
- return
- }
- // trendGrowthMatrixInfo defined matrix checking result.
- type trendGrowthMatrixInfo struct {
- trendType, nCX, nCY, nRX, nRY, M, N int
- mtxX, mtxY [][]float64
- }
- // prepareTrendGrowthMtxX is a part of implementation of the trend growth prepare.
- func prepareTrendGrowthMtxX(mtxX [][]float64) [][]float64 {
- var mtx [][]float64
- for i := 0; i < len(mtxX); i++ {
- for j := 0; j < len(mtxX[i]); j++ {
- if mtxX[i][j] == 0 {
- return nil
- }
- for x := len(mtx); x <= j; x++ {
- mtx = append(mtx, []float64{})
- }
- for y := len(mtx[j]); y <= i; y++ {
- mtx[j] = append(mtx[j], 0)
- }
- mtx[j][i] = mtxX[i][j]
- }
- }
- return mtx
- }
- // prepareTrendGrowthMtxY is a part of implementation of the trend growth prepare.
- func prepareTrendGrowthMtxY(bLOG bool, mtxY [][]float64) [][]float64 {
- var mtx [][]float64
- for i := 0; i < len(mtxY); i++ {
- for j := 0; j < len(mtxY[i]); j++ {
- if mtxY[i][j] == 0 {
- return nil
- }
- for x := len(mtx); x <= j; x++ {
- mtx = append(mtx, []float64{})
- }
- for y := len(mtx[j]); y <= i; y++ {
- mtx[j] = append(mtx[j], 0)
- }
- mtx[j][i] = mtxY[i][j]
- }
- }
- if bLOG {
- var pNewY [][]float64
- for i := 0; i < len(mtxY); i++ {
- for j := 0; j < len(mtxY[i]); j++ {
- fVal := mtxY[i][j]
- if fVal <= 0 {
- return nil
- }
- for x := len(pNewY); x <= j; x++ {
- pNewY = append(pNewY, []float64{})
- }
- for y := len(pNewY[j]); y <= i; y++ {
- pNewY[j] = append(pNewY[j], 0)
- }
- pNewY[j][i] = math.Log(fVal)
- }
- }
- mtx = pNewY
- }
- return mtx
- }
- // prepareTrendGrowth check and return the result.
- func prepareTrendGrowth(bLOG bool, mtxX, mtxY [][]float64) (*trendGrowthMatrixInfo, formulaArg) {
- var nCX, nRX, M, N, trendType int
- nRY, nCY := len(mtxY), len(mtxY[0])
- cntY := nCY * nRY
- newY := prepareTrendGrowthMtxY(bLOG, mtxY)
- if newY == nil {
- return nil, newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- var newX [][]float64
- if len(mtxX) != 0 {
- nRX, nCX = len(mtxX), len(mtxX[0])
- if newX = prepareTrendGrowthMtxX(mtxX); newX == nil {
- return nil, newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if nCX == nCY && nRX == nRY {
- trendType, M, N = 1, 1, cntY // simple regression
- } else if nCY != 1 && nRY != 1 {
- return nil, newErrorFormulaArg(formulaErrorREF, formulaErrorREF)
- } else if nCY == 1 {
- if nRX != nRY {
- return nil, newErrorFormulaArg(formulaErrorREF, formulaErrorREF)
- }
- trendType, M, N = 2, nCX, nRY
- } else if nCX != nCY {
- return nil, newErrorFormulaArg(formulaErrorREF, formulaErrorREF)
- } else {
- trendType, M, N = 3, nRX, nCY
- }
- } else {
- newX = getNewMatrix(nCY, nRY)
- nCX, nRX = nCY, nRY
- num := 1.0
- for i := 0; i < nRY; i++ {
- for j := 0; j < nCY; j++ {
- newX[j][i] = num
- num++
- }
- }
- trendType, M, N = 1, 1, cntY
- }
- return &trendGrowthMatrixInfo{
- trendType: trendType,
- nCX: nCX,
- nCY: nCY,
- nRX: nRX,
- nRY: nRY,
- M: M,
- N: N,
- mtxX: newX,
- mtxY: newY,
- }, newEmptyFormulaArg()
- }
- // calcPosition calculate position for matrix by given index.
- func calcPosition(mtx [][]float64, idx int) (row, col int) {
- rowSize := len(mtx[0])
- col = idx
- if rowSize > 1 {
- col = idx / rowSize
- }
- row = idx - col*rowSize
- return
- }
- // getDouble returns float64 data type value in the matrix by given index.
- func getDouble(mtx [][]float64, idx int) float64 {
- row, col := calcPosition(mtx, idx)
- return mtx[col][row]
- }
- // putDouble set a float64 data type value in the matrix by given index.
- func putDouble(mtx [][]float64, idx int, val float64) {
- row, col := calcPosition(mtx, idx)
- mtx[col][row] = val
- }
- // calcMeanOverAll returns mean of the given matrix by over all element.
- func calcMeanOverAll(mtx [][]float64, n int) float64 {
- var sum float64
- for i := 0; i < len(mtx); i++ {
- for j := 0; j < len(mtx[i]); j++ {
- sum += mtx[i][j]
- }
- }
- return sum / float64(n)
- }
- // calcSumProduct returns uses the matrices as vectors of length M over all
- // element.
- func calcSumProduct(mtxA, mtxB [][]float64, m int) float64 {
- sum := 0.0
- for i := 0; i < m; i++ {
- sum += getDouble(mtxA, i) * getDouble(mtxB, i)
- }
- return sum
- }
- // calcColumnMeans calculates means of the columns of matrix.
- func calcColumnMeans(mtxX, mtxRes [][]float64, c, r int) {
- for i := 0; i < c; i++ {
- var sum float64
- for k := 0; k < r; k++ {
- sum += mtxX[i][k]
- }
- putDouble(mtxRes, i, sum/float64(r))
- }
- }
- // calcColumnsDelta calculates subtract of the columns of matrix.
- func calcColumnsDelta(mtx, columnMeans [][]float64, c, r int) {
- for i := 0; i < c; i++ {
- for k := 0; k < r; k++ {
- mtx[i][k] = approxSub(mtx[i][k], getDouble(columnMeans, i))
- }
- }
- }
- // calcSign returns sign by given value, no mathematical signum, but used to
- // switch between adding and subtracting.
- func calcSign(val float64) float64 {
- if val > 0 {
- return 1
- }
- return -1
- }
- // calcColsMaximumNorm is a special version for use within QR
- // decomposition. Maximum norm of column index c starting in row index r;
- // matrix A has count n rows.
- func calcColsMaximumNorm(mtxA [][]float64, c, r, n int) float64 {
- var norm float64
- for row := r; row < n; row++ {
- if norm < math.Abs(mtxA[c][row]) {
- norm = math.Abs(mtxA[c][row])
- }
- }
- return norm
- }
- // calcFastMult returns multiply n x m matrix A with m x l matrix B to n x l matrix R.
- func calcFastMult(mtxA, mtxB, mtxR [][]float64, n, m, l int) {
- var sum float64
- for row := 0; row < n; row++ {
- for col := 0; col < l; col++ {
- sum = 0.0
- for k := 0; k < m; k++ {
- sum += mtxA[k][row] * mtxB[col][k]
- }
- mtxR[col][row] = sum
- }
- }
- }
- // calcRowsEuclideanNorm is a special version for use within QR
- // decomposition. Euclidean norm of column index c starting in row index r;
- // matrix a has count n rows.
- func calcRowsEuclideanNorm(mtxA [][]float64, c, r, n int) float64 {
- var norm float64
- for row := r; row < n; row++ {
- norm += mtxA[c][row] * mtxA[c][row]
- }
- return math.Sqrt(norm)
- }
- // calcRowsSumProduct is a special version for use within QR decomposition.
- // <A(a);B(b)> starting in row index r;
- // a and b are indices of columns, matrices A and B have count n rows.
- func calcRowsSumProduct(mtxA [][]float64, a int, mtxB [][]float64, b, r, n int) float64 {
- var result float64
- for row := r; row < n; row++ {
- result += mtxA[a][row] * mtxB[b][row]
- }
- return result
- }
- // calcSolveWithUpperRightTriangle solve for X in R*X=S using back substitution.
- func calcSolveWithUpperRightTriangle(mtxA [][]float64, vecR []float64, mtxS [][]float64, k int, bIsTransposed bool) {
- var row int
- for rowp1 := k; rowp1 > 0; rowp1-- {
- row = rowp1 - 1
- sum := getDouble(mtxS, row)
- for col := rowp1; col < k; col++ {
- if bIsTransposed {
- sum -= mtxA[row][col] * getDouble(mtxS, col)
- } else {
- sum -= mtxA[col][row] * getDouble(mtxS, col)
- }
- }
- putDouble(mtxS, row, sum/vecR[row])
- }
- }
- // calcRowQRDecomposition calculates a QR decomposition with Householder
- // reflection.
- func calcRowQRDecomposition(mtxA [][]float64, vecR []float64, k, n int) bool {
- for col := 0; col < k; col++ {
- scale := calcColsMaximumNorm(mtxA, col, col, n)
- if scale == 0 {
- return false
- }
- for row := col; row < n; row++ {
- mtxA[col][row] = mtxA[col][row] / scale
- }
- euclid := calcRowsEuclideanNorm(mtxA, col, col, n)
- factor := 1.0 / euclid / (euclid + math.Abs(mtxA[col][col]))
- signum := calcSign(mtxA[col][col])
- mtxA[col][col] = mtxA[col][col] + signum*euclid
- vecR[col] = -signum * scale * euclid
- // apply Householder transformation to A
- for c := col + 1; c < k; c++ {
- sum := calcRowsSumProduct(mtxA, col, mtxA, c, col, n)
- for row := col; row < n; row++ {
- mtxA[c][row] = mtxA[c][row] - sum*factor*mtxA[col][row]
- }
- }
- }
- return true
- }
- // calcApplyColsHouseholderTransformation transposed matrices A and Y.
- func calcApplyColsHouseholderTransformation(mtxA [][]float64, r int, mtxY [][]float64, n int) {
- denominator := calcColsSumProduct(mtxA, r, mtxA, r, r, n)
- numerator := calcColsSumProduct(mtxA, r, mtxY, 0, r, n)
- factor := 2 * (numerator / denominator)
- for col := r; col < n; col++ {
- putDouble(mtxY, col, getDouble(mtxY, col)-factor*mtxA[col][r])
- }
- }
- // calcRowMeans calculates means of the rows of matrix.
- func calcRowMeans(mtxX, mtxRes [][]float64, c, r int) {
- for k := 0; k < r; k++ {
- var fSum float64
- for i := 0; i < c; i++ {
- fSum += mtxX[i][k]
- }
- mtxRes[k][0] = fSum / float64(c)
- }
- }
- // calcRowsDelta calculates subtract of the rows of matrix.
- func calcRowsDelta(mtx, rowMeans [][]float64, c, r int) {
- for k := 0; k < r; k++ {
- for i := 0; i < c; i++ {
- mtx[i][k] = approxSub(mtx[i][k], rowMeans[k][0])
- }
- }
- }
- // calcColumnMaximumNorm returns maximum norm of row index R starting in col
- // index C; matrix A has count N columns.
- func calcColumnMaximumNorm(mtxA [][]float64, r, c, n int) float64 {
- var norm float64
- for col := c; col < n; col++ {
- if norm < math.Abs(mtxA[col][r]) {
- norm = math.Abs(mtxA[col][r])
- }
- }
- return norm
- }
- // calcColsEuclideanNorm returns euclidean norm of row index R starting in
- // column index C; matrix A has count N columns.
- func calcColsEuclideanNorm(mtxA [][]float64, r, c, n int) float64 {
- var norm float64
- for col := c; col < n; col++ {
- norm += (mtxA[col][r]) * (mtxA[col][r])
- }
- return math.Sqrt(norm)
- }
- // calcColsSumProduct returns sum product for given matrix.
- func calcColsSumProduct(mtxA [][]float64, a int, mtxB [][]float64, b, c, n int) float64 {
- var result float64
- for col := c; col < n; col++ {
- result += mtxA[col][a] * mtxB[col][b]
- }
- return result
- }
- // calcColQRDecomposition same with transposed matrix A, N is count of
- // columns, k count of rows.
- func calcColQRDecomposition(mtxA [][]float64, vecR []float64, k, n int) bool {
- var sum float64
- for row := 0; row < k; row++ {
- // calculate vector u of the householder transformation
- scale := calcColumnMaximumNorm(mtxA, row, row, n)
- if scale == 0 {
- return false
- }
- for col := row; col < n; col++ {
- mtxA[col][row] = mtxA[col][row] / scale
- }
- euclid := calcColsEuclideanNorm(mtxA, row, row, n)
- factor := 1 / euclid / (euclid + math.Abs(mtxA[row][row]))
- signum := calcSign(mtxA[row][row])
- mtxA[row][row] = mtxA[row][row] + signum*euclid
- vecR[row] = -signum * scale * euclid
- // apply Householder transformation to A
- for r := row + 1; r < k; r++ {
- sum = calcColsSumProduct(mtxA, row, mtxA, r, row, n)
- for col := row; col < n; col++ {
- mtxA[col][r] = mtxA[col][r] - sum*factor*mtxA[col][row]
- }
- }
- }
- return true
- }
- // calcApplyRowsHouseholderTransformation applies a Householder transformation to a
- // column vector Y with is given as Nx1 Matrix. The vector u, from which the
- // Householder transformation is built, is the column part in matrix A, with
- // column index c, starting with row index c. A is the result of the QR
- // decomposition as obtained from calcRowQRDecomposition.
- func calcApplyRowsHouseholderTransformation(mtxA [][]float64, c int, mtxY [][]float64, n int) {
- denominator := calcRowsSumProduct(mtxA, c, mtxA, c, c, n)
- numerator := calcRowsSumProduct(mtxA, c, mtxY, 0, c, n)
- factor := 2 * (numerator / denominator)
- for row := c; row < n; row++ {
- putDouble(mtxY, row, getDouble(mtxY, row)-factor*mtxA[c][row])
- }
- }
- // calcTrendGrowthSimpleRegression calculate simple regression for the calcTrendGrowth.
- func calcTrendGrowthSimpleRegression(bConstant, bGrowth bool, mtxY, mtxX, newX, mtxRes [][]float64, meanY float64, N int) {
- var meanX float64
- if bConstant {
- meanX = calcMeanOverAll(mtxX, N)
- for i := 0; i < len(mtxX); i++ {
- for j := 0; j < len(mtxX[i]); j++ {
- mtxX[i][j] = approxSub(mtxX[i][j], meanX)
- }
- }
- }
- sumXY := calcSumProduct(mtxX, mtxY, N)
- sumX2 := calcSumProduct(mtxX, mtxX, N)
- slope := sumXY / sumX2
- var help float64
- var intercept float64
- if bConstant {
- intercept = meanY - slope*meanX
- for i := 0; i < len(mtxRes); i++ {
- for j := 0; j < len(mtxRes[i]); j++ {
- help = newX[i][j]*slope + intercept
- if bGrowth {
- mtxRes[i][j] = math.Exp(help)
- } else {
- mtxRes[i][j] = help
- }
- }
- }
- } else {
- for i := 0; i < len(mtxRes); i++ {
- for j := 0; j < len(mtxRes[i]); j++ {
- help = newX[i][j] * slope
- if bGrowth {
- mtxRes[i][j] = math.Exp(help)
- } else {
- mtxRes[i][j] = help
- }
- }
- }
- }
- }
- // calcTrendGrowthMultipleRegressionPart1 calculate multiple regression for the
- // calcTrendGrowth.
- func calcTrendGrowthMultipleRegressionPart1(bConstant, bGrowth bool, mtxY, mtxX, newX, mtxRes [][]float64, meanY float64, RXN, K, N int) {
- vecR := make([]float64, N) // for QR decomposition
- means := getNewMatrix(K, 1) // mean of each column
- slopes := getNewMatrix(1, K) // from b1 to bK
- if len(means) == 0 || len(slopes) == 0 {
- return
- }
- if bConstant {
- calcColumnMeans(mtxX, means, K, N)
- calcColumnsDelta(mtxX, means, K, N)
- }
- if !calcRowQRDecomposition(mtxX, vecR, K, N) {
- return
- }
- // Later on we will divide by elements of vecR, so make sure that they aren't zero.
- bIsSingular := false
- for row := 0; row < K && !bIsSingular; row++ {
- bIsSingular = bIsSingular || vecR[row] == 0
- }
- if bIsSingular {
- return
- }
- for col := 0; col < K; col++ {
- calcApplyRowsHouseholderTransformation(mtxX, col, mtxY, N)
- }
- for col := 0; col < K; col++ {
- putDouble(slopes, col, getDouble(mtxY, col))
- }
- calcSolveWithUpperRightTriangle(mtxX, vecR, slopes, K, false)
- // Fill result matrix
- calcFastMult(newX, slopes, mtxRes, RXN, K, 1)
- if bConstant {
- intercept := meanY - calcSumProduct(means, slopes, K)
- for row := 0; row < RXN; row++ {
- mtxRes[0][row] = mtxRes[0][row] + intercept
- }
- }
- if bGrowth {
- for i := 0; i < RXN; i++ {
- putDouble(mtxRes, i, math.Exp(getDouble(mtxRes, i)))
- }
- }
- }
- // calcTrendGrowthMultipleRegressionPart2 calculate multiple regression for the
- // calcTrendGrowth.
- func calcTrendGrowthMultipleRegressionPart2(bConstant, bGrowth bool, mtxY, mtxX, newX, mtxRes [][]float64, meanY float64, nCXN, K, N int) {
- vecR := make([]float64, N) // for QR decomposition
- means := getNewMatrix(K, 1) // mean of each row
- slopes := getNewMatrix(K, 1) // row from b1 to bK
- if len(means) == 0 || len(slopes) == 0 {
- return
- }
- if bConstant {
- calcRowMeans(mtxX, means, N, K)
- calcRowsDelta(mtxX, means, N, K)
- }
- if !calcColQRDecomposition(mtxX, vecR, K, N) {
- return
- }
- // later on we will divide by elements of vecR, so make sure that they aren't zero
- bIsSingular := false
- for row := 0; row < K && !bIsSingular; row++ {
- bIsSingular = bIsSingular || vecR[row] == 0
- }
- if bIsSingular {
- return
- }
- for row := 0; row < K; row++ {
- calcApplyColsHouseholderTransformation(mtxX, row, mtxY, N)
- }
- for col := 0; col < K; col++ {
- putDouble(slopes, col, getDouble(mtxY, col))
- }
- calcSolveWithUpperRightTriangle(mtxX, vecR, slopes, K, true)
- // fill result matrix
- calcFastMult(slopes, newX, mtxRes, 1, K, nCXN)
- if bConstant {
- fIntercept := meanY - calcSumProduct(means, slopes, K)
- for col := 0; col < nCXN; col++ {
- mtxRes[col][0] = mtxRes[col][0] + fIntercept
- }
- }
- if bGrowth {
- for i := 0; i < nCXN; i++ {
- putDouble(mtxRes, i, math.Exp(getDouble(mtxRes, i)))
- }
- }
- }
- // calcTrendGrowthRegression is a part of implementation of the calcTrendGrowth.
- func calcTrendGrowthRegression(bConstant, bGrowth bool, trendType, nCXN, nRXN, K, N int, mtxY, mtxX, newX, mtxRes [][]float64) {
- if len(mtxRes) == 0 {
- return
- }
- var meanY float64
- if bConstant {
- copyX, copyY := matrixClone(mtxX), matrixClone(mtxY)
- mtxX, mtxY = copyX, copyY
- meanY = calcMeanOverAll(mtxY, N)
- for i := 0; i < len(mtxY); i++ {
- for j := 0; j < len(mtxY[i]); j++ {
- mtxY[i][j] = approxSub(mtxY[i][j], meanY)
- }
- }
- }
- switch trendType {
- case 1:
- calcTrendGrowthSimpleRegression(bConstant, bGrowth, mtxY, mtxX, newX, mtxRes, meanY, N)
- case 2:
- calcTrendGrowthMultipleRegressionPart1(bConstant, bGrowth, mtxY, mtxX, newX, mtxRes, meanY, nRXN, K, N)
- default:
- calcTrendGrowthMultipleRegressionPart2(bConstant, bGrowth, mtxY, mtxX, newX, mtxRes, meanY, nCXN, K, N)
- }
- }
- // calcTrendGrowth returns values along a predicted exponential trend.
- func calcTrendGrowth(mtxY, mtxX, newX [][]float64, bConstant, bGrowth bool) ([][]float64, formulaArg) {
- getMatrixParams, errArg := prepareTrendGrowth(bGrowth, mtxX, mtxY)
- if errArg.Type != ArgEmpty {
- return nil, errArg
- }
- trendType := getMatrixParams.trendType
- nCX := getMatrixParams.nCX
- nRX := getMatrixParams.nRX
- K := getMatrixParams.M
- N := getMatrixParams.N
- mtxX = getMatrixParams.mtxX
- mtxY = getMatrixParams.mtxY
- // checking if data samples are enough
- if (bConstant && (N < K+1)) || (!bConstant && (N < K)) || (N < 1) || (K < 1) {
- return nil, errArg
- }
- // set the default newX if necessary
- nCXN, nRXN := nCX, nRX
- if len(newX) == 0 {
- newX = matrixClone(mtxX) // mtxX will be changed to X-meanX
- } else {
- nRXN, nCXN = len(newX[0]), len(newX)
- if (trendType == 2 && K != nCXN) || (trendType == 3 && K != nRXN) {
- return nil, errArg
- }
- }
- var mtxRes [][]float64
- switch trendType {
- case 1:
- mtxRes = getNewMatrix(nCXN, nRXN)
- case 2:
- mtxRes = getNewMatrix(1, nRXN)
- default:
- mtxRes = getNewMatrix(nCXN, 1)
- }
- calcTrendGrowthRegression(bConstant, bGrowth, trendType, nCXN, nRXN, K, N, mtxY, mtxX, newX, mtxRes)
- return mtxRes, errArg
- }
- // trendGrowth is an implementation of the formula functions GROWTH and TREND.
- func (fn *formulaFuncs) trendGrowth(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
- }
- if argsList.Len() > 4 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s allows at most 4 arguments", name))
- }
- var knowY, knowX, newX [][]float64
- var errArg formulaArg
- constArg := newBoolFormulaArg(true)
- knowY, errArg = newNumberMatrix(argsList.Front().Value.(formulaArg), false)
- if errArg.Type == ArgError {
- return errArg
- }
- if argsList.Len() > 1 {
- knowX, errArg = newNumberMatrix(argsList.Front().Next().Value.(formulaArg), false)
- if errArg.Type == ArgError {
- return errArg
- }
- }
- if argsList.Len() > 2 {
- newX, errArg = newNumberMatrix(argsList.Front().Next().Next().Value.(formulaArg), false)
- if errArg.Type == ArgError {
- return errArg
- }
- }
- if argsList.Len() > 3 {
- if constArg = argsList.Back().Value.(formulaArg).ToBool(); constArg.Type != ArgNumber {
- return constArg
- }
- }
- var mtxNewX [][]float64
- for i := 0; i < len(newX); i++ {
- for j := 0; j < len(newX[i]); j++ {
- for x := len(mtxNewX); x <= j; x++ {
- mtxNewX = append(mtxNewX, []float64{})
- }
- for k := len(mtxNewX[j]); k <= i; k++ {
- mtxNewX[j] = append(mtxNewX[j], 0)
- }
- mtxNewX[j][i] = newX[i][j]
- }
- }
- mtx, errArg := calcTrendGrowth(knowY, knowX, mtxNewX, constArg.Number == 1, name == "GROWTH")
- if errArg.Type != ArgEmpty {
- return errArg
- }
- return newMatrixFormulaArg(newFormulaArgMatrix(mtx))
- }
- // GROWTH function calculates the exponential growth curve through a given set
- // of y-values and (optionally), one or more sets of x-values. The function
- // then extends the curve to calculate additional y-values for a further
- // supplied set of new x-values. The syntax of the function is:
- //
- // GROWTH(known_y's,[known_x's],[new_x's],[const])
- func (fn *formulaFuncs) GROWTH(argsList *list.List) formulaArg {
- return fn.trendGrowth("GROWTH", argsList)
- }
- // HARMEAN function calculates the harmonic mean of a supplied set of values.
- // The syntax of the function is:
- //
- // HARMEAN(number1,[number2],...)
- func (fn *formulaFuncs) HARMEAN(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "HARMEAN requires at least 1 argument")
- }
- if min := fn.MIN(argsList); min.Number < 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- number, val, cnt := 0.0, 0.0, 0.0
- for token := argsList.Front(); token != nil; token = token.Next() {
- arg := token.Value.(formulaArg)
- switch arg.Type {
- case ArgString:
- num := arg.ToNumber()
- if num.Type != ArgNumber {
- continue
- }
- number = num.Number
- case ArgNumber:
- number = arg.Number
- }
- if number <= 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- val += 1 / number
- cnt++
- }
- return newNumberFormulaArg(1 / (val / cnt))
- }
- // checkHYPGEOMDISTArgs checking arguments for the formula function HYPGEOMDIST
- // and HYPGEOM.DIST.
- func checkHYPGEOMDISTArgs(sampleS, numberSample, populationS, numberPop formulaArg) bool {
- return sampleS.Number < 0 ||
- sampleS.Number > math.Min(numberSample.Number, populationS.Number) ||
- sampleS.Number < math.Max(0, numberSample.Number-numberPop.Number+populationS.Number) ||
- numberSample.Number <= 0 ||
- numberSample.Number > numberPop.Number ||
- populationS.Number <= 0 ||
- populationS.Number > numberPop.Number ||
- numberPop.Number <= 0
- }
- // prepareHYPGEOMDISTArgs prepare arguments for the formula function
- // HYPGEOMDIST and HYPGEOM.DIST.
- func (fn *formulaFuncs) prepareHYPGEOMDISTArgs(name string, argsList *list.List) formulaArg {
- if name == "HYPGEOMDIST" && argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "HYPGEOMDIST requires 4 numeric arguments")
- }
- if name == "HYPGEOM.DIST" && argsList.Len() != 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "HYPGEOM.DIST requires 5 arguments")
- }
- var sampleS, numberSample, populationS, numberPop, cumulative formulaArg
- if sampleS = argsList.Front().Value.(formulaArg).ToNumber(); sampleS.Type != ArgNumber {
- return sampleS
- }
- if numberSample = argsList.Front().Next().Value.(formulaArg).ToNumber(); numberSample.Type != ArgNumber {
- return numberSample
- }
- if populationS = argsList.Front().Next().Next().Value.(formulaArg).ToNumber(); populationS.Type != ArgNumber {
- return populationS
- }
- if numberPop = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); numberPop.Type != ArgNumber {
- return numberPop
- }
- if checkHYPGEOMDISTArgs(sampleS, numberSample, populationS, numberPop) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if name == "HYPGEOM.DIST" {
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type != ArgNumber {
- return cumulative
- }
- }
- return newListFormulaArg([]formulaArg{sampleS, numberSample, populationS, numberPop, cumulative})
- }
- // HYPGEOMdotDIST function returns the value of the hypergeometric distribution
- // for a specified number of successes from a population sample. The function
- // can calculate the cumulative distribution or the probability density
- // function. The syntax of the function is:
- //
- // HYPGEOM.DIST(sample_s,number_sample,population_s,number_pop,cumulative)
- func (fn *formulaFuncs) HYPGEOMdotDIST(argsList *list.List) formulaArg {
- args := fn.prepareHYPGEOMDISTArgs("HYPGEOM.DIST", argsList)
- if args.Type != ArgList {
- return args
- }
- sampleS, numberSample, populationS, numberPop, cumulative := args.List[0], args.List[1], args.List[2], args.List[3], args.List[4]
- if cumulative.Number == 1 {
- var res float64
- for i := 0; i <= int(sampleS.Number); i++ {
- res += binomCoeff(populationS.Number, float64(i)) *
- binomCoeff(numberPop.Number-populationS.Number, numberSample.Number-float64(i)) /
- binomCoeff(numberPop.Number, numberSample.Number)
- }
- return newNumberFormulaArg(res)
- }
- return newNumberFormulaArg(binomCoeff(populationS.Number, sampleS.Number) *
- binomCoeff(numberPop.Number-populationS.Number, numberSample.Number-sampleS.Number) /
- binomCoeff(numberPop.Number, numberSample.Number))
- }
- // HYPGEOMDIST function returns the value of the hypergeometric distribution
- // for a given number of successes from a sample of a population. The syntax
- // of the function is:
- //
- // HYPGEOMDIST(sample_s,number_sample,population_s,number_pop)
- func (fn *formulaFuncs) HYPGEOMDIST(argsList *list.List) formulaArg {
- args := fn.prepareHYPGEOMDISTArgs("HYPGEOMDIST", argsList)
- if args.Type != ArgList {
- return args
- }
- sampleS, numberSample, populationS, numberPop := args.List[0], args.List[1], args.List[2], args.List[3]
- return newNumberFormulaArg(binomCoeff(populationS.Number, sampleS.Number) *
- binomCoeff(numberPop.Number-populationS.Number, numberSample.Number-sampleS.Number) /
- binomCoeff(numberPop.Number, numberSample.Number))
- }
- // KURT function calculates the kurtosis of a supplied set of values. The
- // syntax of the function is:
- //
- // KURT(number1,[number2],...)
- func (fn *formulaFuncs) KURT(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "KURT requires at least 1 argument")
- }
- mean, stdev := fn.AVERAGE(argsList), fn.STDEV(argsList)
- if stdev.Number > 0 {
- count, summer := 0.0, 0.0
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgString, ArgNumber:
- num := token.ToNumber()
- if num.Type == ArgError {
- continue
- }
- summer += math.Pow((num.Number-mean.Number)/stdev.Number, 4)
- count++
- case ArgList, ArgMatrix:
- for _, row := range token.ToList() {
- if row.Type == ArgNumber || row.Type == ArgString {
- num := row.ToNumber()
- if num.Type == ArgError {
- continue
- }
- summer += math.Pow((num.Number-mean.Number)/stdev.Number, 4)
- count++
- }
- }
- }
- }
- if count > 3 {
- return newNumberFormulaArg(summer*(count*(count+1)/((count-1)*(count-2)*(count-3))) - (3 * math.Pow(count-1, 2) / ((count - 2) * (count - 3))))
- }
- }
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- // EXPONdotDIST function returns the value of the exponential distribution for
- // a give value of x. The user can specify whether the probability density
- // function or the cumulative distribution function is used. The syntax of the
- // Expondist function is:
- //
- // EXPON.DIST(x,lambda,cumulative)
- func (fn *formulaFuncs) EXPONdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "EXPON.DIST requires 3 arguments")
- }
- return fn.EXPONDIST(argsList)
- }
- // EXPONDIST function returns the value of the exponential distribution for a
- // give value of x. The user can specify whether the probability density
- // function or the cumulative distribution function is used. The syntax of the
- // Expondist function is:
- //
- // EXPONDIST(x,lambda,cumulative)
- func (fn *formulaFuncs) EXPONDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "EXPONDIST requires 3 arguments")
- }
- var x, lambda, cumulative formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if lambda = argsList.Front().Next().Value.(formulaArg).ToNumber(); lambda.Type != ArgNumber {
- return lambda
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError {
- return cumulative
- }
- if x.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if lambda.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if cumulative.Number == 1 {
- return newNumberFormulaArg(1 - math.Exp(-lambda.Number*x.Number))
- }
- return newNumberFormulaArg(lambda.Number * math.Exp(-lambda.Number*x.Number))
- }
- // FdotDIST function calculates the Probability Density Function or the
- // Cumulative Distribution Function for the F Distribution. This function is
- // frequently used to measure the degree of diversity between two data
- // sets. The syntax of the function is:
- //
- // F.DIST(x,deg_freedom1,deg_freedom2,cumulative)
- func (fn *formulaFuncs) FdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "F.DIST requires 4 arguments")
- }
- var x, deg1, deg2, cumulative formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if deg1 = argsList.Front().Next().Value.(formulaArg).ToNumber(); deg1.Type != ArgNumber {
- return deg1
- }
- if deg2 = argsList.Front().Next().Next().Value.(formulaArg).ToNumber(); deg2.Type != ArgNumber {
- return deg2
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError {
- return cumulative
- }
- if x.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- maxDeg := math.Pow10(10)
- if deg1.Number < 1 || deg1.Number >= maxDeg {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if deg2.Number < 1 || deg2.Number >= maxDeg {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if cumulative.Number == 1 {
- return newNumberFormulaArg(1 - getBetaDist(deg2.Number/(deg2.Number+deg1.Number*x.Number), deg2.Number/2, deg1.Number/2))
- }
- return newNumberFormulaArg(math.Gamma((deg2.Number+deg1.Number)/2) / (math.Gamma(deg1.Number/2) * math.Gamma(deg2.Number/2)) * math.Pow(deg1.Number/deg2.Number, deg1.Number/2) * (math.Pow(x.Number, (deg1.Number-2)/2) / math.Pow(1+(deg1.Number/deg2.Number)*x.Number, (deg1.Number+deg2.Number)/2)))
- }
- // FDIST function calculates the (right-tailed) F Probability Distribution,
- // which measures the degree of diversity between two data sets. The syntax
- // of the function is:
- //
- // FDIST(x,deg_freedom1,deg_freedom2)
- func (fn *formulaFuncs) FDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "FDIST requires 3 arguments")
- }
- var x, deg1, deg2 formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if deg1 = argsList.Front().Next().Value.(formulaArg).ToNumber(); deg1.Type != ArgNumber {
- return deg1
- }
- if deg2 = argsList.Back().Value.(formulaArg).ToNumber(); deg2.Type != ArgNumber {
- return deg2
- }
- if x.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- maxDeg := math.Pow10(10)
- if deg1.Number < 1 || deg1.Number >= maxDeg {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if deg2.Number < 1 || deg2.Number >= maxDeg {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- args := list.New()
- args.PushBack(newNumberFormulaArg(deg1.Number * x.Number / (deg1.Number*x.Number + deg2.Number)))
- args.PushBack(newNumberFormulaArg(0.5 * deg1.Number))
- args.PushBack(newNumberFormulaArg(0.5 * deg2.Number))
- args.PushBack(newNumberFormulaArg(0))
- args.PushBack(newNumberFormulaArg(1))
- return newNumberFormulaArg(1 - fn.BETADIST(args).Number)
- }
- // FdotDISTdotRT function calculates the (right-tailed) F Probability
- // Distribution, which measures the degree of diversity between two data sets.
- // The syntax of the function is:
- //
- // F.DIST.RT(x,deg_freedom1,deg_freedom2)
- func (fn *formulaFuncs) FdotDISTdotRT(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "F.DIST.RT requires 3 arguments")
- }
- return fn.FDIST(argsList)
- }
- // prepareFinvArgs checking and prepare arguments for the formula function
- // F.INV, F.INV.RT and FINV.
- func (fn *formulaFuncs) prepareFinvArgs(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 3 arguments", name))
- }
- var probability, d1, d2 formulaArg
- if probability = argsList.Front().Value.(formulaArg).ToNumber(); probability.Type != ArgNumber {
- return probability
- }
- if d1 = argsList.Front().Next().Value.(formulaArg).ToNumber(); d1.Type != ArgNumber {
- return d1
- }
- if d2 = argsList.Back().Value.(formulaArg).ToNumber(); d2.Type != ArgNumber {
- return d2
- }
- if probability.Number <= 0 || probability.Number > 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if d1.Number < 1 || d1.Number >= math.Pow10(10) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if d2.Number < 1 || d2.Number >= math.Pow10(10) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newListFormulaArg([]formulaArg{probability, d1, d2})
- }
- // FdotINV function calculates the inverse of the Cumulative F Distribution
- // for a supplied probability. The syntax of the F.Inv function is:
- //
- // F.INV(probability,deg_freedom1,deg_freedom2)
- func (fn *formulaFuncs) FdotINV(argsList *list.List) formulaArg {
- args := fn.prepareFinvArgs("F.INV", argsList)
- if args.Type != ArgList {
- return args
- }
- probability, d1, d2 := args.List[0], args.List[1], args.List[2]
- return newNumberFormulaArg((1/calcBetainv(1-probability.Number, d2.Number/2, d1.Number/2, 0, 1) - 1) * (d2.Number / d1.Number))
- }
- // FdotINVdotRT function calculates the inverse of the (right-tailed) F
- // Probability Distribution for a supplied probability. The syntax of the
- // function is:
- //
- // F.INV.RT(probability,deg_freedom1,deg_freedom2)
- func (fn *formulaFuncs) FdotINVdotRT(argsList *list.List) formulaArg {
- args := fn.prepareFinvArgs("F.INV.RT", argsList)
- if args.Type != ArgList {
- return args
- }
- probability, d1, d2 := args.List[0], args.List[1], args.List[2]
- return newNumberFormulaArg((1/calcBetainv(1-(1-probability.Number), d2.Number/2, d1.Number/2, 0, 1) - 1) * (d2.Number / d1.Number))
- }
- // FINV function calculates the inverse of the (right-tailed) F Probability
- // Distribution for a supplied probability. The syntax of the function is:
- //
- // FINV(probability,deg_freedom1,deg_freedom2)
- func (fn *formulaFuncs) FINV(argsList *list.List) formulaArg {
- args := fn.prepareFinvArgs("FINV", argsList)
- if args.Type != ArgList {
- return args
- }
- probability, d1, d2 := args.List[0], args.List[1], args.List[2]
- return newNumberFormulaArg((1/calcBetainv(1-(1-probability.Number), d2.Number/2, d1.Number/2, 0, 1) - 1) * (d2.Number / d1.Number))
- }
- // FdotTEST function returns the F-Test for two supplied arrays. I.e. the
- // function returns the two-tailed probability that the variances in the two
- // supplied arrays are not significantly different. The syntax of the Ftest
- // function is:
- //
- // F.TEST(array1,array2)
- func (fn *formulaFuncs) FdotTEST(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "F.TEST requires 2 arguments")
- }
- array1 := argsList.Front().Value.(formulaArg)
- array2 := argsList.Back().Value.(formulaArg)
- left, right := array1.ToList(), array2.ToList()
- collectMatrix := func(args []formulaArg) (n, accu float64) {
- var p, sum float64
- for _, arg := range args {
- if num := arg.ToNumber(); num.Type == ArgNumber {
- x := num.Number - p
- y := x / (n + 1)
- p += y
- accu += n * x * y
- n++
- sum += num.Number
- }
- }
- return
- }
- nums, accu := collectMatrix(left)
- f3 := nums - 1
- if nums == 1 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- f1 := accu / (nums - 1)
- if f1 == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- nums, accu = collectMatrix(right)
- f4 := nums - 1
- if nums == 1 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- f2 := accu / (nums - 1)
- if f2 == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- args := list.New()
- args.PushBack(newNumberFormulaArg(f1 / f2))
- args.PushBack(newNumberFormulaArg(f3))
- args.PushBack(newNumberFormulaArg(f4))
- probability := (1 - fn.FDIST(args).Number) * 2
- if probability > 1 {
- probability = 2 - probability
- }
- return newNumberFormulaArg(probability)
- }
- // FTEST function returns the F-Test for two supplied arrays. I.e. the function
- // returns the two-tailed probability that the variances in the two supplied
- // arrays are not significantly different. The syntax of the Ftest function
- // is:
- //
- // FTEST(array1,array2)
- func (fn *formulaFuncs) FTEST(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "FTEST requires 2 arguments")
- }
- return fn.FdotTEST(argsList)
- }
- // LOGINV function calculates the inverse of the Cumulative Log-Normal
- // Distribution Function of x, for a supplied probability. The syntax of the
- // function is:
- //
- // LOGINV(probability,mean,standard_dev)
- func (fn *formulaFuncs) LOGINV(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOGINV requires 3 arguments")
- }
- var probability, mean, stdDev formulaArg
- if probability = argsList.Front().Value.(formulaArg).ToNumber(); probability.Type != ArgNumber {
- return probability
- }
- if mean = argsList.Front().Next().Value.(formulaArg).ToNumber(); mean.Type != ArgNumber {
- return mean
- }
- if stdDev = argsList.Back().Value.(formulaArg).ToNumber(); stdDev.Type != ArgNumber {
- return stdDev
- }
- if probability.Number <= 0 || probability.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if stdDev.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- args := list.New()
- args.PushBack(probability)
- args.PushBack(newNumberFormulaArg(0))
- args.PushBack(newNumberFormulaArg(1))
- norminv := fn.NORMINV(args)
- return newNumberFormulaArg(math.Exp(mean.Number + stdDev.Number*norminv.Number))
- }
- // LOGNORMdotINV function calculates the inverse of the Cumulative Log-Normal
- // Distribution Function of x, for a supplied probability. The syntax of the
- // function is:
- //
- // LOGNORM.INV(probability,mean,standard_dev)
- func (fn *formulaFuncs) LOGNORMdotINV(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOGNORM.INV requires 3 arguments")
- }
- return fn.LOGINV(argsList)
- }
- // LOGNORMdotDIST function calculates the Log-Normal Probability Density
- // Function or the Cumulative Log-Normal Distribution Function for a supplied
- // value of x. The syntax of the function is:
- //
- // LOGNORM.DIST(x,mean,standard_dev,cumulative)
- func (fn *formulaFuncs) LOGNORMdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOGNORM.DIST requires 4 arguments")
- }
- var x, mean, stdDev, cumulative formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if mean = argsList.Front().Next().Value.(formulaArg).ToNumber(); mean.Type != ArgNumber {
- return mean
- }
- if stdDev = argsList.Back().Prev().Value.(formulaArg).ToNumber(); stdDev.Type != ArgNumber {
- return stdDev
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError {
- return cumulative
- }
- if x.Number <= 0 || stdDev.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if cumulative.Number == 1 {
- args := list.New()
- args.PushBack(newNumberFormulaArg((math.Log(x.Number) - mean.Number) / stdDev.Number))
- args.PushBack(newNumberFormulaArg(0))
- args.PushBack(newNumberFormulaArg(1))
- args.PushBack(cumulative)
- return fn.NORMDIST(args)
- }
- return newNumberFormulaArg((1 / (math.Sqrt(2*math.Pi) * stdDev.Number * x.Number)) *
- math.Exp(0-(math.Pow(math.Log(x.Number)-mean.Number, 2)/(2*math.Pow(stdDev.Number, 2)))))
- }
- // LOGNORMDIST function calculates the Cumulative Log-Normal Distribution
- // Function at a supplied value of x. The syntax of the function is:
- //
- // LOGNORMDIST(x,mean,standard_dev)
- func (fn *formulaFuncs) LOGNORMDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOGNORMDIST requires 3 arguments")
- }
- var x, mean, stdDev formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if mean = argsList.Front().Next().Value.(formulaArg).ToNumber(); mean.Type != ArgNumber {
- return mean
- }
- if stdDev = argsList.Back().Value.(formulaArg).ToNumber(); stdDev.Type != ArgNumber {
- return stdDev
- }
- if x.Number <= 0 || stdDev.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- args := list.New()
- args.PushBack(newNumberFormulaArg((math.Log(x.Number) - mean.Number) / stdDev.Number))
- return fn.NORMSDIST(args)
- }
- // MODE function returns the statistical mode (the most frequently occurring
- // value) of a list of supplied numbers. If there are 2 or more most
- // frequently occurring values in the supplied data, the function returns the
- // lowest of these values The syntax of the function is:
- //
- // MODE(number1,[number2],...)
- func (fn *formulaFuncs) MODE(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "MODE requires at least 1 argument")
- }
- var values []float64
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- cells := arg.Value.(formulaArg)
- if cells.Type != ArgMatrix && cells.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- for _, cell := range cells.ToList() {
- if cell.Type == ArgNumber {
- values = append(values, cell.Number)
- }
- }
- }
- sort.Float64s(values)
- cnt := len(values)
- var count, modeCnt int
- var mode float64
- for i := 0; i < cnt; i++ {
- count = 0
- for j := 0; j < cnt; j++ {
- if j != i && values[j] == values[i] {
- count++
- }
- }
- if count > modeCnt {
- modeCnt = count
- mode = values[i]
- }
- }
- if modeCnt == 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(mode)
- }
- // MODEdotMULT function returns a vertical array of the statistical modes
- // (the most frequently occurring values) within a list of supplied numbers.
- // The syntax of the function is:
- //
- // MODE.MULT(number1,[number2],...)
- func (fn *formulaFuncs) MODEdotMULT(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "MODE.MULT requires at least 1 argument")
- }
- var values []float64
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- cells := arg.Value.(formulaArg)
- if cells.Type != ArgMatrix && cells.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- for _, cell := range cells.ToList() {
- if cell.Type == ArgNumber {
- values = append(values, cell.Number)
- }
- }
- }
- sort.Float64s(values)
- cnt := len(values)
- var count, modeCnt int
- var mtx [][]formulaArg
- for i := 0; i < cnt; i++ {
- count = 0
- for j := i + 1; j < cnt; j++ {
- if values[i] == values[j] {
- count++
- }
- }
- if count > modeCnt {
- modeCnt = count
- mtx = [][]formulaArg{}
- mtx = append(mtx, []formulaArg{newNumberFormulaArg(values[i])})
- } else if count == modeCnt {
- mtx = append(mtx, []formulaArg{newNumberFormulaArg(values[i])})
- }
- }
- if modeCnt == 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newMatrixFormulaArg(mtx)
- }
- // MODEdotSNGL function returns the statistical mode (the most frequently
- // occurring value) within a list of supplied numbers. If there are 2 or more
- // most frequently occurring values in the supplied data, the function returns
- // the lowest of these values. The syntax of the function is:
- //
- // MODE.SNGL(number1,[number2],...)
- func (fn *formulaFuncs) MODEdotSNGL(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "MODE.SNGL requires at least 1 argument")
- }
- return fn.MODE(argsList)
- }
- // NEGBINOMdotDIST function calculates the probability mass function or the
- // cumulative distribution function for the Negative Binomial Distribution.
- // This gives the probability that there will be a given number of failures
- // before a required number of successes is achieved. The syntax of the
- // function is:
- //
- // NEGBINOM.DIST(number_f,number_s,probability_s,cumulative)
- func (fn *formulaFuncs) NEGBINOMdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "NEGBINOM.DIST requires 4 arguments")
- }
- var f, s, probability, cumulative formulaArg
- if f = argsList.Front().Value.(formulaArg).ToNumber(); f.Type != ArgNumber {
- return f
- }
- if s = argsList.Front().Next().Value.(formulaArg).ToNumber(); s.Type != ArgNumber {
- return s
- }
- if probability = argsList.Front().Next().Next().Value.(formulaArg).ToNumber(); probability.Type != ArgNumber {
- return probability
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type != ArgNumber {
- return cumulative
- }
- if f.Number < 0 || s.Number < 1 || probability.Number < 0 || probability.Number > 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if cumulative.Number == 1 {
- return newNumberFormulaArg(1 - getBetaDist(1-probability.Number, f.Number+1, s.Number))
- }
- return newNumberFormulaArg(binomCoeff(f.Number+s.Number-1, s.Number-1) * math.Pow(probability.Number, s.Number) * math.Pow(1-probability.Number, f.Number))
- }
- // NEGBINOMDIST function calculates the Negative Binomial Distribution for a
- // given set of parameters. This gives the probability that there will be a
- // specified number of failures before a required number of successes is
- // achieved. The syntax of the function is:
- //
- // NEGBINOMDIST(number_f,number_s,probability_s)
- func (fn *formulaFuncs) NEGBINOMDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "NEGBINOMDIST requires 3 arguments")
- }
- var f, s, probability formulaArg
- if f = argsList.Front().Value.(formulaArg).ToNumber(); f.Type != ArgNumber {
- return f
- }
- if s = argsList.Front().Next().Value.(formulaArg).ToNumber(); s.Type != ArgNumber {
- return s
- }
- if probability = argsList.Back().Value.(formulaArg).ToNumber(); probability.Type != ArgNumber {
- return probability
- }
- if f.Number < 0 || s.Number < 1 || probability.Number < 0 || probability.Number > 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(binomCoeff(f.Number+s.Number-1, s.Number-1) * math.Pow(probability.Number, s.Number) * math.Pow(1-probability.Number, f.Number))
- }
- // NORMdotDIST function calculates the Normal Probability Density Function or
- // the Cumulative Normal Distribution. Function for a supplied set of
- // parameters. The syntax of the function is:
- //
- // NORM.DIST(x,mean,standard_dev,cumulative)
- func (fn *formulaFuncs) NORMdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "NORM.DIST requires 4 arguments")
- }
- return fn.NORMDIST(argsList)
- }
- // NORMDIST function calculates the Normal Probability Density Function or the
- // Cumulative Normal Distribution. Function for a supplied set of parameters.
- // The syntax of the function is:
- //
- // NORMDIST(x,mean,standard_dev,cumulative)
- func (fn *formulaFuncs) NORMDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "NORMDIST requires 4 arguments")
- }
- var x, mean, stdDev, cumulative formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if mean = argsList.Front().Next().Value.(formulaArg).ToNumber(); mean.Type != ArgNumber {
- return mean
- }
- if stdDev = argsList.Back().Prev().Value.(formulaArg).ToNumber(); stdDev.Type != ArgNumber {
- return stdDev
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type == ArgError {
- return cumulative
- }
- if stdDev.Number < 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if cumulative.Number == 1 {
- return newNumberFormulaArg(0.5 * (1 + math.Erf((x.Number-mean.Number)/(stdDev.Number*math.Sqrt(2)))))
- }
- return newNumberFormulaArg((1 / (math.Sqrt(2*math.Pi) * stdDev.Number)) * math.Exp(0-(math.Pow(x.Number-mean.Number, 2)/(2*(stdDev.Number*stdDev.Number)))))
- }
- // NORMdotINV function calculates the inverse of the Cumulative Normal
- // Distribution Function for a supplied value of x, and a supplied
- // distribution mean & standard deviation. The syntax of the function is:
- //
- // NORM.INV(probability,mean,standard_dev)
- func (fn *formulaFuncs) NORMdotINV(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "NORM.INV requires 3 arguments")
- }
- return fn.NORMINV(argsList)
- }
- // NORMINV function calculates the inverse of the Cumulative Normal
- // Distribution Function for a supplied value of x, and a supplied
- // distribution mean & standard deviation. The syntax of the function is:
- //
- // NORMINV(probability,mean,standard_dev)
- func (fn *formulaFuncs) NORMINV(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "NORMINV requires 3 arguments")
- }
- var prob, mean, stdDev formulaArg
- if prob = argsList.Front().Value.(formulaArg).ToNumber(); prob.Type != ArgNumber {
- return prob
- }
- if mean = argsList.Front().Next().Value.(formulaArg).ToNumber(); mean.Type != ArgNumber {
- return mean
- }
- if stdDev = argsList.Back().Value.(formulaArg).ToNumber(); stdDev.Type != ArgNumber {
- return stdDev
- }
- if prob.Number < 0 || prob.Number > 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if stdDev.Number < 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- inv, err := norminv(prob.Number)
- if err != nil {
- return newErrorFormulaArg(err.Error(), err.Error())
- }
- return newNumberFormulaArg(inv*stdDev.Number + mean.Number)
- }
- // NORMdotSdotDIST function calculates the Standard Normal Cumulative
- // Distribution Function for a supplied value. The syntax of the function
- // is:
- //
- // NORM.S.DIST(z)
- func (fn *formulaFuncs) NORMdotSdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "NORM.S.DIST requires 2 numeric arguments")
- }
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- args.PushBack(formulaArg{Type: ArgNumber, Number: 0})
- args.PushBack(formulaArg{Type: ArgNumber, Number: 1})
- args.PushBack(argsList.Back().Value.(formulaArg))
- return fn.NORMDIST(args)
- }
- // NORMSDIST function calculates the Standard Normal Cumulative Distribution
- // Function for a supplied value. The syntax of the function is:
- //
- // NORMSDIST(z)
- func (fn *formulaFuncs) NORMSDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "NORMSDIST requires 1 numeric argument")
- }
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- args.PushBack(formulaArg{Type: ArgNumber, Number: 0})
- args.PushBack(formulaArg{Type: ArgNumber, Number: 1})
- args.PushBack(formulaArg{Type: ArgNumber, Number: 1, Boolean: true})
- return fn.NORMDIST(args)
- }
- // NORMSINV function calculates the inverse of the Standard Normal Cumulative
- // Distribution Function for a supplied probability value. The syntax of the
- // function is:
- //
- // NORMSINV(probability)
- func (fn *formulaFuncs) NORMSINV(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "NORMSINV requires 1 numeric argument")
- }
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- args.PushBack(formulaArg{Type: ArgNumber, Number: 0})
- args.PushBack(formulaArg{Type: ArgNumber, Number: 1})
- return fn.NORMINV(args)
- }
- // NORMdotSdotINV function calculates the inverse of the Standard Normal
- // Cumulative Distribution Function for a supplied probability value. The
- // syntax of the function is:
- //
- // NORM.S.INV(probability)
- func (fn *formulaFuncs) NORMdotSdotINV(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "NORM.S.INV requires 1 numeric argument")
- }
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- args.PushBack(formulaArg{Type: ArgNumber, Number: 0})
- args.PushBack(formulaArg{Type: ArgNumber, Number: 1})
- return fn.NORMINV(args)
- }
- // norminv returns the inverse of the normal cumulative distribution for the
- // specified value.
- func norminv(p float64) (float64, error) {
- a := map[int]float64{
- 1: -3.969683028665376e+01, 2: 2.209460984245205e+02, 3: -2.759285104469687e+02,
- 4: 1.383577518672690e+02, 5: -3.066479806614716e+01, 6: 2.506628277459239e+00,
- }
- b := map[int]float64{
- 1: -5.447609879822406e+01, 2: 1.615858368580409e+02, 3: -1.556989798598866e+02,
- 4: 6.680131188771972e+01, 5: -1.328068155288572e+01,
- }
- c := map[int]float64{
- 1: -7.784894002430293e-03, 2: -3.223964580411365e-01, 3: -2.400758277161838e+00,
- 4: -2.549732539343734e+00, 5: 4.374664141464968e+00, 6: 2.938163982698783e+00,
- }
- d := map[int]float64{
- 1: 7.784695709041462e-03, 2: 3.224671290700398e-01, 3: 2.445134137142996e+00,
- 4: 3.754408661907416e+00,
- }
- pLow := 0.02425 // Use lower region approx. below this
- pHigh := 1 - pLow // Use upper region approx. above this
- if 0 < p && p < pLow {
- // Rational approximation for lower region.
- q := math.Sqrt(-2 * math.Log(p))
- return (((((c[1]*q+c[2])*q+c[3])*q+c[4])*q+c[5])*q + c[6]) /
- ((((d[1]*q+d[2])*q+d[3])*q+d[4])*q + 1), nil
- } else if pLow <= p && p <= pHigh {
- // Rational approximation for central region.
- q := p - 0.5
- r := q * q
- f1 := ((((a[1]*r+a[2])*r+a[3])*r+a[4])*r + a[5]) * r
- f2 := (b[1]*r + b[2]) * r
- f3 := ((math.Nextafter(f2, f2)+b[3])*r + b[4]) * r
- f4 := (math.Nextafter(f3, f3) + b[5]) * r
- return (math.Nextafter(f1, f1) + a[6]) * q /
- (math.Nextafter(f4, f4) + 1), nil
- } else if pHigh < p && p < 1 {
- // Rational approximation for upper region.
- q := math.Sqrt(-2 * math.Log(1-p))
- return -(((((c[1]*q+c[2])*q+c[3])*q+c[4])*q+c[5])*q + c[6]) /
- ((((d[1]*q+d[2])*q+d[3])*q+d[4])*q + 1), nil
- }
- return 0, errors.New(formulaErrorNUM)
- }
- // kth is an implementation of the formula functions LARGE and SMALL.
- func (fn *formulaFuncs) kth(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name))
- }
- array := argsList.Front().Value.(formulaArg).ToList()
- argK := argsList.Back().Value.(formulaArg).ToNumber()
- if argK.Type != ArgNumber {
- return argK
- }
- k := int(argK.Number)
- if k < 1 {
- return newErrorFormulaArg(formulaErrorNUM, "k should be > 0")
- }
- var data []float64
- for _, arg := range array {
- if arg.Type == ArgNumber {
- data = append(data, arg.Number)
- }
- }
- if len(data) < k {
- return newErrorFormulaArg(formulaErrorNUM, "k should be <= length of array")
- }
- sort.Float64s(data)
- if name == "LARGE" {
- return newNumberFormulaArg(data[len(data)-k])
- }
- return newNumberFormulaArg(data[k-1])
- }
- // LARGE function returns the k'th largest value from an array of numeric
- // values. The syntax of the function is:
- //
- // LARGE(array,k)
- func (fn *formulaFuncs) LARGE(argsList *list.List) formulaArg {
- return fn.kth("LARGE", argsList)
- }
- // MAX function returns the largest value from a supplied set of numeric
- // values. The syntax of the function is:
- //
- // MAX(number1,[number2],...)
- func (fn *formulaFuncs) MAX(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "MAX requires at least 1 argument")
- }
- return fn.max(false, argsList)
- }
- // MAXA function returns the largest value from a supplied set of numeric
- // values, while counting text and the logical value FALSE as the value 0 and
- // counting the logical value TRUE as the value 1. The syntax of the function
- // is:
- //
- // MAXA(number1,[number2],...)
- func (fn *formulaFuncs) MAXA(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "MAXA requires at least 1 argument")
- }
- return fn.max(true, argsList)
- }
- // MAXIFS function returns the maximum value from a subset of values that are
- // specified according to one or more criteria. The syntax of the function
- // is:
- //
- // MAXIFS(max_range,criteria_range1,criteria1,[criteria_range2,criteria2],...)
- func (fn *formulaFuncs) MAXIFS(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "MAXIFS requires at least 3 arguments")
- }
- if argsList.Len()%2 != 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var args []formulaArg
- max, maxRange := -math.MaxFloat64, argsList.Front().Value.(formulaArg).Matrix
- for arg := argsList.Front().Next(); arg != nil; arg = arg.Next() {
- args = append(args, arg.Value.(formulaArg))
- }
- for _, ref := range formulaIfsMatch(args) {
- if num := maxRange[ref.Row][ref.Col].ToNumber(); num.Type == ArgNumber && max < num.Number {
- max = num.Number
- }
- }
- if max == -math.MaxFloat64 {
- max = 0
- }
- return newNumberFormulaArg(max)
- }
- // calcListMatrixMax is part of the implementation max.
- func calcListMatrixMax(maxa bool, max float64, arg formulaArg) float64 {
- for _, cell := range arg.ToList() {
- if cell.Type == ArgNumber && cell.Number > max {
- if maxa && cell.Boolean || !cell.Boolean {
- max = cell.Number
- }
- }
- }
- return max
- }
- // max is an implementation of the formula functions MAX and MAXA.
- func (fn *formulaFuncs) max(maxa bool, argsList *list.List) formulaArg {
- max := -math.MaxFloat64
- for token := argsList.Front(); token != nil; token = token.Next() {
- arg := token.Value.(formulaArg)
- switch arg.Type {
- case ArgString:
- if !maxa && (arg.Value() == "TRUE" || arg.Value() == "FALSE") {
- continue
- } else {
- num := arg.ToBool()
- if num.Type == ArgNumber && num.Number > max {
- max = num.Number
- continue
- }
- }
- num := arg.ToNumber()
- if num.Type != ArgError && num.Number > max {
- max = num.Number
- }
- case ArgNumber:
- if arg.Number > max {
- max = arg.Number
- }
- case ArgList, ArgMatrix:
- max = calcListMatrixMax(maxa, max, arg)
- case ArgError:
- return arg
- }
- }
- if max == -math.MaxFloat64 {
- max = 0
- }
- return newNumberFormulaArg(max)
- }
- // MEDIAN function returns the statistical median (the middle value) of a list
- // of supplied numbers. The syntax of the function is:
- //
- // MEDIAN(number1,[number2],...)
- func (fn *formulaFuncs) MEDIAN(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "MEDIAN requires at least 1 argument")
- }
- var values []float64
- var median float64
- for token := argsList.Front(); token != nil; token = token.Next() {
- arg := token.Value.(formulaArg)
- switch arg.Type {
- case ArgString:
- value := arg.ToNumber()
- if value.Type != ArgNumber {
- return value
- }
- values = append(values, value.Number)
- case ArgNumber:
- values = append(values, arg.Number)
- case ArgMatrix:
- for _, row := range arg.Matrix {
- for _, cell := range row {
- if cell.Type == ArgNumber {
- values = append(values, cell.Number)
- }
- }
- }
- }
- }
- if len(values) == 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- sort.Float64s(values)
- if len(values)%2 == 0 {
- median = (values[len(values)/2-1] + values[len(values)/2]) / 2
- } else {
- median = values[len(values)/2]
- }
- return newNumberFormulaArg(median)
- }
- // MIN function returns the smallest value from a supplied set of numeric
- // values. The syntax of the function is:
- //
- // MIN(number1,[number2],...)
- func (fn *formulaFuncs) MIN(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "MIN requires at least 1 argument")
- }
- return fn.min(false, argsList)
- }
- // MINA function returns the smallest value from a supplied set of numeric
- // values, while counting text and the logical value FALSE as the value 0 and
- // counting the logical value TRUE as the value 1. The syntax of the function
- // is:
- //
- // MINA(number1,[number2],...)
- func (fn *formulaFuncs) MINA(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "MINA requires at least 1 argument")
- }
- return fn.min(true, argsList)
- }
- // MINIFS function returns the minimum value from a subset of values that are
- // specified according to one or more criteria. The syntax of the function
- // is:
- //
- // MINIFS(min_range,criteria_range1,criteria1,[criteria_range2,criteria2],...)
- func (fn *formulaFuncs) MINIFS(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "MINIFS requires at least 3 arguments")
- }
- if argsList.Len()%2 != 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var args []formulaArg
- min, minRange := math.MaxFloat64, argsList.Front().Value.(formulaArg).Matrix
- for arg := argsList.Front().Next(); arg != nil; arg = arg.Next() {
- args = append(args, arg.Value.(formulaArg))
- }
- for _, ref := range formulaIfsMatch(args) {
- if num := minRange[ref.Row][ref.Col].ToNumber(); num.Type == ArgNumber && min > num.Number {
- min = num.Number
- }
- }
- if min == math.MaxFloat64 {
- min = 0
- }
- return newNumberFormulaArg(min)
- }
- // calcListMatrixMin is part of the implementation min.
- func calcListMatrixMin(mina bool, min float64, arg formulaArg) float64 {
- for _, cell := range arg.ToList() {
- if cell.Type == ArgNumber && cell.Number < min {
- if mina && cell.Boolean || !cell.Boolean {
- min = cell.Number
- }
- }
- }
- return min
- }
- // min is an implementation of the formula functions MIN and MINA.
- func (fn *formulaFuncs) min(mina bool, argsList *list.List) formulaArg {
- min := math.MaxFloat64
- for token := argsList.Front(); token != nil; token = token.Next() {
- arg := token.Value.(formulaArg)
- switch arg.Type {
- case ArgString:
- if !mina && (arg.Value() == "TRUE" || arg.Value() == "FALSE") {
- continue
- } else {
- num := arg.ToBool()
- if num.Type == ArgNumber && num.Number < min {
- min = num.Number
- continue
- }
- }
- num := arg.ToNumber()
- if num.Type != ArgError && num.Number < min {
- min = num.Number
- }
- case ArgNumber:
- if arg.Number < min {
- min = arg.Number
- }
- case ArgList, ArgMatrix:
- min = calcListMatrixMin(mina, min, arg)
- case ArgError:
- return arg
- }
- }
- if min == math.MaxFloat64 {
- min = 0
- }
- return newNumberFormulaArg(min)
- }
- // pearsonProduct is an implementation of the formula functions PEARSON, RSQ
- // and SLOPE.
- func (fn *formulaFuncs) pearsonProduct(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name))
- }
- var array1, array2 []formulaArg
- if name == "SLOPE" {
- array1 = argsList.Back().Value.(formulaArg).ToList()
- array2 = argsList.Front().Value.(formulaArg).ToList()
- } else {
- array1 = argsList.Front().Value.(formulaArg).ToList()
- array2 = argsList.Back().Value.(formulaArg).ToList()
- }
- if len(array1) != len(array2) {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var sum, deltaX, deltaY, x, y, length float64
- for i := 0; i < len(array1); i++ {
- num1, num2 := array1[i], array2[i]
- if !(num1.Type == ArgNumber && num2.Type == ArgNumber) {
- continue
- }
- x += num1.Number
- y += num2.Number
- length++
- }
- x /= length
- y /= length
- for i := 0; i < len(array1); i++ {
- num1, num2 := array1[i], array2[i]
- if !(num1.Type == ArgNumber && num2.Type == ArgNumber) {
- continue
- }
- sum += (num1.Number - x) * (num2.Number - y)
- deltaX += (num1.Number - x) * (num1.Number - x)
- deltaY += (num2.Number - y) * (num2.Number - y)
- }
- if deltaX == 0 || deltaY == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- if name == "RSQ" {
- return newNumberFormulaArg(math.Pow(sum/math.Sqrt(deltaX*deltaY), 2))
- }
- if name == "PEARSON" {
- return newNumberFormulaArg(sum / math.Sqrt(deltaX*deltaY))
- }
- return newNumberFormulaArg(sum / deltaX)
- }
- // PEARSON function calculates the Pearson Product-Moment Correlation
- // Coefficient for two sets of values. The syntax of the function is:
- //
- // PEARSON(array1,array2)
- func (fn *formulaFuncs) PEARSON(argsList *list.List) formulaArg {
- return fn.pearsonProduct("PEARSON", argsList)
- }
- // PERCENTILEdotEXC function returns the k'th percentile (i.e. the value below
- // which k% of the data values fall) for a supplied range of values and a
- // supplied k (between 0 & 1 exclusive).The syntax of the function is:
- //
- // PERCENTILE.EXC(array,k)
- func (fn *formulaFuncs) PERCENTILEdotEXC(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "PERCENTILE.EXC requires 2 arguments")
- }
- array := argsList.Front().Value.(formulaArg).ToList()
- k := argsList.Back().Value.(formulaArg).ToNumber()
- if k.Type != ArgNumber {
- return k
- }
- if k.Number <= 0 || k.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- var numbers []float64
- for _, arg := range array {
- if arg.Type == ArgError {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if arg.Type == ArgNumber {
- numbers = append(numbers, arg.Number)
- }
- }
- cnt := len(numbers)
- sort.Float64s(numbers)
- idx := k.Number * (float64(cnt) + 1)
- base := math.Floor(idx)
- next := base - 1
- proportion := math.Nextafter(idx, idx) - base
- return newNumberFormulaArg(numbers[int(next)] + ((numbers[int(base)] - numbers[int(next)]) * proportion))
- }
- // PERCENTILEdotINC function returns the k'th percentile (i.e. the value below
- // which k% of the data values fall) for a supplied range of values and a
- // supplied k. The syntax of the function is:
- //
- // PERCENTILE.INC(array,k)
- func (fn *formulaFuncs) PERCENTILEdotINC(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "PERCENTILE.INC requires 2 arguments")
- }
- return fn.PERCENTILE(argsList)
- }
- // PERCENTILE function returns the k'th percentile (i.e. the value below which
- // k% of the data values fall) for a supplied range of values and a supplied
- // k. The syntax of the function is:
- //
- // PERCENTILE(array,k)
- func (fn *formulaFuncs) PERCENTILE(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "PERCENTILE requires 2 arguments")
- }
- array := argsList.Front().Value.(formulaArg).ToList()
- k := argsList.Back().Value.(formulaArg).ToNumber()
- if k.Type != ArgNumber {
- return k
- }
- if k.Number < 0 || k.Number > 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var numbers []float64
- for _, arg := range array {
- if arg.Type == ArgError {
- return arg
- }
- if arg.Type == ArgNumber {
- numbers = append(numbers, arg.Number)
- }
- }
- cnt := len(numbers)
- sort.Float64s(numbers)
- idx := k.Number * (float64(cnt) - 1)
- base := math.Floor(idx)
- if idx == base {
- return newNumberFormulaArg(numbers[int(idx)])
- }
- next := base + 1
- proportion := math.Nextafter(idx, idx) - base
- return newNumberFormulaArg(numbers[int(base)] + ((numbers[int(next)] - numbers[int(base)]) * proportion))
- }
- // percentrank is an implementation of the formula functions PERCENTRANK and
- // PERCENTRANK.INC.
- func (fn *formulaFuncs) percentrank(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 2 && argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 or 3 arguments", name))
- }
- array := argsList.Front().Value.(formulaArg).ToList()
- x := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- var numbers []float64
- for _, arg := range array {
- if arg.Type == ArgError {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if arg.Type == ArgNumber {
- numbers = append(numbers, arg.Number)
- }
- }
- cnt := len(numbers)
- sort.Float64s(numbers)
- if x.Number < numbers[0] || x.Number > numbers[cnt-1] {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- pos, significance := float64(inFloat64Slice(numbers, x.Number)), newNumberFormulaArg(3)
- if argsList.Len() == 3 {
- if significance = argsList.Back().Value.(formulaArg).ToNumber(); significance.Type != ArgNumber {
- return significance
- }
- if significance.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, fmt.Sprintf("%s arguments significance should be > 1", name))
- }
- }
- if pos == -1 {
- pos = 0
- cmp := numbers[0]
- for cmp < x.Number {
- pos++
- cmp = numbers[int(pos)]
- }
- pos--
- pos += (x.Number - numbers[int(pos)]) / (cmp - numbers[int(pos)])
- }
- pow := math.Pow(10, significance.Number)
- digit := pow * pos / (float64(cnt) - 1)
- if name == "PERCENTRANK.EXC" {
- digit = pow * (pos + 1) / (float64(cnt) + 1)
- }
- return newNumberFormulaArg(math.Floor(digit) / pow)
- }
- // PERCENTRANKdotEXC function calculates the relative position, between 0 and
- // 1 (exclusive), of a specified value within a supplied array. The syntax of
- // the function is:
- //
- // PERCENTRANK.EXC(array,x,[significance])
- func (fn *formulaFuncs) PERCENTRANKdotEXC(argsList *list.List) formulaArg {
- return fn.percentrank("PERCENTRANK.EXC", argsList)
- }
- // PERCENTRANKdotINC function calculates the relative position, between 0 and
- // 1 (inclusive), of a specified value within a supplied array.The syntax of
- // the function is:
- //
- // PERCENTRANK.INC(array,x,[significance])
- func (fn *formulaFuncs) PERCENTRANKdotINC(argsList *list.List) formulaArg {
- return fn.percentrank("PERCENTRANK.INC", argsList)
- }
- // PERCENTRANK function calculates the relative position of a specified value,
- // within a set of values, as a percentage. The syntax of the function is:
- //
- // PERCENTRANK(array,x,[significance])
- func (fn *formulaFuncs) PERCENTRANK(argsList *list.List) formulaArg {
- return fn.percentrank("PERCENTRANK", argsList)
- }
- // PERMUT function calculates the number of permutations of a specified number
- // of objects from a set of objects. The syntax of the function is:
- //
- // PERMUT(number,number_chosen)
- func (fn *formulaFuncs) PERMUT(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "PERMUT requires 2 numeric arguments")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- chosen := argsList.Back().Value.(formulaArg).ToNumber()
- if number.Type != ArgNumber {
- return number
- }
- if chosen.Type != ArgNumber {
- return chosen
- }
- if number.Number < chosen.Number {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(math.Round(fact(number.Number) / fact(number.Number-chosen.Number)))
- }
- // PERMUTATIONA function calculates the number of permutations, with
- // repetitions, of a specified number of objects from a set. The syntax of
- // the function is:
- //
- // PERMUTATIONA(number,number_chosen)
- func (fn *formulaFuncs) PERMUTATIONA(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "PERMUTATIONA requires 2 numeric arguments")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- chosen := argsList.Back().Value.(formulaArg).ToNumber()
- if number.Type != ArgNumber {
- return number
- }
- if chosen.Type != ArgNumber {
- return chosen
- }
- num, numChosen := math.Floor(number.Number), math.Floor(chosen.Number)
- if num < 0 || numChosen < 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(math.Pow(num, numChosen))
- }
- // PHI function returns the value of the density function for a standard normal
- // distribution for a supplied number. The syntax of the function is:
- //
- // PHI(x)
- func (fn *formulaFuncs) PHI(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "PHI requires 1 argument")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- return newNumberFormulaArg(0.39894228040143268 * math.Exp(-(x.Number*x.Number)/2))
- }
- // QUARTILE function returns a requested quartile of a supplied range of
- // values. The syntax of the function is:
- //
- // QUARTILE(array,quart)
- func (fn *formulaFuncs) QUARTILE(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "QUARTILE requires 2 arguments")
- }
- quart := argsList.Back().Value.(formulaArg).ToNumber()
- if quart.Type != ArgNumber {
- return quart
- }
- if quart.Number < 0 || quart.Number > 4 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- args.PushBack(newNumberFormulaArg(quart.Number / 4))
- return fn.PERCENTILE(args)
- }
- // QUARTILEdotEXC function returns a requested quartile of a supplied range of
- // values, based on a percentile range of 0 to 1 exclusive. The syntax of the
- // function is:
- //
- // QUARTILE.EXC(array,quart)
- func (fn *formulaFuncs) QUARTILEdotEXC(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "QUARTILE.EXC requires 2 arguments")
- }
- quart := argsList.Back().Value.(formulaArg).ToNumber()
- if quart.Type != ArgNumber {
- return quart
- }
- if quart.Number <= 0 || quart.Number >= 4 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- args := list.New().Init()
- args.PushBack(argsList.Front().Value.(formulaArg))
- args.PushBack(newNumberFormulaArg(quart.Number / 4))
- return fn.PERCENTILEdotEXC(args)
- }
- // QUARTILEdotINC function returns a requested quartile of a supplied range of
- // values. The syntax of the function is:
- //
- // QUARTILE.INC(array,quart)
- func (fn *formulaFuncs) QUARTILEdotINC(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "QUARTILE.INC requires 2 arguments")
- }
- return fn.QUARTILE(argsList)
- }
- // rank is an implementation of the formula functions RANK and RANK.EQ.
- func (fn *formulaFuncs) rank(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 2 arguments", name))
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at most 3 arguments", name))
- }
- num := argsList.Front().Value.(formulaArg).ToNumber()
- if num.Type != ArgNumber {
- return num
- }
- var arr []float64
- for _, arg := range argsList.Front().Next().Value.(formulaArg).ToList() {
- if arg.Type == ArgNumber {
- arr = append(arr, arg.Number)
- }
- }
- sort.Float64s(arr)
- order := newNumberFormulaArg(0)
- if argsList.Len() == 3 {
- if order = argsList.Back().Value.(formulaArg).ToNumber(); order.Type != ArgNumber {
- return order
- }
- }
- if order.Number == 0 {
- sort.Sort(sort.Reverse(sort.Float64Slice(arr)))
- }
- if idx := inFloat64Slice(arr, num.Number); idx != -1 {
- return newNumberFormulaArg(float64(idx + 1))
- }
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- // RANKdotEQ function returns the statistical rank of a given value, within a
- // supplied array of values. If there are duplicate values in the list, these
- // are given the same rank. The syntax of the function is:
- //
- // RANK.EQ(number,ref,[order])
- func (fn *formulaFuncs) RANKdotEQ(argsList *list.List) formulaArg {
- return fn.rank("RANK.EQ", argsList)
- }
- // RANK function returns the statistical rank of a given value, within a
- // supplied array of values. If there are duplicate values in the list, these
- // are given the same rank. The syntax of the function is:
- //
- // RANK(number,ref,[order])
- func (fn *formulaFuncs) RANK(argsList *list.List) formulaArg {
- return fn.rank("RANK", argsList)
- }
- // RSQ function calculates the square of the Pearson Product-Moment Correlation
- // Coefficient for two supplied sets of values. The syntax of the function
- // is:
- //
- // RSQ(known_y's,known_x's)
- func (fn *formulaFuncs) RSQ(argsList *list.List) formulaArg {
- return fn.pearsonProduct("RSQ", argsList)
- }
- // skew is an implementation of the formula functions SKEW and SKEW.P.
- func (fn *formulaFuncs) skew(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
- }
- mean := fn.AVERAGE(argsList)
- var stdDev formulaArg
- var count, summer float64
- if name == "SKEW" {
- stdDev = fn.STDEV(argsList)
- } else {
- stdDev = fn.STDEVP(argsList)
- }
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgNumber, ArgString:
- num := token.ToNumber()
- if num.Type == ArgError {
- return num
- }
- summer += math.Pow((num.Number-mean.Number)/stdDev.Number, 3)
- count++
- case ArgList, ArgMatrix:
- for _, cell := range token.ToList() {
- if cell.Type != ArgNumber {
- continue
- }
- summer += math.Pow((cell.Number-mean.Number)/stdDev.Number, 3)
- count++
- }
- }
- }
- if count > 2 {
- if name == "SKEW" {
- return newNumberFormulaArg(summer * (count / ((count - 1) * (count - 2))))
- }
- return newNumberFormulaArg(summer / count)
- }
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- // SKEW function calculates the skewness of the distribution of a supplied set
- // of values. The syntax of the function is:
- //
- // SKEW(number1,[number2],...)
- func (fn *formulaFuncs) SKEW(argsList *list.List) formulaArg {
- return fn.skew("SKEW", argsList)
- }
- // SKEWdotP function calculates the skewness of the distribution of a supplied
- // set of values. The syntax of the function is:
- //
- // SKEW.P(number1,[number2],...)
- func (fn *formulaFuncs) SKEWdotP(argsList *list.List) formulaArg {
- return fn.skew("SKEW.P", argsList)
- }
- // SLOPE returns the slope of the linear regression line through data points in
- // known_y's and known_x's. The slope is the vertical distance divided by the
- // horizontal distance between any two points on the line, which is the rate
- // of change along the regression line. The syntax of the function is:
- //
- // SLOPE(known_y's,known_x's)
- func (fn *formulaFuncs) SLOPE(argsList *list.List) formulaArg {
- return fn.pearsonProduct("SLOPE", argsList)
- }
- // SMALL function returns the k'th smallest value from an array of numeric
- // values. The syntax of the function is:
- //
- // SMALL(array,k)
- func (fn *formulaFuncs) SMALL(argsList *list.List) formulaArg {
- return fn.kth("SMALL", argsList)
- }
- // STANDARDIZE function returns a normalized value of a distribution that is
- // characterized by a supplied mean and standard deviation. The syntax of the
- // function is:
- //
- // STANDARDIZE(x,mean,standard_dev)
- func (fn *formulaFuncs) STANDARDIZE(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "STANDARDIZE requires 3 arguments")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- if x.Type != ArgNumber {
- return x
- }
- mean := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if mean.Type != ArgNumber {
- return mean
- }
- stdDev := argsList.Back().Value.(formulaArg).ToNumber()
- if stdDev.Type != ArgNumber {
- return stdDev
- }
- if stdDev.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg((x.Number - mean.Number) / stdDev.Number)
- }
- // stdevp is an implementation of the formula functions STDEVP, STDEV.P and
- // STDEVPA.
- func (fn *formulaFuncs) stdevp(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
- }
- fnName := "VARP"
- if name == "STDEVPA" {
- fnName = "VARPA"
- }
- varp := fn.vars(fnName, argsList)
- if varp.Type != ArgNumber {
- return varp
- }
- return newNumberFormulaArg(math.Sqrt(varp.Number))
- }
- // STDEVP function calculates the standard deviation of a supplied set of
- // values. The syntax of the function is:
- //
- // STDEVP(number1,[number2],...)
- func (fn *formulaFuncs) STDEVP(argsList *list.List) formulaArg {
- return fn.stdevp("STDEVP", argsList)
- }
- // STDEVdotP function calculates the standard deviation of a supplied set of
- // values.
- //
- // STDEV.P( number1, [number2], ... )
- func (fn *formulaFuncs) STDEVdotP(argsList *list.List) formulaArg {
- return fn.stdevp("STDEV.P", argsList)
- }
- // STDEVPA function calculates the standard deviation of a supplied set of
- // values. The syntax of the function is:
- //
- // STDEVPA(number1,[number2],...)
- func (fn *formulaFuncs) STDEVPA(argsList *list.List) formulaArg {
- return fn.stdevp("STDEVPA", argsList)
- }
- // STEYX function calculates the standard error for the line of best fit,
- // through a supplied set of x- and y- values. The syntax of the function is:
- //
- // STEYX(known_y's,known_x's)
- func (fn *formulaFuncs) STEYX(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "STEYX requires 2 arguments")
- }
- array1 := argsList.Back().Value.(formulaArg).ToList()
- array2 := argsList.Front().Value.(formulaArg).ToList()
- if len(array1) != len(array2) {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var count, sumX, sumY, squareX, squareY, sigmaXY float64
- for i := 0; i < len(array1); i++ {
- num1, num2 := array1[i], array2[i]
- if !(num1.Type == ArgNumber && num2.Type == ArgNumber) {
- continue
- }
- sumX += num1.Number
- sumY += num2.Number
- squareX += num1.Number * num1.Number
- squareY += num2.Number * num2.Number
- sigmaXY += num1.Number * num2.Number
- count++
- }
- if count < 3 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- dx, dy := sumX/count, sumY/count
- sigma1 := squareY - 2*dy*sumY + count*dy*dy
- sigma2 := sigmaXY - dy*sumX - sumY*dx + count*dy*dx
- sigma3 := squareX - 2*dx*sumX + count*dx*dx
- return newNumberFormulaArg(math.Sqrt((sigma1 - (sigma2*sigma2)/sigma3) / (count - 2)))
- }
- // getTDist is an implementation for the beta distribution probability density
- // function.
- func getTDist(T, fDF, nType float64) float64 {
- var res float64
- switch nType {
- case 1:
- res = 0.5 * getBetaDist(fDF/(fDF+T*T), fDF/2, 0.5)
- case 2:
- res = getBetaDist(fDF/(fDF+T*T), fDF/2, 0.5)
- case 3:
- res = math.Pow(1+(T*T/fDF), -(fDF+1)/2) / (math.Sqrt(fDF) * getBeta(0.5, fDF/2.0))
- case 4:
- X := fDF / (T*T + fDF)
- R := 0.5 * getBetaDist(X, 0.5*fDF, 0.5)
- res = 1 - R
- if T < 0 {
- res = R
- }
- }
- return res
- }
- // TdotDIST function calculates the one-tailed Student's T Distribution, which
- // is a continuous probability distribution that is frequently used for
- // testing hypotheses on small sample data sets. The syntax of the function
- // is:
- //
- // T.DIST(x,degrees_freedom,cumulative)
- func (fn *formulaFuncs) TdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "T.DIST requires 3 arguments")
- }
- var x, degrees, cumulative formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if degrees = argsList.Front().Next().Value.(formulaArg).ToNumber(); degrees.Type != ArgNumber {
- return degrees
- }
- if cumulative = argsList.Back().Value.(formulaArg).ToBool(); cumulative.Type != ArgNumber {
- return cumulative
- }
- if cumulative.Number == 1 && degrees.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if cumulative.Number == 0 {
- if degrees.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if degrees.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(getTDist(x.Number, degrees.Number, 3))
- }
- return newNumberFormulaArg(getTDist(x.Number, degrees.Number, 4))
- }
- // TdotDISTdot2T function calculates the two-tailed Student's T Distribution,
- // which is a continuous probability distribution that is frequently used for
- // testing hypotheses on small sample data sets. The syntax of the function
- // is:
- //
- // T.DIST.2T(x,degrees_freedom)
- func (fn *formulaFuncs) TdotDISTdot2T(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "T.DIST.2T requires 2 arguments")
- }
- var x, degrees formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if degrees = argsList.Back().Value.(formulaArg).ToNumber(); degrees.Type != ArgNumber {
- return degrees
- }
- if x.Number < 0 || degrees.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(getTDist(x.Number, degrees.Number, 2))
- }
- // TdotDISTdotRT function calculates the right-tailed Student's T Distribution,
- // which is a continuous probability distribution that is frequently used for
- // testing hypotheses on small sample data sets. The syntax of the function
- // is:
- //
- // T.DIST.RT(x,degrees_freedom)
- func (fn *formulaFuncs) TdotDISTdotRT(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "T.DIST.RT requires 2 arguments")
- }
- var x, degrees formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if degrees = argsList.Back().Value.(formulaArg).ToNumber(); degrees.Type != ArgNumber {
- return degrees
- }
- if degrees.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- v := getTDist(x.Number, degrees.Number, 1)
- if x.Number < 0 {
- v = 1 - v
- }
- return newNumberFormulaArg(v)
- }
- // TDIST function calculates the Student's T Distribution, which is a
- // continuous probability distribution that is frequently used for testing
- // hypotheses on small sample data sets. The syntax of the function is:
- //
- // TDIST(x,degrees_freedom,tails)
- func (fn *formulaFuncs) TDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "TDIST requires 3 arguments")
- }
- var x, degrees, tails formulaArg
- if x = argsList.Front().Value.(formulaArg).ToNumber(); x.Type != ArgNumber {
- return x
- }
- if degrees = argsList.Front().Next().Value.(formulaArg).ToNumber(); degrees.Type != ArgNumber {
- return degrees
- }
- if tails = argsList.Back().Value.(formulaArg).ToNumber(); tails.Type != ArgNumber {
- return tails
- }
- if x.Number < 0 || degrees.Number < 1 || (tails.Number != 1 && tails.Number != 2) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(getTDist(x.Number, degrees.Number, tails.Number))
- }
- // TdotINV function calculates the left-tailed inverse of the Student's T
- // Distribution, which is a continuous probability distribution that is
- // frequently used for testing hypotheses on small sample data sets. The
- // syntax of the function is:
- //
- // T.INV(probability,degrees_freedom)
- func (fn *formulaFuncs) TdotINV(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "T.INV requires 2 arguments")
- }
- var probability, degrees formulaArg
- if probability = argsList.Front().Value.(formulaArg).ToNumber(); probability.Type != ArgNumber {
- return probability
- }
- if degrees = argsList.Back().Value.(formulaArg).ToNumber(); degrees.Type != ArgNumber {
- return degrees
- }
- if probability.Number <= 0 || probability.Number >= 1 || degrees.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if probability.Number < 0.5 {
- return newNumberFormulaArg(-calcIterateInverse(calcInverseIterator{
- name: "T.INV",
- fp: 1 - probability.Number,
- fDF: degrees.Number,
- nT: 4,
- }, degrees.Number/2, degrees.Number))
- }
- return newNumberFormulaArg(calcIterateInverse(calcInverseIterator{
- name: "T.INV",
- fp: probability.Number,
- fDF: degrees.Number,
- nT: 4,
- }, degrees.Number/2, degrees.Number))
- }
- // TdotINVdot2T function calculates the inverse of the two-tailed Student's T
- // Distribution, which is a continuous probability distribution that is
- // frequently used for testing hypotheses on small sample data sets. The
- // syntax of the function is:
- //
- // T.INV.2T(probability,degrees_freedom)
- func (fn *formulaFuncs) TdotINVdot2T(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "T.INV.2T requires 2 arguments")
- }
- var probability, degrees formulaArg
- if probability = argsList.Front().Value.(formulaArg).ToNumber(); probability.Type != ArgNumber {
- return probability
- }
- if degrees = argsList.Back().Value.(formulaArg).ToNumber(); degrees.Type != ArgNumber {
- return degrees
- }
- if probability.Number <= 0 || probability.Number > 1 || degrees.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(calcIterateInverse(calcInverseIterator{
- name: "T.INV.2T",
- fp: probability.Number,
- fDF: degrees.Number,
- nT: 2,
- }, degrees.Number/2, degrees.Number))
- }
- // TINV function calculates the inverse of the two-tailed Student's T
- // Distribution, which is a continuous probability distribution that is
- // frequently used for testing hypotheses on small sample data sets. The
- // syntax of the function is:
- //
- // TINV(probability,degrees_freedom)
- func (fn *formulaFuncs) TINV(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "TINV requires 2 arguments")
- }
- return fn.TdotINVdot2T(argsList)
- }
- // TREND function calculates the linear trend line through a given set of
- // y-values and (optionally), a given set of x-values. The function then
- // extends the linear trendline to calculate additional y-values for a further
- // supplied set of new x-values. The syntax of the function is:
- //
- // TREND(known_y's,[known_x's],[new_x's],[const])
- func (fn *formulaFuncs) TREND(argsList *list.List) formulaArg {
- return fn.trendGrowth("TREND", argsList)
- }
- // tTest calculates the probability associated with the Student's T Test.
- func tTest(bTemplin bool, mtx1, mtx2 [][]formulaArg, c1, c2, r1, r2 int) (float64, float64, bool) {
- var cnt1, cnt2, sum1, sumSqr1, sum2, sumSqr2 float64
- var fVal formulaArg
- for i := 0; i < c1; i++ {
- for j := 0; j < r1; j++ {
- if fVal = mtx1[i][j]; fVal.Type == ArgNumber {
- sum1 += fVal.Number
- sumSqr1 += fVal.Number * fVal.Number
- cnt1++
- }
- }
- }
- for i := 0; i < c2; i++ {
- for j := 0; j < r2; j++ {
- if fVal = mtx2[i][j]; fVal.Type == ArgNumber {
- sum2 += fVal.Number
- sumSqr2 += fVal.Number * fVal.Number
- cnt2++
- }
- }
- }
- if cnt1 < 2.0 || cnt2 < 2.0 {
- return 0, 0, false
- }
- if bTemplin {
- fS1 := (sumSqr1 - sum1*sum1/cnt1) / (cnt1 - 1) / cnt1
- fS2 := (sumSqr2 - sum2*sum2/cnt2) / (cnt2 - 1) / cnt2
- if fS1+fS2 == 0 {
- return 0, 0, false
- }
- c := fS1 / (fS1 + fS2)
- return math.Abs(sum1/cnt1-sum2/cnt2) / math.Sqrt(fS1+fS2), 1 / (c*c/(cnt1-1) + (1-c)*(1-c)/(cnt2-1)), true
- }
- fS1 := (sumSqr1 - sum1*sum1/cnt1) / (cnt1 - 1)
- fS2 := (sumSqr2 - sum2*sum2/cnt2) / (cnt2 - 1)
- return math.Abs(sum1/cnt1-sum2/cnt2) / math.Sqrt((cnt1-1)*fS1+(cnt2-1)*fS2) * math.Sqrt(cnt1*cnt2*(cnt1+cnt2-2)/(cnt1+cnt2)), cnt1 + cnt2 - 2, true
- }
- // tTest is an implementation of the formula function TTEST.
- func (fn *formulaFuncs) tTest(mtx1, mtx2 [][]formulaArg, fTails, fTyp float64) formulaArg {
- var fT, fF float64
- c1, c2, r1, r2, ok := len(mtx1), len(mtx2), len(mtx1[0]), len(mtx2[0]), true
- if fTyp == 1 {
- if c1 != c2 || r1 != r2 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- var cnt, sum1, sum2, sumSqrD float64
- var fVal1, fVal2 formulaArg
- for i := 0; i < c1; i++ {
- for j := 0; j < r1; j++ {
- fVal1, fVal2 = mtx1[i][j], mtx2[i][j]
- if fVal1.Type != ArgNumber || fVal2.Type != ArgNumber {
- continue
- }
- sum1 += fVal1.Number
- sum2 += fVal2.Number
- sumSqrD += (fVal1.Number - fVal2.Number) * (fVal1.Number - fVal2.Number)
- cnt++
- }
- }
- if cnt < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- sumD := sum1 - sum2
- divider := cnt*sumSqrD - sumD*sumD
- if divider == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- fT = math.Abs(sumD) * math.Sqrt((cnt-1)/divider)
- fF = cnt - 1
- } else if fTyp == 2 {
- fT, fF, ok = tTest(false, mtx1, mtx2, c1, c2, r1, r2)
- } else {
- fT, fF, ok = tTest(true, mtx1, mtx2, c1, c2, r1, r2)
- }
- if !ok {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(getTDist(fT, fF, fTails))
- }
- // TTEST function calculates the probability associated with the Student's T
- // Test, which is commonly used for identifying whether two data sets are
- // likely to have come from the same two underlying populations with the same
- // mean. The syntax of the function is:
- //
- // TTEST(array1,array2,tails,type)
- func (fn *formulaFuncs) TTEST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "TTEST requires 4 arguments")
- }
- var array1, array2, tails, typeArg formulaArg
- array1 = argsList.Front().Value.(formulaArg)
- array2 = argsList.Front().Next().Value.(formulaArg)
- if tails = argsList.Front().Next().Next().Value.(formulaArg); tails.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if typeArg = argsList.Back().Value.(formulaArg); typeArg.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if len(array1.Matrix) == 0 || len(array2.Matrix) == 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if tails.Number != 1 && tails.Number != 2 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if typeArg.Number != 1 && typeArg.Number != 2 && typeArg.Number != 3 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return fn.tTest(array1.Matrix, array2.Matrix, tails.Number, typeArg.Number)
- }
- // TdotTEST function calculates the probability associated with the Student's T
- // Test, which is commonly used for identifying whether two data sets are
- // likely to have come from the same two underlying populations with the same
- // mean. The syntax of the function is:
- //
- // T.TEST(array1,array2,tails,type)
- func (fn *formulaFuncs) TdotTEST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "T.TEST requires 4 arguments")
- }
- return fn.TTEST(argsList)
- }
- // TRIMMEAN function calculates the trimmed mean (or truncated mean) of a
- // supplied set of values. The syntax of the function is:
- //
- // TRIMMEAN(array,percent)
- func (fn *formulaFuncs) TRIMMEAN(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "TRIMMEAN requires 2 arguments")
- }
- percent := argsList.Back().Value.(formulaArg).ToNumber()
- if percent.Type != ArgNumber {
- return percent
- }
- if percent.Number < 0 || percent.Number >= 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- var arr []float64
- arrArg := argsList.Front().Value.(formulaArg).ToList()
- for _, cell := range arrArg {
- if cell.Type != ArgNumber {
- continue
- }
- arr = append(arr, cell.Number)
- }
- discard := math.Floor(float64(len(arr)) * percent.Number / 2)
- sort.Float64s(arr)
- for i := 0; i < int(discard); i++ {
- if len(arr) > 0 {
- arr = arr[1:]
- }
- if len(arr) > 0 {
- arr = arr[:len(arr)-1]
- }
- }
- args := list.New().Init()
- for _, ele := range arr {
- args.PushBack(newNumberFormulaArg(ele))
- }
- return fn.AVERAGE(args)
- }
- // vars is an implementation of the formula functions VAR, VARA, VARP, VAR.P
- // VAR.S and VARPA.
- func (fn *formulaFuncs) vars(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
- }
- summerA, summerB, count := 0.0, 0.0, 0.0
- minimum := 0.0
- if name == "VAR" || name == "VAR.S" || name == "VARA" {
- minimum = 1.0
- }
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- for _, token := range arg.Value.(formulaArg).ToList() {
- if token.Value() == "" {
- continue
- }
- num := token.ToNumber()
- if token.Value() != "TRUE" && num.Type == ArgNumber {
- summerA += num.Number * num.Number
- summerB += num.Number
- count++
- continue
- }
- num = token.ToBool()
- if num.Type == ArgNumber {
- summerA += num.Number * num.Number
- summerB += num.Number
- count++
- continue
- }
- if name == "VARA" || name == "VARPA" {
- count++
- }
- }
- }
- if count > minimum {
- summerA *= count
- summerB *= summerB
- return newNumberFormulaArg((summerA - summerB) / (count * (count - minimum)))
- }
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- // VAR function returns the sample variance of a supplied set of values. The
- // syntax of the function is:
- //
- // VAR(number1,[number2],...)
- func (fn *formulaFuncs) VAR(argsList *list.List) formulaArg {
- return fn.vars("VAR", argsList)
- }
- // VARA function calculates the sample variance of a supplied set of values.
- // The syntax of the function is:
- //
- // VARA(number1,[number2],...)
- func (fn *formulaFuncs) VARA(argsList *list.List) formulaArg {
- return fn.vars("VARA", argsList)
- }
- // VARP function returns the Variance of a given set of values. The syntax of
- // the function is:
- //
- // VARP(number1,[number2],...)
- func (fn *formulaFuncs) VARP(argsList *list.List) formulaArg {
- return fn.vars("VARP", argsList)
- }
- // VARdotP function returns the Variance of a given set of values. The syntax
- // of the function is:
- //
- // VAR.P(number1,[number2],...)
- func (fn *formulaFuncs) VARdotP(argsList *list.List) formulaArg {
- return fn.vars("VAR.P", argsList)
- }
- // VARdotS function calculates the sample variance of a supplied set of
- // values. The syntax of the function is:
- //
- // VAR.S(number1,[number2],...)
- func (fn *formulaFuncs) VARdotS(argsList *list.List) formulaArg {
- return fn.vars("VAR.S", argsList)
- }
- // VARPA function returns the Variance of a given set of values. The syntax of
- // the function is:
- //
- // VARPA(number1,[number2],...)
- func (fn *formulaFuncs) VARPA(argsList *list.List) formulaArg {
- return fn.vars("VARPA", argsList)
- }
- // WEIBULL function calculates the Weibull Probability Density Function or the
- // Weibull Cumulative Distribution Function for a supplied set of parameters.
- // The syntax of the function is:
- //
- // WEIBULL(x,alpha,beta,cumulative)
- func (fn *formulaFuncs) WEIBULL(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "WEIBULL requires 4 arguments")
- }
- x := argsList.Front().Value.(formulaArg).ToNumber()
- alpha := argsList.Front().Next().Value.(formulaArg).ToNumber()
- beta := argsList.Back().Prev().Value.(formulaArg).ToNumber()
- if alpha.Type == ArgNumber && beta.Type == ArgNumber && x.Type == ArgNumber {
- if alpha.Number < 0 || alpha.Number <= 0 || beta.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- cumulative := argsList.Back().Value.(formulaArg).ToBool()
- if cumulative.Boolean && cumulative.Number == 1 {
- return newNumberFormulaArg(1 - math.Exp(0-math.Pow(x.Number/beta.Number, alpha.Number)))
- }
- return newNumberFormulaArg((alpha.Number / math.Pow(beta.Number, alpha.Number)) *
- math.Pow(x.Number, alpha.Number-1) * math.Exp(0-math.Pow(x.Number/beta.Number, alpha.Number)))
- }
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- // WEIBULLdotDIST function calculates the Weibull Probability Density Function
- // or the Weibull Cumulative Distribution Function for a supplied set of
- // parameters. The syntax of the function is:
- //
- // WEIBULL.DIST(x,alpha,beta,cumulative)
- func (fn *formulaFuncs) WEIBULLdotDIST(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "WEIBULL.DIST requires 4 arguments")
- }
- return fn.WEIBULL(argsList)
- }
- // ZdotTEST function calculates the one-tailed probability value of the
- // Z-Test. The syntax of the function is:
- //
- // Z.TEST(array,x,[sigma])
- func (fn *formulaFuncs) ZdotTEST(argsList *list.List) formulaArg {
- argsLen := argsList.Len()
- if argsLen < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "Z.TEST requires at least 2 arguments")
- }
- if argsLen > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "Z.TEST accepts at most 3 arguments")
- }
- return fn.ZTEST(argsList)
- }
- // ZTEST function calculates the one-tailed probability value of the Z-Test.
- // The syntax of the function is:
- //
- // ZTEST(array,x,[sigma])
- func (fn *formulaFuncs) ZTEST(argsList *list.List) formulaArg {
- argsLen := argsList.Len()
- if argsLen < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "ZTEST requires at least 2 arguments")
- }
- if argsLen > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "ZTEST accepts at most 3 arguments")
- }
- arrArg, arrArgs := argsList.Front().Value.(formulaArg), list.New()
- arrArgs.PushBack(arrArg)
- arr := fn.AVERAGE(arrArgs)
- if arr.Type == ArgError {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- x := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if x.Type == ArgError {
- return x
- }
- sigma := argsList.Back().Value.(formulaArg).ToNumber()
- if sigma.Type == ArgError {
- return sigma
- }
- if argsLen != 3 {
- sigma = fn.STDEV(arrArgs).ToNumber()
- }
- normsdistArg := list.New()
- div := sigma.Number / math.Sqrt(float64(len(arrArg.ToList())))
- if div == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- normsdistArg.PushBack(newNumberFormulaArg((arr.Number - x.Number) / div))
- return newNumberFormulaArg(1 - fn.NORMSDIST(normsdistArg).Number)
- }
- // Information Functions
- // ERRORdotTYPE function receives an error value and returns an integer, that
- // tells you the type of the supplied error. The syntax of the function is:
- //
- // ERROR.TYPE(error_val)
- func (fn *formulaFuncs) ERRORdotTYPE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ERROR.TYPE requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- if token.Type == ArgError {
- for i, errType := range []string{
- formulaErrorNULL, formulaErrorDIV, formulaErrorVALUE, formulaErrorREF,
- formulaErrorNAME, formulaErrorNUM, formulaErrorNA,
- } {
- if errType == token.String {
- return newNumberFormulaArg(float64(i) + 1)
- }
- }
- }
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- // ISBLANK function tests if a specified cell is blank (empty) and if so,
- // returns TRUE; Otherwise the function returns FALSE. The syntax of the
- // function is:
- //
- // ISBLANK(value)
- func (fn *formulaFuncs) ISBLANK(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISBLANK requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- switch token.Type {
- case ArgUnknown, ArgEmpty:
- return newBoolFormulaArg(true)
- default:
- return newBoolFormulaArg(false)
- }
- }
- // ISERR function tests if an initial supplied expression (or value) returns
- // any Excel Error, except the #N/A error. If so, the function returns the
- // logical value TRUE; If the supplied value is not an error or is the #N/A
- // error, the ISERR function returns FALSE. The syntax of the function is:
- //
- // ISERR(value)
- func (fn *formulaFuncs) ISERR(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISERR requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- result := false
- if token.Type == ArgError {
- for _, errType := range []string{
- formulaErrorDIV, formulaErrorNAME, formulaErrorNUM,
- formulaErrorVALUE, formulaErrorREF, formulaErrorNULL,
- formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA,
- } {
- if errType == token.String {
- result = true
- }
- }
- }
- return newBoolFormulaArg(result)
- }
- // ISERROR function tests if an initial supplied expression (or value) returns
- // an Excel Error, and if so, returns the logical value TRUE; Otherwise the
- // function returns FALSE. The syntax of the function is:
- //
- // ISERROR(value)
- func (fn *formulaFuncs) ISERROR(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISERROR requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- result := false
- if token.Type == ArgError {
- for _, errType := range []string{
- formulaErrorDIV, formulaErrorNAME, formulaErrorNA, formulaErrorNUM,
- formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL,
- formulaErrorCALC, formulaErrorGETTINGDATA,
- } {
- if errType == token.String {
- result = true
- }
- }
- }
- return newBoolFormulaArg(result)
- }
- // ISEVEN function tests if a supplied number (or numeric expression)
- // evaluates to an even number, and if so, returns TRUE; Otherwise, the
- // function returns FALSE. The syntax of the function is:
- //
- // ISEVEN(value)
- func (fn *formulaFuncs) ISEVEN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISEVEN requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- switch token.Type {
- case ArgEmpty:
- return newBoolFormulaArg(true)
- case ArgNumber, ArgString:
- num := token.ToNumber()
- if num.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if num.Number == 1 {
- return newBoolFormulaArg(false)
- }
- return newBoolFormulaArg(num.Number == num.Number/2*2)
- default:
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- // ISFORMULA function tests if a specified cell contains a formula, and if so,
- // returns TRUE; Otherwise, the function returns FALSE. The syntax of the
- // function is:
- //
- // ISFORMULA(reference)
- func (fn *formulaFuncs) ISFORMULA(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISFORMULA requires 1 argument")
- }
- arg := argsList.Front().Value.(formulaArg)
- if arg.cellRefs != nil && arg.cellRefs.Len() == 1 {
- ref := arg.cellRefs.Front().Value.(cellRef)
- cell, _ := CoordinatesToCellName(ref.Col, ref.Row)
- if formula, _ := fn.f.GetCellFormula(ref.Sheet, cell); len(formula) > 0 {
- return newBoolFormulaArg(true)
- }
- }
- return newBoolFormulaArg(false)
- }
- // ISLOGICAL function tests if a supplied value (or expression) returns a
- // logical value (i.e. evaluates to True or False). If so, the function
- // returns TRUE; Otherwise, it returns FALSE. The syntax of the function is:
- //
- // ISLOGICAL(value)
- func (fn *formulaFuncs) ISLOGICAL(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISLOGICAL requires 1 argument")
- }
- val := argsList.Front().Value.(formulaArg).Value()
- if strings.EqualFold("TRUE", val) || strings.EqualFold("FALSE", val) {
- return newBoolFormulaArg(true)
- }
- return newBoolFormulaArg(false)
- }
- // ISNA function tests if an initial supplied expression (or value) returns
- // the Excel #N/A Error, and if so, returns TRUE; Otherwise the function
- // returns FALSE. The syntax of the function is:
- //
- // ISNA(value)
- func (fn *formulaFuncs) ISNA(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISNA requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- result := "FALSE"
- if token.Type == ArgError && token.String == formulaErrorNA {
- result = "TRUE"
- }
- return newStringFormulaArg(result)
- }
- // ISNONTEXT function tests if a supplied value is text. If not, the
- // function returns TRUE; If the supplied value is text, the function returns
- // FALSE. The syntax of the function is:
- //
- // ISNONTEXT(value)
- func (fn *formulaFuncs) ISNONTEXT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISNONTEXT requires 1 argument")
- }
- if argsList.Front().Value.(formulaArg).Type == ArgString {
- return newBoolFormulaArg(false)
- }
- return newBoolFormulaArg(true)
- }
- // ISNUMBER function tests if a supplied value is a number. If so,
- // the function returns TRUE; Otherwise it returns FALSE. The syntax of the
- // function is:
- //
- // ISNUMBER(value)
- func (fn *formulaFuncs) ISNUMBER(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISNUMBER requires 1 argument")
- }
- if argsList.Front().Value.(formulaArg).Type == ArgNumber {
- return newBoolFormulaArg(true)
- }
- return newBoolFormulaArg(false)
- }
- // ISODD function tests if a supplied number (or numeric expression) evaluates
- // to an odd number, and if so, returns TRUE; Otherwise, the function returns
- // FALSE. The syntax of the function is:
- //
- // ISODD(value)
- func (fn *formulaFuncs) ISODD(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISODD requires 1 argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if int(arg.Number) != int(arg.Number)/2*2 {
- return newBoolFormulaArg(true)
- }
- return newBoolFormulaArg(false)
- }
- // ISREF function tests if a supplied value is a reference. If so, the
- // function returns TRUE; Otherwise it returns FALSE. The syntax of the
- // function is:
- //
- // ISREF(value)
- func (fn *formulaFuncs) ISREF(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISREF requires 1 argument")
- }
- arg := argsList.Front().Value.(formulaArg)
- if arg.cellRanges != nil && arg.cellRanges.Len() > 0 || arg.cellRefs != nil && arg.cellRefs.Len() > 0 {
- return newBoolFormulaArg(true)
- }
- return newBoolFormulaArg(false)
- }
- // ISTEXT function tests if a supplied value is text, and if so, returns TRUE;
- // Otherwise, the function returns FALSE. The syntax of the function is:
- //
- // ISTEXT(value)
- func (fn *formulaFuncs) ISTEXT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISTEXT requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- if token.ToNumber().Type != ArgError {
- return newBoolFormulaArg(false)
- }
- return newBoolFormulaArg(token.Type == ArgString)
- }
- // N function converts data into a numeric value. The syntax of the function
- // is:
- //
- // N(value)
- func (fn *formulaFuncs) N(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "N requires 1 argument")
- }
- token, num := argsList.Front().Value.(formulaArg), 0.0
- if token.Type == ArgError {
- return token
- }
- if arg := token.ToNumber(); arg.Type == ArgNumber {
- num = arg.Number
- }
- if token.Value() == "TRUE" {
- num = 1
- }
- return newNumberFormulaArg(num)
- }
- // NA function returns the Excel #N/A error. This error message has the
- // meaning 'value not available' and is produced when an Excel Formula is
- // unable to find a value that it needs. The syntax of the function is:
- //
- // NA()
- func (fn *formulaFuncs) NA(argsList *list.List) formulaArg {
- if argsList.Len() != 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "NA accepts no arguments")
- }
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- // SHEET function returns the Sheet number for a specified reference. The
- // syntax of the function is:
- //
- // SHEET([value])
- func (fn *formulaFuncs) SHEET(argsList *list.List) formulaArg {
- if argsList.Len() > 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SHEET accepts at most 1 argument")
- }
- if argsList.Len() == 0 {
- idx, _ := fn.f.GetSheetIndex(fn.sheet)
- return newNumberFormulaArg(float64(idx + 1))
- }
- arg := argsList.Front().Value.(formulaArg)
- if sheetIdx, _ := fn.f.GetSheetIndex(arg.Value()); sheetIdx != -1 {
- return newNumberFormulaArg(float64(sheetIdx + 1))
- }
- if arg.cellRanges != nil && arg.cellRanges.Len() > 0 {
- if sheetIdx, _ := fn.f.GetSheetIndex(arg.cellRanges.Front().Value.(cellRange).From.Sheet); sheetIdx != -1 {
- return newNumberFormulaArg(float64(sheetIdx + 1))
- }
- }
- if arg.cellRefs != nil && arg.cellRefs.Len() > 0 {
- if sheetIdx, _ := fn.f.GetSheetIndex(arg.cellRefs.Front().Value.(cellRef).Sheet); sheetIdx != -1 {
- return newNumberFormulaArg(float64(sheetIdx + 1))
- }
- }
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- // SHEETS function returns the number of sheets in a supplied reference. The
- // result includes sheets that are Visible, Hidden or Very Hidden. The syntax
- // of the function is:
- //
- // SHEETS([reference])
- func (fn *formulaFuncs) SHEETS(argsList *list.List) formulaArg {
- if argsList.Len() > 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SHEETS accepts at most 1 argument")
- }
- if argsList.Len() == 0 {
- return newNumberFormulaArg(float64(len(fn.f.GetSheetList())))
- }
- arg := argsList.Front().Value.(formulaArg)
- sheetMap := map[string]struct{}{}
- if arg.cellRanges != nil && arg.cellRanges.Len() > 0 {
- for rng := arg.cellRanges.Front(); rng != nil; rng = rng.Next() {
- sheetMap[rng.Value.(cellRange).From.Sheet] = struct{}{}
- }
- }
- if arg.cellRefs != nil && arg.cellRefs.Len() > 0 {
- for ref := arg.cellRefs.Front(); ref != nil; ref = ref.Next() {
- sheetMap[ref.Value.(cellRef).Sheet] = struct{}{}
- }
- }
- if len(sheetMap) > 0 {
- return newNumberFormulaArg(float64(len(sheetMap)))
- }
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- // TYPE function returns an integer that represents the value's data type. The
- // syntax of the function is:
- //
- // TYPE(value)
- func (fn *formulaFuncs) TYPE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "TYPE requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- switch token.Type {
- case ArgError:
- return newNumberFormulaArg(16)
- case ArgMatrix:
- return newNumberFormulaArg(64)
- case ArgNumber, ArgEmpty:
- if token.Boolean {
- return newNumberFormulaArg(4)
- }
- return newNumberFormulaArg(1)
- default:
- return newNumberFormulaArg(2)
- }
- }
- // T function tests if a supplied value is text and if so, returns the
- // supplied text; Otherwise, the function returns an empty text string. The
- // syntax of the function is:
- //
- // T(value)
- func (fn *formulaFuncs) T(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "T requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- if token.Type == ArgError {
- return token
- }
- if token.Type == ArgNumber {
- return newStringFormulaArg("")
- }
- return newStringFormulaArg(token.Value())
- }
- // Logical Functions
- // AND function tests a number of supplied conditions and returns TRUE or
- // FALSE. The syntax of the function is:
- //
- // AND(logical_test1,[logical_test2],...)
- func (fn *formulaFuncs) AND(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "AND requires at least 1 argument")
- }
- if argsList.Len() > 30 {
- return newErrorFormulaArg(formulaErrorVALUE, "AND accepts at most 30 arguments")
- }
- and := true
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgUnknown:
- continue
- case ArgString:
- if token.String == "TRUE" {
- continue
- }
- if token.String == "FALSE" {
- return newStringFormulaArg(token.String)
- }
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- case ArgNumber:
- and = and && token.Number != 0
- case ArgMatrix:
- // TODO
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- return newBoolFormulaArg(and)
- }
- // FALSE function returns the logical value FALSE. The syntax of the
- // function is:
- //
- // FALSE()
- func (fn *formulaFuncs) FALSE(argsList *list.List) formulaArg {
- if argsList.Len() != 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "FALSE takes no arguments")
- }
- return newBoolFormulaArg(false)
- }
- // IFERROR function receives two values (or expressions) and tests if the
- // first of these evaluates to an error. The syntax of the function is:
- //
- // IFERROR(value,value_if_error)
- func (fn *formulaFuncs) IFERROR(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "IFERROR requires 2 arguments")
- }
- value := argsList.Front().Value.(formulaArg)
- if value.Type != ArgError {
- if value.Type == ArgEmpty {
- return newNumberFormulaArg(0)
- }
- return value
- }
- return argsList.Back().Value.(formulaArg)
- }
- // IFNA function tests if an initial supplied value (or expression) evaluates
- // to the Excel #N/A error. If so, the function returns a second supplied
- // value; Otherwise the function returns the first supplied value. The syntax
- // of the function is:
- //
- // IFNA(value,value_if_na)
- func (fn *formulaFuncs) IFNA(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "IFNA requires 2 arguments")
- }
- arg := argsList.Front().Value.(formulaArg)
- if arg.Type == ArgError && arg.String == formulaErrorNA {
- return argsList.Back().Value.(formulaArg)
- }
- return arg
- }
- // IFS function tests a number of supplied conditions and returns the result
- // corresponding to the first condition that evaluates to TRUE. If none of
- // the supplied conditions evaluate to TRUE, the function returns the #N/A
- // error.
- //
- // IFS(logical_test1,value_if_true1,[logical_test2,value_if_true2],...)
- func (fn *formulaFuncs) IFS(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "IFS requires at least 2 arguments")
- }
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- if arg.Value.(formulaArg).ToBool().Number == 1 {
- return arg.Next().Value.(formulaArg)
- }
- arg = arg.Next()
- }
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- // NOT function returns the opposite to a supplied logical value. The syntax
- // of the function is:
- //
- // NOT(logical)
- func (fn *formulaFuncs) NOT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "NOT requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg)
- switch token.Type {
- case ArgString, ArgList:
- if strings.ToUpper(token.String) == "TRUE" {
- return newBoolFormulaArg(false)
- }
- if strings.ToUpper(token.String) == "FALSE" {
- return newBoolFormulaArg(true)
- }
- case ArgNumber:
- return newBoolFormulaArg(!(token.Number != 0))
- case ArgError:
- return token
- }
- return newErrorFormulaArg(formulaErrorVALUE, "NOT expects 1 boolean or numeric argument")
- }
- // OR function tests a number of supplied conditions and returns either TRUE
- // or FALSE. The syntax of the function is:
- //
- // OR(logical_test1,[logical_test2],...)
- func (fn *formulaFuncs) OR(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "OR requires at least 1 argument")
- }
- if argsList.Len() > 30 {
- return newErrorFormulaArg(formulaErrorVALUE, "OR accepts at most 30 arguments")
- }
- var or bool
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgUnknown:
- continue
- case ArgString:
- if token.String == "FALSE" {
- continue
- }
- if token.String == "TRUE" {
- or = true
- continue
- }
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- case ArgNumber:
- if or = token.Number != 0; or {
- return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(or)))
- }
- case ArgMatrix:
- // TODO
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(or)))
- }
- // SWITCH function compares a number of supplied values to a supplied test
- // expression and returns a result corresponding to the first value that
- // matches the test expression. A default value can be supplied, to be
- // returned if none of the supplied values match the test expression. The
- // syntax of the function is:
- //
- // SWITCH(expression,value1,result1,[value2,result2],[value3,result3],...,[default])
- func (fn *formulaFuncs) SWITCH(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "SWITCH requires at least 3 arguments")
- }
- target := argsList.Front().Value.(formulaArg)
- argCount := argsList.Len() - 1
- switchCount := int(math.Floor(float64(argCount) / 2))
- hasDefaultClause := argCount%2 != 0
- result := newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- if hasDefaultClause {
- result = argsList.Back().Value.(formulaArg)
- }
- if switchCount > 0 {
- arg := argsList.Front()
- for i := 0; i < switchCount; i++ {
- arg = arg.Next()
- if target.Value() == arg.Value.(formulaArg).Value() {
- result = arg.Next().Value.(formulaArg)
- break
- }
- arg = arg.Next()
- }
- }
- return result
- }
- // TRUE function returns the logical value TRUE. The syntax of the function
- // is:
- //
- // TRUE()
- func (fn *formulaFuncs) TRUE(argsList *list.List) formulaArg {
- if argsList.Len() != 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "TRUE takes no arguments")
- }
- return newBoolFormulaArg(true)
- }
- // calcXor checking if numeric cell exists and count it by given arguments
- // sequence for the formula function XOR.
- func calcXor(argsList *list.List) formulaArg {
- count, ok := 0, false
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgError:
- return token
- case ArgNumber:
- ok = true
- if token.Number != 0 {
- count++
- }
- case ArgMatrix:
- for _, value := range token.ToList() {
- if num := value.ToNumber(); num.Type == ArgNumber {
- ok = true
- if num.Number != 0 {
- count++
- }
- }
- }
- }
- }
- if !ok {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return newBoolFormulaArg(count%2 != 0)
- }
- // XOR function returns the Exclusive Or logical operation for one or more
- // supplied conditions. I.e. the Xor function returns TRUE if an odd number
- // of the supplied conditions evaluate to TRUE, and FALSE otherwise. The
- // syntax of the function is:
- //
- // XOR(logical_test1,[logical_test2],...)
- func (fn *formulaFuncs) XOR(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "XOR requires at least 1 argument")
- }
- return calcXor(argsList)
- }
- // Date and Time Functions
- // DATE returns a date, from a user-supplied year, month and day. The syntax
- // of the function is:
- //
- // DATE(year,month,day)
- func (fn *formulaFuncs) DATE(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "DATE requires 3 number arguments")
- }
- year := argsList.Front().Value.(formulaArg).ToNumber()
- month := argsList.Front().Next().Value.(formulaArg).ToNumber()
- day := argsList.Back().Value.(formulaArg).ToNumber()
- if year.Type != ArgNumber || month.Type != ArgNumber || day.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, "DATE requires 3 number arguments")
- }
- d := makeDate(int(year.Number), time.Month(month.Number), int(day.Number))
- return newStringFormulaArg(timeFromExcelTime(daysBetween(excelMinTime1900.Unix(), d)+1, false).String())
- }
- // calcDateDif is an implementation of the formula function DATEDIF,
- // calculation difference between two dates.
- func calcDateDif(unit string, diff float64, seq []int, startArg, endArg formulaArg) float64 {
- ey, sy, em, sm, ed, sd := seq[0], seq[1], seq[2], seq[3], seq[4], seq[5]
- switch unit {
- case "d":
- diff = endArg.Number - startArg.Number
- case "md":
- smMD := em
- if ed < sd {
- smMD--
- }
- diff = endArg.Number - daysBetween(excelMinTime1900.Unix(), makeDate(ey, time.Month(smMD), sd)) - 1
- case "ym":
- diff = float64(em - sm)
- if ed < sd {
- diff--
- }
- if diff < 0 {
- diff += 12
- }
- case "yd":
- syYD := sy
- if em < sm || (em == sm && ed < sd) {
- syYD++
- }
- s := daysBetween(excelMinTime1900.Unix(), makeDate(syYD, time.Month(em), ed))
- e := daysBetween(excelMinTime1900.Unix(), makeDate(sy, time.Month(sm), sd))
- diff = s - e
- }
- return diff
- }
- // DATEDIF function calculates the number of days, months, or years between
- // two dates. The syntax of the function is:
- //
- // DATEDIF(start_date,end_date,unit)
- func (fn *formulaFuncs) DATEDIF(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "DATEDIF requires 3 number arguments")
- }
- startArg, endArg := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Front().Next().Value.(formulaArg).ToNumber()
- if startArg.Type != ArgNumber || endArg.Type != ArgNumber {
- return startArg
- }
- if startArg.Number > endArg.Number {
- return newErrorFormulaArg(formulaErrorNUM, "start_date > end_date")
- }
- if startArg.Number == endArg.Number {
- return newNumberFormulaArg(0)
- }
- unit := strings.ToLower(argsList.Back().Value.(formulaArg).Value())
- startDate, endDate := timeFromExcelTime(startArg.Number, false), timeFromExcelTime(endArg.Number, false)
- sy, smm, sd := startDate.Date()
- ey, emm, ed := endDate.Date()
- sm, em, diff := int(smm), int(emm), 0.0
- switch unit {
- case "y":
- diff = float64(ey - sy)
- if em < sm || (em == sm && ed < sd) {
- diff--
- }
- case "m":
- yDiff := ey - sy
- mDiff := em - sm
- if ed < sd {
- mDiff--
- }
- if mDiff < 0 {
- yDiff--
- mDiff += 12
- }
- diff = float64(yDiff*12 + mDiff)
- case "d", "md", "ym", "yd":
- diff = calcDateDif(unit, diff, []int{ey, sy, em, sm, ed, sd}, startArg, endArg)
- default:
- return newErrorFormulaArg(formulaErrorVALUE, "DATEDIF has invalid unit")
- }
- return newNumberFormulaArg(diff)
- }
- // isDateOnlyFmt check if the given string matches date-only format regular expressions.
- func isDateOnlyFmt(dateString string) bool {
- for _, df := range dateOnlyFormats {
- subMatch := df.FindStringSubmatch(dateString)
- if len(subMatch) > 1 {
- return true
- }
- }
- return false
- }
- // isTimeOnlyFmt check if the given string matches time-only format regular expressions.
- func isTimeOnlyFmt(timeString string) bool {
- for _, tf := range timeFormats {
- subMatch := tf.FindStringSubmatch(timeString)
- if len(subMatch) > 1 {
- return true
- }
- }
- return false
- }
- // strToTimePatternHandler1 parse and convert the given string in pattern
- // hh to the time.
- func strToTimePatternHandler1(subMatch []string) (h, m int, s float64, err error) {
- h, err = strconv.Atoi(subMatch[0])
- return
- }
- // strToTimePatternHandler2 parse and convert the given string in pattern
- // hh:mm to the time.
- func strToTimePatternHandler2(subMatch []string) (h, m int, s float64, err error) {
- if h, err = strconv.Atoi(subMatch[0]); err != nil {
- return
- }
- m, err = strconv.Atoi(subMatch[2])
- return
- }
- // strToTimePatternHandler3 parse and convert the given string in pattern
- // mm:ss to the time.
- func strToTimePatternHandler3(subMatch []string) (h, m int, s float64, err error) {
- if m, err = strconv.Atoi(subMatch[0]); err != nil {
- return
- }
- s, err = strconv.ParseFloat(subMatch[2], 64)
- return
- }
- // strToTimePatternHandler4 parse and convert the given string in pattern
- // hh:mm:ss to the time.
- func strToTimePatternHandler4(subMatch []string) (h, m int, s float64, err error) {
- if h, err = strconv.Atoi(subMatch[0]); err != nil {
- return
- }
- if m, err = strconv.Atoi(subMatch[2]); err != nil {
- return
- }
- s, err = strconv.ParseFloat(subMatch[4], 64)
- return
- }
- // strToTime parse and convert the given string to the time.
- func strToTime(str string) (int, int, float64, bool, bool, formulaArg) {
- var subMatch []string
- pattern := ""
- for key, tf := range timeFormats {
- subMatch = tf.FindStringSubmatch(str)
- if len(subMatch) > 1 {
- pattern = key
- break
- }
- }
- if pattern == "" {
- return 0, 0, 0, false, false, newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- dateIsEmpty := subMatch[1] == ""
- subMatch = subMatch[49:]
- var (
- l = len(subMatch)
- last = subMatch[l-1]
- am = last == "am"
- pm = last == "pm"
- hours, minutes int
- seconds float64
- err error
- )
- if handler, ok := map[string]func(match []string) (int, int, float64, error){
- "hh": strToTimePatternHandler1,
- "hh:mm": strToTimePatternHandler2,
- "mm:ss": strToTimePatternHandler3,
- "hh:mm:ss": strToTimePatternHandler4,
- }[pattern]; ok {
- if hours, minutes, seconds, err = handler(subMatch); err != nil {
- return 0, 0, 0, false, false, newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- if minutes >= 60 {
- return 0, 0, 0, false, false, newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if am || pm {
- if hours > 12 || seconds >= 60 {
- return 0, 0, 0, false, false, newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- } else if hours == 12 {
- hours = 0
- }
- } else if hours >= 24 || seconds >= 10000 {
- return 0, 0, 0, false, false, newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return hours, minutes, seconds, pm, dateIsEmpty, newEmptyFormulaArg()
- }
- // strToDatePatternHandler1 parse and convert the given string in pattern
- // mm/dd/yy to the date.
- func strToDatePatternHandler1(subMatch []string) (int, int, int, bool, error) {
- var year, month, day int
- var err error
- if month, err = strconv.Atoi(subMatch[1]); err != nil {
- return 0, 0, 0, false, err
- }
- if day, err = strconv.Atoi(subMatch[3]); err != nil {
- return 0, 0, 0, false, err
- }
- if year, err = strconv.Atoi(subMatch[5]); err != nil {
- return 0, 0, 0, false, err
- }
- if year < 0 || year > 9999 || (year > 99 && year < 1900) {
- return 0, 0, 0, false, ErrParameterInvalid
- }
- return formatYear(year), month, day, subMatch[8] == "", err
- }
- // strToDatePatternHandler2 parse and convert the given string in pattern mm
- // dd, yy to the date.
- func strToDatePatternHandler2(subMatch []string) (int, int, int, bool, error) {
- var year, month, day int
- var err error
- month = month2num[subMatch[1]]
- if day, err = strconv.Atoi(subMatch[14]); err != nil {
- return 0, 0, 0, false, err
- }
- if year, err = strconv.Atoi(subMatch[16]); err != nil {
- return 0, 0, 0, false, err
- }
- if year < 0 || year > 9999 || (year > 99 && year < 1900) {
- return 0, 0, 0, false, ErrParameterInvalid
- }
- return formatYear(year), month, day, subMatch[19] == "", err
- }
- // strToDatePatternHandler3 parse and convert the given string in pattern
- // yy-mm-dd to the date.
- func strToDatePatternHandler3(subMatch []string) (int, int, int, bool, error) {
- var year, month, day int
- v1, err := strconv.Atoi(subMatch[1])
- if err != nil {
- return 0, 0, 0, false, err
- }
- v2, err := strconv.Atoi(subMatch[3])
- if err != nil {
- return 0, 0, 0, false, err
- }
- v3, err := strconv.Atoi(subMatch[5])
- if err != nil {
- return 0, 0, 0, false, err
- }
- if v1 >= 1900 && v1 < 10000 {
- year = v1
- month = v2
- day = v3
- } else if v1 > 0 && v1 < 13 {
- month = v1
- day = v2
- year = v3
- } else {
- return 0, 0, 0, false, ErrParameterInvalid
- }
- return year, month, day, subMatch[8] == "", err
- }
- // strToDatePatternHandler4 parse and convert the given string in pattern
- // yy-mmStr-dd, yy to the date.
- func strToDatePatternHandler4(subMatch []string) (int, int, int, bool, error) {
- var year, month, day int
- var err error
- if year, err = strconv.Atoi(subMatch[16]); err != nil {
- return 0, 0, 0, false, err
- }
- month = month2num[subMatch[3]]
- if day, err = strconv.Atoi(subMatch[1]); err != nil {
- return 0, 0, 0, false, err
- }
- return formatYear(year), month, day, subMatch[19] == "", err
- }
- // strToDate parse and convert the given string to the date.
- func strToDate(str string) (int, int, int, bool, formulaArg) {
- var subMatch []string
- pattern := ""
- for key, df := range dateFormats {
- subMatch = df.FindStringSubmatch(str)
- if len(subMatch) > 1 {
- pattern = key
- break
- }
- }
- if pattern == "" {
- return 0, 0, 0, false, newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- var (
- timeIsEmpty bool
- year, month, day int
- err error
- )
- if handler, ok := map[string]func(match []string) (int, int, int, bool, error){
- "mm/dd/yy": strToDatePatternHandler1,
- "mm dd, yy": strToDatePatternHandler2,
- "yy-mm-dd": strToDatePatternHandler3,
- "yy-mmStr-dd": strToDatePatternHandler4,
- }[pattern]; ok {
- if year, month, day, timeIsEmpty, err = handler(subMatch); err != nil {
- return 0, 0, 0, false, newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- if !validateDate(year, month, day) {
- return 0, 0, 0, false, newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return year, month, day, timeIsEmpty, newEmptyFormulaArg()
- }
- // DATEVALUE function converts a text representation of a date into an Excel
- // date. For example, the function converts a text string representing a
- // date, into the serial number that represents the date in Excels' date-time
- // code. The syntax of the function is:
- //
- // DATEVALUE(date_text)
- func (fn *formulaFuncs) DATEVALUE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "DATEVALUE requires 1 argument")
- }
- dateText := argsList.Front().Value.(formulaArg).Value()
- if !isDateOnlyFmt(dateText) {
- if _, _, _, _, _, err := strToTime(dateText); err.Type == ArgError {
- return err
- }
- }
- y, m, d, _, err := strToDate(dateText)
- if err.Type == ArgError {
- return err
- }
- return newNumberFormulaArg(daysBetween(excelMinTime1900.Unix(), makeDate(y, time.Month(m), d)) + 1)
- }
- // DAY function returns the day of a date, represented by a serial number. The
- // day is given as an integer ranging from 1 to 31. The syntax of the
- // function is:
- //
- // DAY(serial_number)
- func (fn *formulaFuncs) DAY(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "DAY requires exactly 1 argument")
- }
- arg := argsList.Front().Value.(formulaArg)
- num := arg.ToNumber()
- if num.Type != ArgNumber {
- dateString := strings.ToLower(arg.Value())
- if !isDateOnlyFmt(dateString) {
- if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
- return err
- }
- }
- _, _, day, _, err := strToDate(dateString)
- if err.Type == ArgError {
- return err
- }
- return newNumberFormulaArg(float64(day))
- }
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "DAY only accepts positive argument")
- }
- if num.Number <= 60 {
- return newNumberFormulaArg(math.Mod(num.Number, 31.0))
- }
- return newNumberFormulaArg(float64(timeFromExcelTime(num.Number, false).Day()))
- }
- // DAYS function returns the number of days between two supplied dates. The
- // syntax of the function is:
- //
- // DAYS(end_date,start_date)
- func (fn *formulaFuncs) DAYS(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "DAYS requires 2 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- end, start := args.List[0], args.List[1]
- return newNumberFormulaArg(end.Number - start.Number)
- }
- // DAYS360 function returns the number of days between 2 dates, based on a
- // 360-day year (12 x 30 months). The syntax of the function is:
- //
- // DAYS360(start_date,end_date,[method])
- func (fn *formulaFuncs) DAYS360(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "DAYS360 requires at least 2 arguments")
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "DAYS360 requires at most 3 arguments")
- }
- startDate := toExcelDateArg(argsList.Front().Value.(formulaArg))
- if startDate.Type != ArgNumber {
- return startDate
- }
- endDate := toExcelDateArg(argsList.Front().Next().Value.(formulaArg))
- if endDate.Type != ArgNumber {
- return endDate
- }
- start, end := timeFromExcelTime(startDate.Number, false), timeFromExcelTime(endDate.Number, false)
- sy, sm, sd, ey, em, ed := start.Year(), int(start.Month()), start.Day(), end.Year(), int(end.Month()), end.Day()
- method := newBoolFormulaArg(false)
- if argsList.Len() > 2 {
- if method = argsList.Back().Value.(formulaArg).ToBool(); method.Type != ArgNumber {
- return method
- }
- }
- if method.Number == 1 {
- if sd == 31 {
- sd--
- }
- if ed == 31 {
- ed--
- }
- } else {
- if getDaysInMonth(sy, sm) == sd {
- sd = 30
- }
- if ed > 30 {
- if sd < 30 {
- em++
- ed = 1
- } else {
- ed = 30
- }
- }
- }
- return newNumberFormulaArg(float64(360*(ey-sy) + 30*(em-sm) + (ed - sd)))
- }
- // ISOWEEKNUM function returns the ISO week number of a supplied date. The
- // syntax of the function is:
- //
- // ISOWEEKNUM(date)
- func (fn *formulaFuncs) ISOWEEKNUM(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISOWEEKNUM requires 1 argument")
- }
- date := argsList.Front().Value.(formulaArg)
- num := date.ToNumber()
- weekNum := 0
- if num.Type != ArgNumber {
- dateString := strings.ToLower(date.Value())
- if !isDateOnlyFmt(dateString) {
- if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
- return err
- }
- }
- y, m, d, _, err := strToDate(dateString)
- if err.Type == ArgError {
- return err
- }
- _, weekNum = time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.UTC).ISOWeek()
- } else {
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- _, weekNum = timeFromExcelTime(num.Number, false).ISOWeek()
- }
- return newNumberFormulaArg(float64(weekNum))
- }
- // EDATE function returns a date that is a specified number of months before or
- // after a supplied start date. The syntax of function is:
- //
- // EDATE(start_date,months)
- func (fn *formulaFuncs) EDATE(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "EDATE requires 2 arguments")
- }
- date := argsList.Front().Value.(formulaArg)
- num := date.ToNumber()
- var dateTime time.Time
- if num.Type != ArgNumber {
- dateString := strings.ToLower(date.Value())
- if !isDateOnlyFmt(dateString) {
- if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
- return err
- }
- }
- y, m, d, _, err := strToDate(dateString)
- if err.Type == ArgError {
- return err
- }
- dateTime = time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Now().Location())
- } else {
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- dateTime = timeFromExcelTime(num.Number, false)
- }
- month := argsList.Back().Value.(formulaArg).ToNumber()
- if month.Type != ArgNumber {
- return month
- }
- y, d := dateTime.Year(), dateTime.Day()
- m := int(dateTime.Month()) + int(month.Number)
- if month.Number < 0 {
- y -= int(math.Ceil(-1 * float64(m) / 12))
- }
- if month.Number > 11 {
- y += int(math.Floor(float64(m) / 12))
- }
- if m = m % 12; m < 0 {
- m += 12
- }
- if d > 28 {
- if days := getDaysInMonth(y, m); d > days {
- d = days
- }
- }
- result, _ := timeToExcelTime(time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.UTC), false)
- return newNumberFormulaArg(result)
- }
- // EOMONTH function returns the last day of the month, that is a specified
- // number of months before or after an initial supplied start date. The syntax
- // of the function is:
- //
- // EOMONTH(start_date,months)
- func (fn *formulaFuncs) EOMONTH(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "EOMONTH requires 2 arguments")
- }
- date := argsList.Front().Value.(formulaArg)
- num := date.ToNumber()
- var dateTime time.Time
- if num.Type != ArgNumber {
- dateString := strings.ToLower(date.Value())
- if !isDateOnlyFmt(dateString) {
- if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
- return err
- }
- }
- y, m, d, _, err := strToDate(dateString)
- if err.Type == ArgError {
- return err
- }
- dateTime = time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Now().Location())
- } else {
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- dateTime = timeFromExcelTime(num.Number, false)
- }
- months := argsList.Back().Value.(formulaArg).ToNumber()
- if months.Type != ArgNumber {
- return months
- }
- y, m := dateTime.Year(), int(dateTime.Month())+int(months.Number)-1
- if m < 0 {
- y -= int(math.Ceil(-1 * float64(m) / 12))
- }
- if m > 11 {
- y += int(math.Floor(float64(m) / 12))
- }
- if m = m % 12; m < 0 {
- m += 12
- }
- result, _ := timeToExcelTime(time.Date(y, time.Month(m+1), getDaysInMonth(y, m+1), 0, 0, 0, 0, time.UTC), false)
- return newNumberFormulaArg(result)
- }
- // HOUR function returns an integer representing the hour component of a
- // supplied Excel time. The syntax of the function is:
- //
- // HOUR(serial_number)
- func (fn *formulaFuncs) HOUR(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "HOUR requires exactly 1 argument")
- }
- date := argsList.Front().Value.(formulaArg)
- num := date.ToNumber()
- if num.Type != ArgNumber {
- timeString := strings.ToLower(date.Value())
- if !isTimeOnlyFmt(timeString) {
- _, _, _, _, err := strToDate(timeString)
- if err.Type == ArgError {
- return err
- }
- }
- h, _, _, pm, _, err := strToTime(timeString)
- if err.Type == ArgError {
- return err
- }
- if pm {
- h += 12
- }
- return newNumberFormulaArg(float64(h))
- }
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "HOUR only accepts positive argument")
- }
- return newNumberFormulaArg(float64(timeFromExcelTime(num.Number, false).Hour()))
- }
- // MINUTE function returns an integer representing the minute component of a
- // supplied Excel time. The syntax of the function is:
- //
- // MINUTE(serial_number)
- func (fn *formulaFuncs) MINUTE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "MINUTE requires exactly 1 argument")
- }
- date := argsList.Front().Value.(formulaArg)
- num := date.ToNumber()
- if num.Type != ArgNumber {
- timeString := strings.ToLower(date.Value())
- if !isTimeOnlyFmt(timeString) {
- _, _, _, _, err := strToDate(timeString)
- if err.Type == ArgError {
- return err
- }
- }
- _, m, _, _, _, err := strToTime(timeString)
- if err.Type == ArgError {
- return err
- }
- return newNumberFormulaArg(float64(m))
- }
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "MINUTE only accepts positive argument")
- }
- return newNumberFormulaArg(float64(timeFromExcelTime(num.Number, false).Minute()))
- }
- // MONTH function returns the month of a date represented by a serial number.
- // The month is given as an integer, ranging from 1 (January) to 12
- // (December). The syntax of the function is:
- //
- // MONTH(serial_number)
- func (fn *formulaFuncs) MONTH(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "MONTH requires exactly 1 argument")
- }
- arg := argsList.Front().Value.(formulaArg)
- num := arg.ToNumber()
- if num.Type != ArgNumber {
- dateString := strings.ToLower(arg.Value())
- if !isDateOnlyFmt(dateString) {
- if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
- return err
- }
- }
- _, month, _, _, err := strToDate(dateString)
- if err.Type == ArgError {
- return err
- }
- return newNumberFormulaArg(float64(month))
- }
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "MONTH only accepts positive argument")
- }
- return newNumberFormulaArg(float64(timeFromExcelTime(num.Number, false).Month()))
- }
- // genWeekendMask generate weekend mask of a series of seven 0's and 1's which
- // represent the seven weekdays, starting from Monday.
- func genWeekendMask(weekend int) []byte {
- if masks, ok := map[int][]int{
- 1: {5, 6}, 2: {6, 0}, 3: {0, 1}, 4: {1, 2}, 5: {2, 3}, 6: {3, 4}, 7: {4, 5},
- 11: {6}, 12: {0}, 13: {1}, 14: {2}, 15: {3}, 16: {4}, 17: {5},
- }[weekend]; ok {
- mask := make([]byte, 7)
- for _, idx := range masks {
- mask[idx] = 1
- }
- return mask
- }
- return nil
- }
- // isWorkday check if the date is workday.
- func isWorkday(weekendMask []byte, date float64) bool {
- dateTime := timeFromExcelTime(date, false)
- weekday := dateTime.Weekday()
- if weekday == time.Sunday {
- weekday = 7
- }
- return weekendMask[weekday-1] == 0
- }
- // prepareWorkday returns weekend mask and workdays pre week by given days
- // counted as weekend.
- func prepareWorkday(weekend formulaArg) ([]byte, int) {
- weekendArg := weekend.ToNumber()
- if weekendArg.Type != ArgNumber {
- return nil, 0
- }
- var weekendMask []byte
- var workdaysPerWeek int
- if len(weekend.Value()) == 7 {
- // possible string values for the weekend argument
- for _, mask := range weekend.Value() {
- if mask != '0' && mask != '1' {
- return nil, 0
- }
- weekendMask = append(weekendMask, byte(mask)-48)
- }
- } else {
- weekendMask = genWeekendMask(int(weekendArg.Number))
- }
- for _, mask := range weekendMask {
- if mask == 0 {
- workdaysPerWeek++
- }
- }
- return weekendMask, workdaysPerWeek
- }
- // toExcelDateArg function converts a text representation of a time, into an
- // Excel date time number formula argument.
- func toExcelDateArg(arg formulaArg) formulaArg {
- num := arg.ToNumber()
- if num.Type != ArgNumber {
- dateString := strings.ToLower(arg.Value())
- if !isDateOnlyFmt(dateString) {
- if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
- return err
- }
- }
- y, m, d, _, err := strToDate(dateString)
- if err.Type == ArgError {
- return err
- }
- num.Number, _ = timeToExcelTime(time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.UTC), false)
- return newNumberFormulaArg(num.Number)
- }
- if arg.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return num
- }
- // prepareHolidays function converts array type formula arguments to into an
- // Excel date time number formula arguments list.
- func prepareHolidays(args formulaArg) []int {
- var holidays []int
- for _, arg := range args.ToList() {
- num := toExcelDateArg(arg)
- if num.Type != ArgNumber {
- continue
- }
- holidays = append(holidays, int(math.Ceil(num.Number)))
- }
- return holidays
- }
- // workdayIntl is an implementation of the formula function WORKDAY.INTL.
- func workdayIntl(endDate, sign int, holidays []int, weekendMask []byte, startDate float64) int {
- for i := 0; i < len(holidays); i++ {
- holiday := holidays[i]
- if sign > 0 {
- if holiday > endDate {
- break
- }
- } else {
- if holiday < endDate {
- break
- }
- }
- if sign > 0 {
- if holiday > int(math.Ceil(startDate)) {
- if isWorkday(weekendMask, float64(holiday)) {
- endDate += sign
- for !isWorkday(weekendMask, float64(endDate)) {
- endDate += sign
- }
- }
- }
- } else {
- if holiday < int(math.Ceil(startDate)) {
- if isWorkday(weekendMask, float64(holiday)) {
- endDate += sign
- for !isWorkday(weekendMask, float64(endDate)) {
- endDate += sign
- }
- }
- }
- }
- }
- return endDate
- }
- // NETWORKDAYS function calculates the number of work days between two supplied
- // dates (including the start and end date). The calculation includes all
- // weekdays (Mon - Fri), excluding a supplied list of holidays. The syntax of
- // the function is:
- //
- // NETWORKDAYS(start_date,end_date,[holidays])
- func (fn *formulaFuncs) NETWORKDAYS(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "NETWORKDAYS requires at least 2 arguments")
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "NETWORKDAYS requires at most 3 arguments")
- }
- args := list.New()
- args.PushBack(argsList.Front().Value.(formulaArg))
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- args.PushBack(newNumberFormulaArg(1))
- if argsList.Len() == 3 {
- args.PushBack(argsList.Back().Value.(formulaArg))
- }
- return fn.NETWORKDAYSdotINTL(args)
- }
- // NETWORKDAYSdotINTL function calculates the number of whole work days between
- // two supplied dates, excluding weekends and holidays. The function allows
- // the user to specify which days are counted as weekends and holidays. The
- // syntax of the function is:
- //
- // NETWORKDAYS.INTL(start_date,end_date,[weekend],[holidays])
- func (fn *formulaFuncs) NETWORKDAYSdotINTL(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "NETWORKDAYS.INTL requires at least 2 arguments")
- }
- if argsList.Len() > 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "NETWORKDAYS.INTL requires at most 4 arguments")
- }
- startDate := toExcelDateArg(argsList.Front().Value.(formulaArg))
- if startDate.Type != ArgNumber {
- return startDate
- }
- endDate := toExcelDateArg(argsList.Front().Next().Value.(formulaArg))
- if endDate.Type != ArgNumber {
- return endDate
- }
- weekend := newNumberFormulaArg(1)
- if argsList.Len() > 2 {
- weekend = argsList.Front().Next().Next().Value.(formulaArg)
- }
- var holidays []int
- if argsList.Len() == 4 {
- holidays = prepareHolidays(argsList.Back().Value.(formulaArg))
- sort.Ints(holidays)
- }
- weekendMask, workdaysPerWeek := prepareWorkday(weekend)
- if workdaysPerWeek == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- sign := 1
- if startDate.Number > endDate.Number {
- sign = -1
- temp := startDate.Number
- startDate.Number = endDate.Number
- endDate.Number = temp
- }
- offset := endDate.Number - startDate.Number
- count := int(math.Floor(offset/7) * float64(workdaysPerWeek))
- daysMod := int(offset) % 7
- for daysMod >= 0 {
- if isWorkday(weekendMask, endDate.Number-float64(daysMod)) {
- count++
- }
- daysMod--
- }
- for i := 0; i < len(holidays); i++ {
- holiday := float64(holidays[i])
- if isWorkday(weekendMask, holiday) && holiday >= startDate.Number && holiday <= endDate.Number {
- count--
- }
- }
- return newNumberFormulaArg(float64(sign * count))
- }
- // WORKDAY function returns a date that is a supplied number of working days
- // (excluding weekends and holidays) ahead of a given start date. The syntax
- // of the function is:
- //
- // WORKDAY(start_date,days,[holidays])
- func (fn *formulaFuncs) WORKDAY(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "WORKDAY requires at least 2 arguments")
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "WORKDAY requires at most 3 arguments")
- }
- args := list.New()
- args.PushBack(argsList.Front().Value.(formulaArg))
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- args.PushBack(newNumberFormulaArg(1))
- if argsList.Len() == 3 {
- args.PushBack(argsList.Back().Value.(formulaArg))
- }
- return fn.WORKDAYdotINTL(args)
- }
- // WORKDAYdotINTL function returns a date that is a supplied number of working
- // days (excluding weekends and holidays) ahead of a given start date. The
- // function allows the user to specify which days of the week are counted as
- // weekends. The syntax of the function is:
- //
- // WORKDAY.INTL(start_date,days,[weekend],[holidays])
- func (fn *formulaFuncs) WORKDAYdotINTL(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "WORKDAY.INTL requires at least 2 arguments")
- }
- if argsList.Len() > 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "WORKDAY.INTL requires at most 4 arguments")
- }
- startDate := toExcelDateArg(argsList.Front().Value.(formulaArg))
- if startDate.Type != ArgNumber {
- return startDate
- }
- days := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if days.Type != ArgNumber {
- return days
- }
- weekend := newNumberFormulaArg(1)
- if argsList.Len() > 2 {
- weekend = argsList.Front().Next().Next().Value.(formulaArg)
- }
- var holidays []int
- if argsList.Len() == 4 {
- holidays = prepareHolidays(argsList.Back().Value.(formulaArg))
- sort.Ints(holidays)
- }
- if days.Number == 0 {
- return newNumberFormulaArg(math.Ceil(startDate.Number))
- }
- weekendMask, workdaysPerWeek := prepareWorkday(weekend)
- if workdaysPerWeek == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- sign := 1
- if days.Number < 0 {
- sign = -1
- }
- offset := int(days.Number) / workdaysPerWeek
- daysMod := int(days.Number) % workdaysPerWeek
- endDate := int(math.Ceil(startDate.Number)) + offset*7
- if daysMod == 0 {
- for !isWorkday(weekendMask, float64(endDate)) {
- endDate -= sign
- }
- } else {
- for daysMod != 0 {
- endDate += sign
- if isWorkday(weekendMask, float64(endDate)) {
- if daysMod < 0 {
- daysMod++
- continue
- }
- daysMod--
- }
- }
- }
- return newNumberFormulaArg(float64(workdayIntl(endDate, sign, holidays, weekendMask, startDate.Number)))
- }
- // YEAR function returns an integer representing the year of a supplied date.
- // The syntax of the function is:
- //
- // YEAR(serial_number)
- func (fn *formulaFuncs) YEAR(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "YEAR requires exactly 1 argument")
- }
- arg := argsList.Front().Value.(formulaArg)
- num := arg.ToNumber()
- if num.Type != ArgNumber {
- dateString := strings.ToLower(arg.Value())
- if !isDateOnlyFmt(dateString) {
- if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
- return err
- }
- }
- year, _, _, _, err := strToDate(dateString)
- if err.Type == ArgError {
- return err
- }
- return newNumberFormulaArg(float64(year))
- }
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "YEAR only accepts positive argument")
- }
- return newNumberFormulaArg(float64(timeFromExcelTime(num.Number, false).Year()))
- }
- // yearFracBasisCond is an implementation of the yearFracBasis1.
- func yearFracBasisCond(sy, sm, sd, ey, em, ed int) bool {
- return (isLeapYear(sy) && (sm < 2 || (sm == 2 && sd <= 29))) || (isLeapYear(ey) && (em > 2 || (em == 2 && ed == 29)))
- }
- // yearFracBasis0 function returns the fraction of a year that between two
- // supplied dates in US (NASD) 30/360 type of day.
- func yearFracBasis0(startDate, endDate float64) (dayDiff, daysInYear float64) {
- startTime, endTime := timeFromExcelTime(startDate, false), timeFromExcelTime(endDate, false)
- sy, smM, sd := startTime.Date()
- ey, emM, ed := endTime.Date()
- sm, em := int(smM), int(emM)
- if sd == 31 {
- sd--
- }
- if sd == 30 && ed == 31 {
- ed--
- } else if leap := isLeapYear(sy); sm == 2 && ((leap && sd == 29) || (!leap && sd == 28)) {
- sd = 30
- if leap := isLeapYear(ey); em == 2 && ((leap && ed == 29) || (!leap && ed == 28)) {
- ed = 30
- }
- }
- dayDiff = float64((ey-sy)*360 + (em-sm)*30 + (ed - sd))
- daysInYear = 360
- return
- }
- // yearFracBasis1 function returns the fraction of a year that between two
- // supplied dates in actual type of day.
- func yearFracBasis1(startDate, endDate float64) (dayDiff, daysInYear float64) {
- startTime, endTime := timeFromExcelTime(startDate, false), timeFromExcelTime(endDate, false)
- sy, smM, sd := startTime.Date()
- ey, emM, ed := endTime.Date()
- sm, em := int(smM), int(emM)
- dayDiff = endDate - startDate
- isYearDifferent := sy != ey
- if isYearDifferent && (ey != sy+1 || sm < em || (sm == em && sd < ed)) {
- dayCount := 0
- for y := sy; y <= ey; y++ {
- dayCount += getYearDays(y, 1)
- }
- daysInYear = float64(dayCount) / float64(ey-sy+1)
- } else {
- if !isYearDifferent && isLeapYear(sy) {
- daysInYear = 366
- } else {
- if isYearDifferent && yearFracBasisCond(sy, sm, sd, ey, em, ed) {
- daysInYear = 366
- } else {
- daysInYear = 365
- }
- }
- }
- return
- }
- // yearFracBasis4 function returns the fraction of a year that between two
- // supplied dates in European 30/360 type of day.
- func yearFracBasis4(startDate, endDate float64) (dayDiff, daysInYear float64) {
- startTime, endTime := timeFromExcelTime(startDate, false), timeFromExcelTime(endDate, false)
- sy, smM, sd := startTime.Date()
- ey, emM, ed := endTime.Date()
- sm, em := int(smM), int(emM)
- if sd == 31 {
- sd--
- }
- if ed == 31 {
- ed--
- }
- dayDiff = float64((ey-sy)*360 + (em-sm)*30 + (ed - sd))
- daysInYear = 360
- return
- }
- // yearFrac is an implementation of the formula function YEARFRAC.
- func yearFrac(startDate, endDate float64, basis int) formulaArg {
- startTime, endTime := timeFromExcelTime(startDate, false), timeFromExcelTime(endDate, false)
- if startTime == endTime {
- return newNumberFormulaArg(0)
- }
- var dayDiff, daysInYear float64
- switch basis {
- case 0:
- dayDiff, daysInYear = yearFracBasis0(startDate, endDate)
- case 1:
- dayDiff, daysInYear = yearFracBasis1(startDate, endDate)
- case 2:
- dayDiff = endDate - startDate
- daysInYear = 360
- case 3:
- dayDiff = endDate - startDate
- daysInYear = 365
- case 4:
- dayDiff, daysInYear = yearFracBasis4(startDate, endDate)
- default:
- return newErrorFormulaArg(formulaErrorNUM, "invalid basis")
- }
- return newNumberFormulaArg(dayDiff / daysInYear)
- }
- // getYearDays return days of the year with specifying the type of day count
- // basis to be used.
- func getYearDays(year, basis int) int {
- switch basis {
- case 1:
- if isLeapYear(year) {
- return 366
- }
- return 365
- case 3:
- return 365
- default:
- return 360
- }
- }
- // YEARFRAC function returns the fraction of a year that is represented by the
- // number of whole days between two supplied dates. The syntax of the
- // function is:
- //
- // YEARFRAC(start_date,end_date,[basis])
- func (fn *formulaFuncs) YEARFRAC(argsList *list.List) formulaArg {
- if argsList.Len() != 2 && argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "YEARFRAC requires 3 or 4 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- start, end := args.List[0], args.List[1]
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 3 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return basis
- }
- }
- return yearFrac(start.Number, end.Number, int(basis.Number))
- }
- // NOW function returns the current date and time. The function receives no
- // arguments and therefore. The syntax of the function is:
- //
- // NOW()
- func (fn *formulaFuncs) NOW(argsList *list.List) formulaArg {
- if argsList.Len() != 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "NOW accepts no arguments")
- }
- now := time.Now()
- _, offset := now.Zone()
- return newNumberFormulaArg(25569.0 + float64(now.Unix()+int64(offset))/86400)
- }
- // SECOND function returns an integer representing the second component of a
- // supplied Excel time. The syntax of the function is:
- //
- // SECOND(serial_number)
- func (fn *formulaFuncs) SECOND(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "SECOND requires exactly 1 argument")
- }
- date := argsList.Front().Value.(formulaArg)
- num := date.ToNumber()
- if num.Type != ArgNumber {
- timeString := strings.ToLower(date.Value())
- if !isTimeOnlyFmt(timeString) {
- _, _, _, _, err := strToDate(timeString)
- if err.Type == ArgError {
- return err
- }
- }
- _, _, s, _, _, err := strToTime(timeString)
- if err.Type == ArgError {
- return err
- }
- return newNumberFormulaArg(float64(int(s) % 60))
- }
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "SECOND only accepts positive argument")
- }
- return newNumberFormulaArg(float64(timeFromExcelTime(num.Number, false).Second()))
- }
- // TIME function accepts three integer arguments representing hours, minutes
- // and seconds, and returns an Excel time. I.e. the function returns the
- // decimal value that represents the time in Excel. The syntax of the
- // function is:
- //
- // TIME(hour,minute,second)
- func (fn *formulaFuncs) TIME(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "TIME requires 3 number arguments")
- }
- h := argsList.Front().Value.(formulaArg).ToNumber()
- m := argsList.Front().Next().Value.(formulaArg).ToNumber()
- s := argsList.Back().Value.(formulaArg).ToNumber()
- if h.Type != ArgNumber || m.Type != ArgNumber || s.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, "TIME requires 3 number arguments")
- }
- t := (h.Number*3600 + m.Number*60 + s.Number) / 86400
- if t < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(t)
- }
- // TIMEVALUE function converts a text representation of a time, into an Excel
- // time. The syntax of the function is:
- //
- // TIMEVALUE(time_text)
- func (fn *formulaFuncs) TIMEVALUE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "TIMEVALUE requires exactly 1 argument")
- }
- date := argsList.Front().Value.(formulaArg)
- timeString := strings.ToLower(date.Value())
- if !isTimeOnlyFmt(timeString) {
- _, _, _, _, err := strToDate(timeString)
- if err.Type == ArgError {
- return err
- }
- }
- h, m, s, pm, _, err := strToTime(timeString)
- if err.Type == ArgError {
- return err
- }
- if pm {
- h += 12
- }
- args := list.New()
- args.PushBack(newNumberFormulaArg(float64(h)))
- args.PushBack(newNumberFormulaArg(float64(m)))
- args.PushBack(newNumberFormulaArg(s))
- return fn.TIME(args)
- }
- // TODAY function returns the current date. The function has no arguments and
- // therefore. The syntax of the function is:
- //
- // TODAY()
- func (fn *formulaFuncs) TODAY(argsList *list.List) formulaArg {
- if argsList.Len() != 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "TODAY accepts no arguments")
- }
- now := time.Now()
- _, offset := now.Zone()
- return newNumberFormulaArg(daysBetween(excelMinTime1900.Unix(), now.Unix()+int64(offset)) + 1)
- }
- // makeDate return date as a Unix time, the number of seconds elapsed since
- // January 1, 1970 UTC.
- func makeDate(y int, m time.Month, d int) int64 {
- if y == 1900 && int(m) <= 2 {
- d--
- }
- date := time.Date(y, m, d, 0, 0, 0, 0, time.UTC)
- return date.Unix()
- }
- // daysBetween return time interval of the given start timestamp and end
- // timestamp.
- func daysBetween(startDate, endDate int64) float64 {
- return float64(int(0.5 + float64((endDate-startDate)/86400)))
- }
- // WEEKDAY function returns an integer representing the day of the week for a
- // supplied date. The syntax of the function is:
- //
- // WEEKDAY(serial_number,[return_type])
- func (fn *formulaFuncs) WEEKDAY(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "WEEKDAY requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "WEEKDAY allows at most 2 arguments")
- }
- sn := argsList.Front().Value.(formulaArg)
- num := sn.ToNumber()
- weekday, returnType := 0, 1
- if num.Type != ArgNumber {
- dateString := strings.ToLower(sn.Value())
- if !isDateOnlyFmt(dateString) {
- if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
- return err
- }
- }
- y, m, d, _, err := strToDate(dateString)
- if err.Type == ArgError {
- return err
- }
- weekday = int(time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Now().Location()).Weekday())
- } else {
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- weekday = int(timeFromExcelTime(num.Number, false).Weekday())
- }
- if argsList.Len() == 2 {
- returnTypeArg := argsList.Back().Value.(formulaArg).ToNumber()
- if returnTypeArg.Type != ArgNumber {
- return returnTypeArg
- }
- returnType = int(returnTypeArg.Number)
- }
- if returnType == 2 {
- returnType = 11
- }
- weekday++
- if returnType == 1 {
- return newNumberFormulaArg(float64(weekday))
- }
- if returnType == 3 {
- return newNumberFormulaArg(float64((weekday + 6 - 1) % 7))
- }
- if returnType >= 11 && returnType <= 17 {
- return newNumberFormulaArg(float64((weekday+6-(returnType-10))%7 + 1))
- }
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- // weeknum is an implementation of the formula function WEEKNUM.
- func (fn *formulaFuncs) weeknum(snTime time.Time, returnType int) formulaArg {
- days := snTime.YearDay()
- weekMod, weekNum := days%7, math.Ceil(float64(days)/7)
- if weekMod == 0 {
- weekMod = 7
- }
- year := snTime.Year()
- firstWeekday := int(time.Date(year, time.January, 1, 0, 0, 0, 0, time.UTC).Weekday())
- var offset int
- switch returnType {
- case 1, 17:
- offset = 0
- case 2, 11, 21:
- offset = 1
- case 12, 13, 14, 15, 16:
- offset = returnType - 10
- default:
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- padding := offset + 7 - firstWeekday
- if padding > 7 {
- padding -= 7
- }
- if weekMod > padding {
- weekNum++
- }
- if returnType == 21 && (firstWeekday == 0 || firstWeekday > 4) {
- if weekNum--; weekNum < 1 {
- if weekNum = 52; int(time.Date(year-1, time.January, 1, 0, 0, 0, 0, time.UTC).Weekday()) < 4 {
- weekNum++
- }
- }
- }
- return newNumberFormulaArg(weekNum)
- }
- // WEEKNUM function returns an integer representing the week number (from 1 to
- // 53) of the year. The syntax of the function is:
- //
- // WEEKNUM(serial_number,[return_type])
- func (fn *formulaFuncs) WEEKNUM(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "WEEKNUM requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "WEEKNUM allows at most 2 arguments")
- }
- sn := argsList.Front().Value.(formulaArg)
- num, returnType := sn.ToNumber(), 1
- var snTime time.Time
- if num.Type != ArgNumber {
- dateString := strings.ToLower(sn.Value())
- if !isDateOnlyFmt(dateString) {
- if _, _, _, _, _, err := strToTime(dateString); err.Type == ArgError {
- return err
- }
- }
- y, m, d, _, err := strToDate(dateString)
- if err.Type == ArgError {
- return err
- }
- snTime = time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Now().Location())
- } else {
- if num.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- snTime = timeFromExcelTime(num.Number, false)
- }
- if argsList.Len() == 2 {
- returnTypeArg := argsList.Back().Value.(formulaArg).ToNumber()
- if returnTypeArg.Type != ArgNumber {
- return returnTypeArg
- }
- returnType = int(returnTypeArg.Number)
- }
- return fn.weeknum(snTime, returnType)
- }
- // Text Functions
- // CHAR function returns the character relating to a supplied character set
- // number (from 1 to 255). syntax of the function is:
- //
- // CHAR(number)
- func (fn *formulaFuncs) CHAR(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHAR requires 1 argument")
- }
- arg := argsList.Front().Value.(formulaArg).ToNumber()
- if arg.Type != ArgNumber {
- return arg
- }
- num := int(arg.Number)
- if num < 0 || num > MaxFieldLength {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return newStringFormulaArg(fmt.Sprintf("%c", num))
- }
- // CLEAN removes all non-printable characters from a supplied text string. The
- // syntax of the function is:
- //
- // CLEAN(text)
- func (fn *formulaFuncs) CLEAN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "CLEAN requires 1 argument")
- }
- b := bytes.Buffer{}
- for _, c := range argsList.Front().Value.(formulaArg).Value() {
- if c > 31 {
- b.WriteRune(c)
- }
- }
- return newStringFormulaArg(b.String())
- }
- // CODE function converts the first character of a supplied text string into
- // the associated numeric character set code used by your computer. The
- // syntax of the function is:
- //
- // CODE(text)
- func (fn *formulaFuncs) CODE(argsList *list.List) formulaArg {
- return fn.code("CODE", argsList)
- }
- // code is an implementation of the formula functions CODE and UNICODE.
- func (fn *formulaFuncs) code(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 1 argument", name))
- }
- text := argsList.Front().Value.(formulaArg).Value()
- if len(text) == 0 {
- if name == "CODE" {
- return newNumberFormulaArg(0)
- }
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return newNumberFormulaArg(float64(text[0]))
- }
- // CONCAT function joins together a series of supplied text strings into one
- // combined text string.
- //
- // CONCAT(text1,[text2],...)
- func (fn *formulaFuncs) CONCAT(argsList *list.List) formulaArg {
- return fn.concat("CONCAT", argsList)
- }
- // CONCATENATE function joins together a series of supplied text strings into
- // one combined text string.
- //
- // CONCATENATE(text1,[text2],...)
- func (fn *formulaFuncs) CONCATENATE(argsList *list.List) formulaArg {
- return fn.concat("CONCATENATE", argsList)
- }
- // concat is an implementation of the formula functions CONCAT and
- // CONCATENATE.
- func (fn *formulaFuncs) concat(name string, argsList *list.List) formulaArg {
- buf := bytes.Buffer{}
- for arg := argsList.Front(); arg != nil; arg = arg.Next() {
- token := arg.Value.(formulaArg)
- switch token.Type {
- case ArgString:
- buf.WriteString(token.String)
- case ArgNumber:
- if token.Boolean {
- if token.Number == 0 {
- buf.WriteString("FALSE")
- } else {
- buf.WriteString("TRUE")
- }
- } else {
- buf.WriteString(token.Value())
- }
- default:
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires arguments to be strings", name))
- }
- }
- return newStringFormulaArg(buf.String())
- }
- // EXACT function tests if two supplied text strings or values are exactly
- // equal and if so, returns TRUE; Otherwise, the function returns FALSE. The
- // function is case-sensitive. The syntax of the function is:
- //
- // EXACT(text1,text2)
- func (fn *formulaFuncs) EXACT(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "EXACT requires 2 arguments")
- }
- text1 := argsList.Front().Value.(formulaArg).Value()
- text2 := argsList.Back().Value.(formulaArg).Value()
- return newBoolFormulaArg(text1 == text2)
- }
- // FIXED function rounds a supplied number to a specified number of decimal
- // places and then converts this into text. The syntax of the function is:
- //
- // FIXED(number,[decimals],[no_commas])
- func (fn *formulaFuncs) FIXED(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "FIXED requires at least 1 argument")
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "FIXED allows at most 3 arguments")
- }
- numArg := argsList.Front().Value.(formulaArg).ToNumber()
- if numArg.Type != ArgNumber {
- return numArg
- }
- precision, decimals, noCommas := 0, 0, false
- s := strings.Split(argsList.Front().Value.(formulaArg).Value(), ".")
- if argsList.Len() == 1 && len(s) == 2 {
- precision = len(s[1])
- decimals = len(s[1])
- }
- if argsList.Len() >= 2 {
- decimalsArg := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if decimalsArg.Type != ArgNumber {
- return decimalsArg
- }
- decimals = int(decimalsArg.Number)
- }
- if argsList.Len() == 3 {
- noCommasArg := argsList.Back().Value.(formulaArg).ToBool()
- if noCommasArg.Type == ArgError {
- return noCommasArg
- }
- noCommas = noCommasArg.Boolean
- }
- n := math.Pow(10, float64(decimals))
- r := numArg.Number * n
- fixed := float64(int(r+math.Copysign(0.5, r))) / n
- if decimals > 0 {
- precision = decimals
- }
- if noCommas {
- return newStringFormulaArg(fmt.Sprintf(fmt.Sprintf("%%.%df", precision), fixed))
- }
- p := message.NewPrinter(language.English)
- return newStringFormulaArg(p.Sprintf(fmt.Sprintf("%%.%df", precision), fixed))
- }
- // FIND function returns the position of a specified character or sub-string
- // within a supplied text string. The function is case-sensitive. The syntax
- // of the function is:
- //
- // FIND(find_text,within_text,[start_num])
- func (fn *formulaFuncs) FIND(argsList *list.List) formulaArg {
- return fn.find("FIND", argsList)
- }
- // FINDB counts each double-byte character as 2 when you have enabled the
- // editing of a language that supports DBCS and then set it as the default
- // language. Otherwise, FINDB counts each character as 1. The syntax of the
- // function is:
- //
- // FINDB(find_text,within_text,[start_num])
- func (fn *formulaFuncs) FINDB(argsList *list.List) formulaArg {
- return fn.find("FINDB", argsList)
- }
- // find is an implementation of the formula functions FIND and FINDB.
- func (fn *formulaFuncs) find(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 2 arguments", name))
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s allows at most 3 arguments", name))
- }
- findText := argsList.Front().Value.(formulaArg).Value()
- withinText := argsList.Front().Next().Value.(formulaArg).Value()
- startNum, result := 1, 1
- if argsList.Len() == 3 {
- numArg := argsList.Back().Value.(formulaArg).ToNumber()
- if numArg.Type != ArgNumber {
- return numArg
- }
- if numArg.Number < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- startNum = int(numArg.Number)
- }
- if findText == "" {
- return newNumberFormulaArg(float64(startNum))
- }
- for idx := range withinText {
- if result < startNum {
- result++
- }
- if strings.Index(withinText[idx:], findText) == 0 {
- return newNumberFormulaArg(float64(result))
- }
- result++
- }
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- // LEFT function returns a specified number of characters from the start of a
- // supplied text string. The syntax of the function is:
- //
- // LEFT(text,[num_chars])
- func (fn *formulaFuncs) LEFT(argsList *list.List) formulaArg {
- return fn.leftRight("LEFT", argsList)
- }
- // LEFTB returns the first character or characters in a text string, based on
- // the number of bytes you specify. The syntax of the function is:
- //
- // LEFTB(text,[num_bytes])
- func (fn *formulaFuncs) LEFTB(argsList *list.List) formulaArg {
- return fn.leftRight("LEFTB", argsList)
- }
- // leftRight is an implementation of the formula functions LEFT, LEFTB, RIGHT,
- // RIGHTB.
- func (fn *formulaFuncs) leftRight(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 1 argument", name))
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s allows at most 2 arguments", name))
- }
- text, numChars := argsList.Front().Value.(formulaArg).Value(), 1
- if argsList.Len() == 2 {
- numArg := argsList.Back().Value.(formulaArg).ToNumber()
- if numArg.Type != ArgNumber {
- return numArg
- }
- if numArg.Number < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- numChars = int(numArg.Number)
- }
- if name == "LEFTB" || name == "RIGHTB" {
- if len(text) > numChars {
- if name == "LEFTB" {
- return newStringFormulaArg(text[:numChars])
- }
- // RIGHTB
- return newStringFormulaArg(text[len(text)-numChars:])
- }
- return newStringFormulaArg(text)
- }
- // LEFT/RIGHT
- if utf8.RuneCountInString(text) > numChars {
- if name == "LEFT" {
- return newStringFormulaArg(string([]rune(text)[:numChars]))
- }
- // RIGHT
- return newStringFormulaArg(string([]rune(text)[utf8.RuneCountInString(text)-numChars:]))
- }
- return newStringFormulaArg(text)
- }
- // LEN returns the length of a supplied text string. The syntax of the
- // function is:
- //
- // LEN(text)
- func (fn *formulaFuncs) LEN(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "LEN requires 1 string argument")
- }
- return newStringFormulaArg(strconv.Itoa(utf8.RuneCountInString(argsList.Front().Value.(formulaArg).String)))
- }
- // LENB returns the number of bytes used to represent the characters in a text
- // string. LENB counts 2 bytes per character only when a DBCS language is set
- // as the default language. Otherwise LENB behaves the same as LEN, counting
- // 1 byte per character. The syntax of the function is:
- //
- // LENB(text)
- func (fn *formulaFuncs) LENB(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "LENB requires 1 string argument")
- }
- bytes := 0
- for _, r := range argsList.Front().Value.(formulaArg).Value() {
- b := utf8.RuneLen(r)
- if b == 1 {
- bytes++
- } else if b > 1 {
- bytes += 2
- }
- }
- return newStringFormulaArg(strconv.Itoa(bytes))
- }
- // LOWER converts all characters in a supplied text string to lower case. The
- // syntax of the function is:
- //
- // LOWER(text)
- func (fn *formulaFuncs) LOWER(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOWER requires 1 argument")
- }
- return newStringFormulaArg(strings.ToLower(argsList.Front().Value.(formulaArg).String))
- }
- // MID function returns a specified number of characters from the middle of a
- // supplied text string. The syntax of the function is:
- //
- // MID(text,start_num,num_chars)
- func (fn *formulaFuncs) MID(argsList *list.List) formulaArg {
- return fn.mid("MID", argsList)
- }
- // MIDB returns a specific number of characters from a text string, starting
- // at the position you specify, based on the number of bytes you specify. The
- // syntax of the function is:
- //
- // MID(text,start_num,num_chars)
- func (fn *formulaFuncs) MIDB(argsList *list.List) formulaArg {
- return fn.mid("MIDB", argsList)
- }
- // mid is an implementation of the formula functions MID and MIDB.
- func (fn *formulaFuncs) mid(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 3 arguments", name))
- }
- text := argsList.Front().Value.(formulaArg).Value()
- startNumArg, numCharsArg := argsList.Front().Next().Value.(formulaArg).ToNumber(), argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if startNumArg.Type != ArgNumber {
- return startNumArg
- }
- if numCharsArg.Type != ArgNumber {
- return numCharsArg
- }
- startNum := int(startNumArg.Number)
- if startNum < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if name == "MIDB" {
- textLen := len(text)
- if startNum > textLen {
- return newStringFormulaArg("")
- }
- startNum--
- endNum := startNum + int(numCharsArg.Number)
- if endNum > textLen+1 {
- return newStringFormulaArg(text[startNum:])
- }
- return newStringFormulaArg(text[startNum:endNum])
- }
- // MID
- textLen := utf8.RuneCountInString(text)
- if startNum > textLen {
- return newStringFormulaArg("")
- }
- startNum--
- endNum := startNum + int(numCharsArg.Number)
- if endNum > textLen+1 {
- return newStringFormulaArg(string([]rune(text)[startNum:]))
- }
- return newStringFormulaArg(string([]rune(text)[startNum:endNum]))
- }
- // PROPER converts all characters in a supplied text string to proper case
- // (i.e. all letters that do not immediately follow another letter are set to
- // upper case and all other characters are lower case). The syntax of the
- // function is:
- //
- // PROPER(text)
- func (fn *formulaFuncs) PROPER(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "PROPER requires 1 argument")
- }
- buf := bytes.Buffer{}
- isLetter := false
- for _, char := range argsList.Front().Value.(formulaArg).String {
- if !isLetter && unicode.IsLetter(char) {
- buf.WriteRune(unicode.ToUpper(char))
- } else {
- buf.WriteRune(unicode.ToLower(char))
- }
- isLetter = unicode.IsLetter(char)
- }
- return newStringFormulaArg(buf.String())
- }
- // REPLACE function replaces all or part of a text string with another string.
- // The syntax of the function is:
- //
- // REPLACE(old_text,start_num,num_chars,new_text)
- func (fn *formulaFuncs) REPLACE(argsList *list.List) formulaArg {
- return fn.replace("REPLACE", argsList)
- }
- // REPLACEB replaces part of a text string, based on the number of bytes you
- // specify, with a different text string.
- //
- // REPLACEB(old_text,start_num,num_chars,new_text)
- func (fn *formulaFuncs) REPLACEB(argsList *list.List) formulaArg {
- return fn.replace("REPLACEB", argsList)
- }
- // replace is an implementation of the formula functions REPLACE and REPLACEB.
- // TODO: support DBCS include Japanese, Chinese (Simplified), Chinese
- // (Traditional), and Korean.
- func (fn *formulaFuncs) replace(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 4 arguments", name))
- }
- sourceText, targetText := argsList.Front().Value.(formulaArg).Value(), argsList.Back().Value.(formulaArg).Value()
- startNumArg, numCharsArg := argsList.Front().Next().Value.(formulaArg).ToNumber(), argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if startNumArg.Type != ArgNumber {
- return startNumArg
- }
- if numCharsArg.Type != ArgNumber {
- return numCharsArg
- }
- sourceTextLen, startIdx := len(sourceText), int(startNumArg.Number)
- if startIdx > sourceTextLen {
- startIdx = sourceTextLen + 1
- }
- endIdx := startIdx + int(numCharsArg.Number)
- if endIdx > sourceTextLen {
- endIdx = sourceTextLen + 1
- }
- if startIdx < 1 || endIdx < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- result := sourceText[:startIdx-1] + targetText + sourceText[endIdx-1:]
- return newStringFormulaArg(result)
- }
- // REPT function returns a supplied text string, repeated a specified number
- // of times. The syntax of the function is:
- //
- // REPT(text,number_times)
- func (fn *formulaFuncs) REPT(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "REPT requires 2 arguments")
- }
- text := argsList.Front().Value.(formulaArg)
- if text.Type != ArgString {
- return newErrorFormulaArg(formulaErrorVALUE, "REPT requires first argument to be a string")
- }
- times := argsList.Back().Value.(formulaArg).ToNumber()
- if times.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, "REPT requires second argument to be a number")
- }
- if times.Number < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "REPT requires second argument to be >= 0")
- }
- if times.Number == 0 {
- return newStringFormulaArg("")
- }
- buf := bytes.Buffer{}
- for i := 0; i < int(times.Number); i++ {
- buf.WriteString(text.String)
- }
- return newStringFormulaArg(buf.String())
- }
- // RIGHT function returns a specified number of characters from the end of a
- // supplied text string. The syntax of the function is:
- //
- // RIGHT(text,[num_chars])
- func (fn *formulaFuncs) RIGHT(argsList *list.List) formulaArg {
- return fn.leftRight("RIGHT", argsList)
- }
- // RIGHTB returns the last character or characters in a text string, based on
- // the number of bytes you specify. The syntax of the function is:
- //
- // RIGHTB(text,[num_bytes])
- func (fn *formulaFuncs) RIGHTB(argsList *list.List) formulaArg {
- return fn.leftRight("RIGHTB", argsList)
- }
- // SUBSTITUTE function replaces one or more instances of a given text string,
- // within an original text string. The syntax of the function is:
- //
- // SUBSTITUTE(text,old_text,new_text,[instance_num])
- func (fn *formulaFuncs) SUBSTITUTE(argsList *list.List) formulaArg {
- if argsList.Len() != 3 && argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "SUBSTITUTE requires 3 or 4 arguments")
- }
- text, sourceText := argsList.Front().Value.(formulaArg), argsList.Front().Next().Value.(formulaArg)
- targetText, instanceNum := argsList.Front().Next().Next().Value.(formulaArg), 0
- if argsList.Len() == 3 {
- return newStringFormulaArg(strings.ReplaceAll(text.Value(), sourceText.Value(), targetText.Value()))
- }
- instanceNumArg := argsList.Back().Value.(formulaArg).ToNumber()
- if instanceNumArg.Type != ArgNumber {
- return instanceNumArg
- }
- instanceNum = int(instanceNumArg.Number)
- if instanceNum < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "instance_num should be > 0")
- }
- str, sourceTextLen, count, chars, pos := text.Value(), len(sourceText.Value()), instanceNum, 0, -1
- for {
- count--
- index := strings.Index(str, sourceText.Value())
- if index == -1 {
- pos = -1
- break
- } else {
- pos = index + chars
- if count == 0 {
- break
- }
- idx := sourceTextLen + index
- chars += idx
- str = str[idx:]
- }
- }
- if pos == -1 {
- return newStringFormulaArg(text.Value())
- }
- pre, post := text.Value()[:pos], text.Value()[pos+sourceTextLen:]
- return newStringFormulaArg(pre + targetText.Value() + post)
- }
- // TEXTJOIN function joins together a series of supplied text strings into one
- // combined text string. The user can specify a delimiter to add between the
- // individual text items, if required. The syntax of the function is:
- //
- // TEXTJOIN([delimiter],[ignore_empty],text1,[text2],...)
- func (fn *formulaFuncs) TEXTJOIN(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "TEXTJOIN requires at least 3 arguments")
- }
- if argsList.Len() > 252 {
- return newErrorFormulaArg(formulaErrorVALUE, "TEXTJOIN accepts at most 252 arguments")
- }
- delimiter := argsList.Front().Value.(formulaArg)
- ignoreEmpty := argsList.Front().Next().Value.(formulaArg)
- if ignoreEmpty.Type != ArgNumber || !ignoreEmpty.Boolean {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args, ok := textJoin(argsList.Front().Next().Next(), []string{}, ignoreEmpty.Number != 0)
- if ok.Type != ArgNumber {
- return ok
- }
- result := strings.Join(args, delimiter.Value())
- if len(result) > TotalCellChars {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("TEXTJOIN function exceeds %d characters", TotalCellChars))
- }
- return newStringFormulaArg(result)
- }
- // textJoin is an implementation of the formula function TEXTJOIN.
- func textJoin(arg *list.Element, arr []string, ignoreEmpty bool) ([]string, formulaArg) {
- for arg.Next(); arg != nil; arg = arg.Next() {
- switch arg.Value.(formulaArg).Type {
- case ArgError:
- return arr, arg.Value.(formulaArg)
- case ArgString, ArgEmpty:
- val := arg.Value.(formulaArg).Value()
- if val != "" || !ignoreEmpty {
- arr = append(arr, val)
- }
- case ArgNumber:
- arr = append(arr, arg.Value.(formulaArg).Value())
- case ArgMatrix:
- for _, row := range arg.Value.(formulaArg).Matrix {
- argList := list.New().Init()
- for _, ele := range row {
- argList.PushBack(ele)
- }
- if argList.Len() > 0 {
- args, _ := textJoin(argList.Front(), []string{}, ignoreEmpty)
- arr = append(arr, args...)
- }
- }
- }
- }
- return arr, newBoolFormulaArg(true)
- }
- // TRIM removes extra spaces (i.e. all spaces except for single spaces between
- // words or characters) from a supplied text string. The syntax of the
- // function is:
- //
- // TRIM(text)
- func (fn *formulaFuncs) TRIM(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "TRIM requires 1 argument")
- }
- return newStringFormulaArg(strings.TrimSpace(argsList.Front().Value.(formulaArg).Value()))
- }
- // UNICHAR returns the Unicode character that is referenced by the given
- // numeric value. The syntax of the function is:
- //
- // UNICHAR(number)
- func (fn *formulaFuncs) UNICHAR(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "UNICHAR requires 1 argument")
- }
- numArg := argsList.Front().Value.(formulaArg).ToNumber()
- if numArg.Type != ArgNumber {
- return numArg
- }
- if numArg.Number <= 0 || numArg.Number > 55295 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return newStringFormulaArg(string(rune(numArg.Number)))
- }
- // UNICODE function returns the code point for the first character of a
- // supplied text string. The syntax of the function is:
- //
- // UNICODE(text)
- func (fn *formulaFuncs) UNICODE(argsList *list.List) formulaArg {
- return fn.code("UNICODE", argsList)
- }
- // UPPER converts all characters in a supplied text string to upper case. The
- // syntax of the function is:
- //
- // UPPER(text)
- func (fn *formulaFuncs) UPPER(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "UPPER requires 1 argument")
- }
- return newStringFormulaArg(strings.ToUpper(argsList.Front().Value.(formulaArg).String))
- }
- // VALUE function converts a text string into a numeric value. The syntax of
- // the function is:
- //
- // VALUE(text)
- func (fn *formulaFuncs) VALUE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "VALUE requires 1 argument")
- }
- text := strings.ReplaceAll(argsList.Front().Value.(formulaArg).Value(), ",", "")
- percent := 1.0
- if strings.HasSuffix(text, "%") {
- percent, text = 0.01, strings.TrimSuffix(text, "%")
- }
- decimal := big.Float{}
- if _, ok := decimal.SetString(text); ok {
- value, _ := decimal.Float64()
- return newNumberFormulaArg(value * percent)
- }
- dateValue, timeValue, errTime, errDate := 0.0, 0.0, false, false
- if !isDateOnlyFmt(text) {
- h, m, s, _, _, err := strToTime(text)
- errTime = err.Type == ArgError
- if !errTime {
- timeValue = (float64(h)*3600 + float64(m)*60 + s) / 86400
- }
- }
- y, m, d, _, err := strToDate(text)
- errDate = err.Type == ArgError
- if !errDate {
- dateValue = daysBetween(excelMinTime1900.Unix(), makeDate(y, time.Month(m), d)) + 1
- }
- if errTime && errDate {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return newNumberFormulaArg(dateValue + timeValue)
- }
- // Conditional Functions
- // IF function tests a supplied condition and returns one result if the
- // condition evaluates to TRUE, and another result if the condition evaluates
- // to FALSE. The syntax of the function is:
- //
- // IF(logical_test,value_if_true,value_if_false)
- func (fn *formulaFuncs) IF(argsList *list.List) formulaArg {
- if argsList.Len() == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "IF requires at least 1 argument")
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "IF accepts at most 3 arguments")
- }
- token := argsList.Front().Value.(formulaArg)
- var (
- cond bool
- err error
- result formulaArg
- )
- switch token.Type {
- case ArgString:
- if cond, err = strconv.ParseBool(token.String); err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
- }
- case ArgNumber:
- cond = token.Number == 1
- }
- if argsList.Len() == 1 {
- return newBoolFormulaArg(cond)
- }
- if cond {
- value := argsList.Front().Next().Value.(formulaArg)
- switch value.Type {
- case ArgNumber:
- result = value.ToNumber()
- default:
- result = newStringFormulaArg(value.String)
- }
- return result
- }
- if argsList.Len() == 3 {
- value := argsList.Back().Value.(formulaArg)
- switch value.Type {
- case ArgNumber:
- result = value.ToNumber()
- default:
- result = newStringFormulaArg(value.String)
- }
- }
- return result
- }
- // Lookup and Reference Functions
- // ADDRESS function takes a row and a column number and returns a cell
- // reference as a text string. The syntax of the function is:
- //
- // ADDRESS(row_num,column_num,[abs_num],[a1],[sheet_text])
- func (fn *formulaFuncs) ADDRESS(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "ADDRESS requires at least 2 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "ADDRESS requires at most 5 arguments")
- }
- rowNum := argsList.Front().Value.(formulaArg).ToNumber()
- if rowNum.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if rowNum.Number >= TotalRows {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- colNum := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if colNum.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- absNum := newNumberFormulaArg(1)
- if argsList.Len() >= 3 {
- absNum = argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if absNum.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- if absNum.Number < 1 || absNum.Number > 4 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- a1 := newBoolFormulaArg(true)
- if argsList.Len() >= 4 {
- a1 = argsList.Front().Next().Next().Next().Value.(formulaArg).ToBool()
- if a1.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- var sheetText string
- if argsList.Len() == 5 {
- sheetText = fmt.Sprintf("%s!", argsList.Back().Value.(formulaArg).Value())
- }
- formatter := addressFmtMaps[fmt.Sprintf("%d_%s", int(absNum.Number), a1.Value())]
- addr, err := formatter(int(colNum.Number), int(rowNum.Number))
- if err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return newStringFormulaArg(fmt.Sprintf("%s%s", sheetText, addr))
- }
- // CHOOSE function returns a value from an array, that corresponds to a
- // supplied index number (position). The syntax of the function is:
- //
- // CHOOSE(index_num,value1,[value2],...)
- func (fn *formulaFuncs) CHOOSE(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "CHOOSE requires 2 arguments")
- }
- idx, err := strconv.Atoi(argsList.Front().Value.(formulaArg).Value())
- if err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, "CHOOSE requires first argument of type number")
- }
- if argsList.Len() <= idx {
- return newErrorFormulaArg(formulaErrorVALUE, "index_num should be <= to the number of values")
- }
- arg := argsList.Front()
- for i := 0; i < idx; i++ {
- arg = arg.Next()
- }
- return arg.Value.(formulaArg)
- }
- // deepMatchRune finds whether the text deep matches/satisfies the pattern
- // string.
- func deepMatchRune(str, pattern []rune, simple bool) bool {
- for len(pattern) > 0 {
- switch pattern[0] {
- default:
- if len(str) == 0 || str[0] != pattern[0] {
- return false
- }
- case '?':
- if len(str) == 0 && !simple {
- return false
- }
- case '*':
- return deepMatchRune(str, pattern[1:], simple) ||
- (len(str) > 0 && deepMatchRune(str[1:], pattern, simple))
- }
- str = str[1:]
- pattern = pattern[1:]
- }
- return len(str) == 0 && len(pattern) == 0
- }
- // matchPattern finds whether the text matches or satisfies the pattern
- // string. The pattern supports '*' and '?' wildcards in the pattern string.
- func matchPattern(pattern, name string) (matched bool) {
- if pattern == "" {
- return name == pattern
- }
- if pattern == "*" {
- return true
- }
- rName, rPattern := make([]rune, 0, len(name)), make([]rune, 0, len(pattern))
- for _, r := range name {
- rName = append(rName, r)
- }
- for _, r := range pattern {
- rPattern = append(rPattern, r)
- }
- return deepMatchRune(rName, rPattern, false)
- }
- // compareFormulaArg compares the left-hand sides and the right-hand sides'
- // formula arguments by given conditions such as case-sensitive, if exact
- // match, and make compare result as formula criteria condition type.
- func compareFormulaArg(lhs, rhs, matchMode formulaArg, caseSensitive bool) byte {
- if lhs.Type != rhs.Type {
- return criteriaNe
- }
- switch lhs.Type {
- case ArgNumber:
- if lhs.Number == rhs.Number {
- return criteriaEq
- }
- if lhs.Number < rhs.Number {
- return criteriaL
- }
- return criteriaG
- case ArgString:
- ls, rs := lhs.String, rhs.String
- if !caseSensitive {
- ls, rs = strings.ToLower(ls), strings.ToLower(rs)
- }
- if matchMode.Number == matchModeWildcard {
- if matchPattern(rs, ls) {
- return criteriaEq
- }
- }
- return map[int]byte{1: criteriaG, -1: criteriaL, 0: criteriaEq}[strings.Compare(ls, rs)]
- case ArgEmpty:
- return criteriaEq
- case ArgList:
- return compareFormulaArgList(lhs, rhs, matchMode, caseSensitive)
- case ArgMatrix:
- return compareFormulaArgMatrix(lhs, rhs, matchMode, caseSensitive)
- default:
- return criteriaErr
- }
- }
- // compareFormulaArgList compares the left-hand sides and the right-hand sides
- // list type formula arguments.
- func compareFormulaArgList(lhs, rhs, matchMode formulaArg, caseSensitive bool) byte {
- if len(lhs.List) < len(rhs.List) {
- return criteriaL
- }
- if len(lhs.List) > len(rhs.List) {
- return criteriaG
- }
- for arg := range lhs.List {
- criteria := compareFormulaArg(lhs.List[arg], rhs.List[arg], matchMode, caseSensitive)
- if criteria != criteriaEq {
- return criteria
- }
- }
- return criteriaEq
- }
- // compareFormulaArgMatrix compares the left-hand sides and the right-hand sides'
- // matrix type formula arguments.
- func compareFormulaArgMatrix(lhs, rhs, matchMode formulaArg, caseSensitive bool) byte {
- if len(lhs.Matrix) < len(rhs.Matrix) {
- return criteriaL
- }
- if len(lhs.Matrix) > len(rhs.Matrix) {
- return criteriaG
- }
- for i := range lhs.Matrix {
- left := lhs.Matrix[i]
- right := lhs.Matrix[i]
- if len(left) < len(right) {
- return criteriaL
- }
- if len(left) > len(right) {
- return criteriaG
- }
- for arg := range left {
- criteria := compareFormulaArg(left[arg], right[arg], matchMode, caseSensitive)
- if criteria != criteriaEq {
- return criteria
- }
- }
- }
- return criteriaEq
- }
- // COLUMN function returns the first column number within a supplied reference
- // or the number of the current column. The syntax of the function is:
- //
- // COLUMN([reference])
- func (fn *formulaFuncs) COLUMN(argsList *list.List) formulaArg {
- if argsList.Len() > 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "COLUMN requires at most 1 argument")
- }
- if argsList.Len() == 1 {
- if argsList.Front().Value.(formulaArg).cellRanges != nil && argsList.Front().Value.(formulaArg).cellRanges.Len() > 0 {
- return newNumberFormulaArg(float64(argsList.Front().Value.(formulaArg).cellRanges.Front().Value.(cellRange).From.Col))
- }
- if argsList.Front().Value.(formulaArg).cellRefs != nil && argsList.Front().Value.(formulaArg).cellRefs.Len() > 0 {
- return newNumberFormulaArg(float64(argsList.Front().Value.(formulaArg).cellRefs.Front().Value.(cellRef).Col))
- }
- return newErrorFormulaArg(formulaErrorVALUE, "invalid reference")
- }
- col, _, _ := CellNameToCoordinates(fn.cell)
- return newNumberFormulaArg(float64(col))
- }
- // calcColumnsMinMax calculation min and max value for given formula arguments
- // sequence of the formula function COLUMNS.
- func calcColumnsMinMax(argsList *list.List) (min, max int) {
- if argsList.Front().Value.(formulaArg).cellRanges != nil && argsList.Front().Value.(formulaArg).cellRanges.Len() > 0 {
- crs := argsList.Front().Value.(formulaArg).cellRanges
- for cr := crs.Front(); cr != nil; cr = cr.Next() {
- if min == 0 {
- min = cr.Value.(cellRange).From.Col
- }
- if min > cr.Value.(cellRange).From.Col {
- min = cr.Value.(cellRange).From.Col
- }
- if min > cr.Value.(cellRange).To.Col {
- min = cr.Value.(cellRange).To.Col
- }
- if max < cr.Value.(cellRange).To.Col {
- max = cr.Value.(cellRange).To.Col
- }
- if max < cr.Value.(cellRange).From.Col {
- max = cr.Value.(cellRange).From.Col
- }
- }
- }
- if argsList.Front().Value.(formulaArg).cellRefs != nil && argsList.Front().Value.(formulaArg).cellRefs.Len() > 0 {
- cr := argsList.Front().Value.(formulaArg).cellRefs
- for refs := cr.Front(); refs != nil; refs = refs.Next() {
- if min == 0 {
- min = refs.Value.(cellRef).Col
- }
- if min > refs.Value.(cellRef).Col {
- min = refs.Value.(cellRef).Col
- }
- if max < refs.Value.(cellRef).Col {
- max = refs.Value.(cellRef).Col
- }
- }
- }
- return
- }
- // COLUMNS function receives an Excel range and returns the number of columns
- // that are contained within the range. The syntax of the function is:
- //
- // COLUMNS(array)
- func (fn *formulaFuncs) COLUMNS(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "COLUMNS requires 1 argument")
- }
- min, max := calcColumnsMinMax(argsList)
- if max == MaxColumns {
- return newNumberFormulaArg(float64(MaxColumns))
- }
- result := max - min + 1
- if max == min {
- if min == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "invalid reference")
- }
- return newNumberFormulaArg(float64(1))
- }
- return newNumberFormulaArg(float64(result))
- }
- // FORMULATEXT function returns a formula as a text string. The syntax of the
- // function is:
- //
- // FORMULATEXT(reference)
- func (fn *formulaFuncs) FORMULATEXT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "FORMULATEXT requires 1 argument")
- }
- refs := argsList.Front().Value.(formulaArg).cellRefs
- col, row := 0, 0
- if refs != nil && refs.Len() > 0 {
- col, row = refs.Front().Value.(cellRef).Col, refs.Front().Value.(cellRef).Row
- }
- ranges := argsList.Front().Value.(formulaArg).cellRanges
- if ranges != nil && ranges.Len() > 0 {
- col, row = ranges.Front().Value.(cellRange).From.Col, ranges.Front().Value.(cellRange).From.Row
- }
- cell, err := CoordinatesToCellName(col, row)
- if err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- formula, _ := fn.f.GetCellFormula(fn.sheet, cell)
- return newStringFormulaArg(formula)
- }
- // checkHVLookupArgs checking arguments, prepare extract mode, lookup value,
- // and data for the formula functions HLOOKUP and VLOOKUP.
- func checkHVLookupArgs(name string, argsList *list.List) (idx int, lookupValue, tableArray, matchMode, errArg formulaArg) {
- unit := map[string]string{
- "HLOOKUP": "row",
- "VLOOKUP": "col",
- }[name]
- if argsList.Len() < 3 {
- errArg = newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 3 arguments", name))
- return
- }
- if argsList.Len() > 4 {
- errArg = newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at most 4 arguments", name))
- return
- }
- lookupValue = argsList.Front().Value.(formulaArg)
- tableArray = argsList.Front().Next().Value.(formulaArg)
- if tableArray.Type != ArgMatrix {
- errArg = newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires second argument of table array", name))
- return
- }
- arg := argsList.Front().Next().Next().Value.(formulaArg)
- if arg.Type != ArgNumber || arg.Boolean {
- errArg = newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires numeric %s argument", name, unit))
- return
- }
- idx, matchMode = int(arg.Number)-1, newNumberFormulaArg(matchModeMaxLess)
- if argsList.Len() == 4 {
- rangeLookup := argsList.Back().Value.(formulaArg).ToBool()
- if rangeLookup.Type == ArgError {
- errArg = rangeLookup
- return
- }
- if rangeLookup.Number == 0 {
- matchMode = newNumberFormulaArg(matchModeWildcard)
- }
- }
- return
- }
- // HLOOKUP function 'looks up' a given value in the top row of a data array
- // (or table), and returns the corresponding value from another row of the
- // array. The syntax of the function is:
- //
- // HLOOKUP(lookup_value,table_array,row_index_num,[range_lookup])
- func (fn *formulaFuncs) HLOOKUP(argsList *list.List) formulaArg {
- rowIdx, lookupValue, tableArray, matchMode, errArg := checkHVLookupArgs("HLOOKUP", argsList)
- if errArg.Type == ArgError {
- return errArg
- }
- var matchIdx int
- var wasExact bool
- if matchMode.Number == matchModeWildcard || len(tableArray.Matrix) == TotalRows {
- matchIdx, wasExact = lookupLinearSearch(false, lookupValue, tableArray, matchMode, newNumberFormulaArg(searchModeLinear))
- } else {
- matchIdx, wasExact = lookupBinarySearch(false, lookupValue, tableArray, matchMode, newNumberFormulaArg(searchModeAscBinary))
- }
- if matchIdx == -1 {
- return newErrorFormulaArg(formulaErrorNA, "HLOOKUP no result found")
- }
- if rowIdx < 0 || rowIdx >= len(tableArray.Matrix) {
- return newErrorFormulaArg(formulaErrorNA, "HLOOKUP has invalid row index")
- }
- row := tableArray.Matrix[rowIdx]
- if wasExact || matchMode.Number == matchModeWildcard {
- return row[matchIdx]
- }
- return newErrorFormulaArg(formulaErrorNA, "HLOOKUP no result found")
- }
- // HYPERLINK function creates a hyperlink to a specified location. The syntax
- // of the function is:
- //
- // HYPERLINK(link_location,[friendly_name])
- func (fn *formulaFuncs) HYPERLINK(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "HYPERLINK requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "HYPERLINK allows at most 2 arguments")
- }
- return newStringFormulaArg(argsList.Back().Value.(formulaArg).Value())
- }
- // calcMatch returns the position of the value by given match type, criteria
- // and lookup array for the formula function MATCH.
- func calcMatch(matchType int, criteria *formulaCriteria, lookupArray []formulaArg) formulaArg {
- switch matchType {
- case 0:
- for i, arg := range lookupArray {
- if ok, _ := formulaCriteriaEval(arg.Value(), criteria); ok {
- return newNumberFormulaArg(float64(i + 1))
- }
- }
- case -1:
- for i, arg := range lookupArray {
- if ok, _ := formulaCriteriaEval(arg.Value(), criteria); ok {
- return newNumberFormulaArg(float64(i + 1))
- }
- if ok, _ := formulaCriteriaEval(arg.Value(), &formulaCriteria{
- Type: criteriaL, Condition: criteria.Condition,
- }); ok {
- if i == 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(float64(i))
- }
- }
- case 1:
- for i, arg := range lookupArray {
- if ok, _ := formulaCriteriaEval(arg.Value(), criteria); ok {
- return newNumberFormulaArg(float64(i + 1))
- }
- if ok, _ := formulaCriteriaEval(arg.Value(), &formulaCriteria{
- Type: criteriaG, Condition: criteria.Condition,
- }); ok {
- if i == 0 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- return newNumberFormulaArg(float64(i))
- }
- }
- }
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- // MATCH function looks up a value in an array, and returns the position of
- // the value within the array. The user can specify that the function should
- // only return a result if an exact match is found, or that the function
- // should return the position of the closest match (above or below), if an
- // exact match is not found. The syntax of the Match function is:
- //
- // MATCH(lookup_value,lookup_array,[match_type])
- func (fn *formulaFuncs) MATCH(argsList *list.List) formulaArg {
- if argsList.Len() != 2 && argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "MATCH requires 1 or 2 arguments")
- }
- var (
- matchType = 1
- lookupArray []formulaArg
- lookupArrayArg = argsList.Front().Next().Value.(formulaArg)
- lookupArrayErr = "MATCH arguments lookup_array should be one-dimensional array"
- )
- if argsList.Len() == 3 {
- matchTypeArg := argsList.Back().Value.(formulaArg).ToNumber()
- if matchTypeArg.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, "MATCH requires numeric match_type argument")
- }
- if matchTypeArg.Number == -1 || matchTypeArg.Number == 0 {
- matchType = int(matchTypeArg.Number)
- }
- }
- switch lookupArrayArg.Type {
- case ArgMatrix:
- if len(lookupArrayArg.Matrix[0]) != 1 {
- return newErrorFormulaArg(formulaErrorNA, lookupArrayErr)
- }
- lookupArray = lookupArrayArg.ToList()
- default:
- return newErrorFormulaArg(formulaErrorNA, lookupArrayErr)
- }
- return calcMatch(matchType, formulaCriteriaParser(argsList.Front().Value.(formulaArg).Value()), lookupArray)
- }
- // TRANSPOSE function 'transposes' an array of cells (i.e. the function copies
- // a horizontal range of cells into a vertical range and vice versa). The
- // syntax of the function is:
- //
- // TRANSPOSE(array)
- func (fn *formulaFuncs) TRANSPOSE(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "TRANSPOSE requires 1 argument")
- }
- args := argsList.Back().Value.(formulaArg).ToList()
- rmin, rmax := calcRowsMinMax(argsList)
- cmin, cmax := calcColumnsMinMax(argsList)
- cols, rows := cmax-cmin+1, rmax-rmin+1
- src := make([][]formulaArg, 0)
- for i := 0; i < len(args); i += cols {
- src = append(src, args[i:i+cols])
- }
- mtx := make([][]formulaArg, cols)
- for r, row := range src {
- colIdx := r % rows
- for c, cell := range row {
- rowIdx := c % cols
- if len(mtx[rowIdx]) == 0 {
- mtx[rowIdx] = make([]formulaArg, rows)
- }
- mtx[rowIdx][colIdx] = cell
- }
- }
- return newMatrixFormulaArg(mtx)
- }
- // lookupLinearSearch sequentially checks each look value of the lookup array until
- // a match is found or the whole list has been searched.
- func lookupLinearSearch(vertical bool, lookupValue, lookupArray, matchMode, searchMode formulaArg) (int, bool) {
- var tableArray []formulaArg
- if vertical {
- for _, row := range lookupArray.Matrix {
- tableArray = append(tableArray, row[0])
- }
- } else {
- tableArray = lookupArray.Matrix[0]
- }
- matchIdx, wasExact := -1, false
- start:
- for i, cell := range tableArray {
- lhs := cell
- if lookupValue.Type == ArgNumber {
- if lhs = cell.ToNumber(); lhs.Type == ArgError {
- lhs = cell
- }
- } else if lookupValue.Type == ArgMatrix {
- lhs = lookupArray
- } else if lookupArray.Type == ArgString {
- lhs = newStringFormulaArg(cell.Value())
- }
- if compareFormulaArg(lhs, lookupValue, matchMode, false) == criteriaEq {
- matchIdx = i
- wasExact = true
- if searchMode.Number == searchModeLinear {
- break start
- }
- }
- if matchMode.Number == matchModeMinGreater || matchMode.Number == matchModeMaxLess {
- matchIdx = int(calcMatch(int(matchMode.Number), formulaCriteriaParser(lookupValue.Value()), tableArray).Number)
- continue
- }
- }
- return matchIdx, wasExact
- }
- // VLOOKUP function 'looks up' a given value in the left-hand column of a
- // data array (or table), and returns the corresponding value from another
- // column of the array. The syntax of the function is:
- //
- // VLOOKUP(lookup_value,table_array,col_index_num,[range_lookup])
- func (fn *formulaFuncs) VLOOKUP(argsList *list.List) formulaArg {
- colIdx, lookupValue, tableArray, matchMode, errArg := checkHVLookupArgs("VLOOKUP", argsList)
- if errArg.Type == ArgError {
- return errArg
- }
- var matchIdx int
- var wasExact bool
- if matchMode.Number == matchModeWildcard || len(tableArray.Matrix) == TotalRows {
- matchIdx, wasExact = lookupLinearSearch(true, lookupValue, tableArray, matchMode, newNumberFormulaArg(searchModeLinear))
- } else {
- matchIdx, wasExact = lookupBinarySearch(true, lookupValue, tableArray, matchMode, newNumberFormulaArg(searchModeAscBinary))
- }
- if matchIdx == -1 {
- return newErrorFormulaArg(formulaErrorNA, "VLOOKUP no result found")
- }
- mtx := tableArray.Matrix[matchIdx]
- if colIdx < 0 || colIdx >= len(mtx) {
- return newErrorFormulaArg(formulaErrorNA, "VLOOKUP has invalid column index")
- }
- if wasExact || matchMode.Number == matchModeWildcard {
- return mtx[colIdx]
- }
- return newErrorFormulaArg(formulaErrorNA, "VLOOKUP no result found")
- }
- // lookupBinarySearch finds the position of a target value when range lookup
- // is TRUE, if the data of table array can't guarantee be sorted, it will
- // return wrong result.
- func lookupBinarySearch(vertical bool, lookupValue, lookupArray, matchMode, searchMode formulaArg) (matchIdx int, wasExact bool) {
- var tableArray []formulaArg
- if vertical {
- for _, row := range lookupArray.Matrix {
- tableArray = append(tableArray, row[0])
- }
- } else {
- tableArray = lookupArray.Matrix[0]
- }
- low, high, lastMatchIdx := 0, len(tableArray)-1, -1
- count := high
- for low <= high {
- mid := low + (high-low)/2
- cell := tableArray[mid]
- lhs := cell
- if lookupValue.Type == ArgNumber {
- if lhs = cell.ToNumber(); lhs.Type == ArgError {
- lhs = cell
- }
- } else if lookupValue.Type == ArgMatrix && vertical {
- lhs = lookupArray
- } else if lookupValue.Type == ArgString {
- lhs = newStringFormulaArg(cell.Value())
- }
- result := compareFormulaArg(lhs, lookupValue, matchMode, false)
- if result == criteriaEq {
- matchIdx, wasExact = mid, true
- if searchMode.Number == searchModeDescBinary {
- matchIdx = count - matchIdx
- }
- return
- } else if result == criteriaG {
- high = mid - 1
- } else if result == criteriaL {
- matchIdx = mid
- if cell.Type != ArgEmpty {
- lastMatchIdx = matchIdx
- }
- low = mid + 1
- } else {
- return -1, false
- }
- }
- matchIdx, wasExact = lastMatchIdx, true
- return
- }
- // checkLookupArgs checking arguments, prepare lookup value, and data for the
- // formula function LOOKUP.
- func checkLookupArgs(argsList *list.List) (arrayForm bool, lookupValue, lookupVector, errArg formulaArg) {
- if argsList.Len() < 2 {
- errArg = newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires at least 2 arguments")
- return
- }
- if argsList.Len() > 3 {
- errArg = newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires at most 3 arguments")
- return
- }
- lookupValue = newStringFormulaArg(argsList.Front().Value.(formulaArg).Value())
- lookupVector = argsList.Front().Next().Value.(formulaArg)
- if lookupVector.Type != ArgMatrix && lookupVector.Type != ArgList {
- errArg = newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires second argument of table array")
- return
- }
- arrayForm = lookupVector.Type == ArgMatrix
- if arrayForm && len(lookupVector.Matrix) == 0 {
- errArg = newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires not empty range as second argument")
- }
- return
- }
- // iterateLookupArgs iterate arguments to extract columns and calculate match
- // index for the formula function LOOKUP.
- func iterateLookupArgs(lookupValue, lookupVector formulaArg) ([]formulaArg, int, bool) {
- cols, matchIdx, ok := lookupCol(lookupVector, 0), -1, false
- for idx, col := range cols {
- lhs := lookupValue
- switch col.Type {
- case ArgNumber:
- lhs = lhs.ToNumber()
- if !col.Boolean {
- if lhs.Type == ArgError {
- lhs = lookupValue
- }
- }
- }
- compare := compareFormulaArg(lhs, col, newNumberFormulaArg(matchModeMaxLess), false)
- // Find exact match
- if compare == criteriaEq {
- matchIdx = idx
- break
- }
- // Find the nearest match if lookup value is more than or equal to the first value in lookup vector
- if idx == 0 {
- ok = compare == criteriaG
- } else if ok && compare == criteriaL && matchIdx == -1 {
- matchIdx = idx - 1
- }
- }
- return cols, matchIdx, ok
- }
- // index is an implementation of the formula function INDEX.
- func (fn *formulaFuncs) index(array formulaArg, rowIdx, colIdx int) formulaArg {
- var cells []formulaArg
- if array.Type == ArgMatrix {
- cellMatrix := array.Matrix
- if rowIdx < -1 || rowIdx >= len(cellMatrix) {
- return newErrorFormulaArg(formulaErrorREF, "INDEX row_num out of range")
- }
- if rowIdx == -1 {
- if colIdx >= len(cellMatrix[0]) {
- return newErrorFormulaArg(formulaErrorREF, "INDEX col_num out of range")
- }
- var column [][]formulaArg
- for _, cells = range cellMatrix {
- column = append(column, []formulaArg{cells[colIdx]})
- }
- return newMatrixFormulaArg(column)
- }
- cells = cellMatrix[rowIdx]
- }
- if colIdx < -1 || colIdx >= len(cells) {
- return newErrorFormulaArg(formulaErrorREF, "INDEX col_num out of range")
- }
- return newListFormulaArg(cells)
- }
- // validateMatchMode check the number of match mode if be equal to 0, 1, -1 or
- // 2.
- func validateMatchMode(mode float64) bool {
- return mode == matchModeExact || mode == matchModeMinGreater || mode == matchModeMaxLess || mode == matchModeWildcard
- }
- // validateSearchMode check the number of search mode if be equal to 1, -1, 2
- // or -2.
- func validateSearchMode(mode float64) bool {
- return mode == searchModeLinear || mode == searchModeReverseLinear || mode == searchModeAscBinary || mode == searchModeDescBinary
- }
- // prepareXlookupArgs checking and prepare arguments for the formula function
- // XLOOKUP.
- func (fn *formulaFuncs) prepareXlookupArgs(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "XLOOKUP requires at least 3 arguments")
- }
- if argsList.Len() > 6 {
- return newErrorFormulaArg(formulaErrorVALUE, "XLOOKUP allows at most 6 arguments")
- }
- lookupValue := argsList.Front().Value.(formulaArg)
- lookupArray := argsList.Front().Next().Value.(formulaArg)
- returnArray := argsList.Front().Next().Next().Value.(formulaArg)
- ifNotFond := newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- matchMode, searchMode := newNumberFormulaArg(matchModeExact), newNumberFormulaArg(searchModeLinear)
- if argsList.Len() > 3 {
- ifNotFond = argsList.Front().Next().Next().Next().Value.(formulaArg)
- }
- if argsList.Len() > 4 {
- if matchMode = argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber(); matchMode.Type != ArgNumber {
- return matchMode
- }
- }
- if argsList.Len() > 5 {
- if searchMode = argsList.Back().Value.(formulaArg).ToNumber(); searchMode.Type != ArgNumber {
- return searchMode
- }
- }
- if lookupArray.Type != ArgMatrix || returnArray.Type != ArgMatrix {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if !validateMatchMode(matchMode.Number) || !validateSearchMode(searchMode.Number) {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return newListFormulaArg([]formulaArg{lookupValue, lookupArray, returnArray, ifNotFond, matchMode, searchMode})
- }
- // xlookup is an implementation of the formula function XLOOKUP.
- func (fn *formulaFuncs) xlookup(lookupRows, lookupCols, returnArrayRows, returnArrayCols, matchIdx int,
- condition1, condition2, condition3, condition4 bool, returnArray formulaArg,
- ) formulaArg {
- var result [][]formulaArg
- for rowIdx, row := range returnArray.Matrix {
- for colIdx, cell := range row {
- if condition1 {
- if condition2 {
- result = append(result, []formulaArg{cell})
- continue
- }
- if returnArrayRows > 1 && returnArrayCols > 1 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- if condition3 {
- if returnArrayCols != lookupCols {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if colIdx == matchIdx {
- result = append(result, []formulaArg{cell})
- continue
- }
- }
- if condition4 {
- if returnArrayRows != lookupRows {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if rowIdx == matchIdx {
- if len(result) == 0 {
- result = append(result, []formulaArg{cell})
- continue
- }
- result[0] = append(result[0], cell)
- }
- }
- }
- }
- array := newMatrixFormulaArg(result)
- cells := array.ToList()
- if len(cells) == 1 {
- return cells[0]
- }
- return array
- }
- // XLOOKUP function searches a range or an array, and then returns the item
- // corresponding to the first match it finds. If no match exists, then
- // XLOOKUP can return the closest (approximate) match. The syntax of the
- // function is:
- //
- // XLOOKUP(lookup_value,lookup_array,return_array,[if_not_found],[match_mode],[search_mode])
- func (fn *formulaFuncs) XLOOKUP(argsList *list.List) formulaArg {
- args := fn.prepareXlookupArgs(argsList)
- if args.Type != ArgList {
- return args
- }
- lookupValue, lookupArray, returnArray, ifNotFond, matchMode, searchMode := args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5]
- lookupRows, lookupCols := len(lookupArray.Matrix), 0
- if lookupRows > 0 {
- lookupCols = len(lookupArray.Matrix[0])
- }
- if lookupRows != 1 && lookupCols != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- verticalLookup := lookupRows >= lookupCols
- var matchIdx int
- switch searchMode.Number {
- case searchModeLinear, searchModeReverseLinear:
- matchIdx, _ = lookupLinearSearch(verticalLookup, lookupValue, lookupArray, matchMode, searchMode)
- default:
- matchIdx, _ = lookupBinarySearch(verticalLookup, lookupValue, lookupArray, matchMode, searchMode)
- }
- if matchIdx == -1 {
- return ifNotFond
- }
- returnArrayRows, returnArrayCols := len(returnArray.Matrix), len(returnArray.Matrix[0])
- condition1 := lookupRows == 1 && lookupCols == 1
- condition2 := returnArrayRows == 1 || returnArrayCols == 1
- condition3 := lookupRows == 1 && lookupCols > 1
- condition4 := lookupRows > 1 && lookupCols == 1
- return fn.xlookup(lookupRows, lookupCols, returnArrayRows, returnArrayCols, matchIdx, condition1, condition2, condition3, condition4, returnArray)
- }
- // INDEX function returns a reference to a cell that lies in a specified row
- // and column of a range of cells. The syntax of the function is:
- //
- // INDEX(array,row_num,[col_num])
- func (fn *formulaFuncs) INDEX(argsList *list.List) formulaArg {
- if argsList.Len() < 2 || argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "INDEX requires 2 or 3 arguments")
- }
- array := argsList.Front().Value.(formulaArg)
- if array.Type != ArgMatrix && array.Type != ArgList {
- array = newMatrixFormulaArg([][]formulaArg{{array}})
- }
- rowArg := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if rowArg.Type != ArgNumber {
- return rowArg
- }
- rowIdx, colIdx := int(rowArg.Number)-1, -1
- if argsList.Len() == 3 {
- colArg := argsList.Back().Value.(formulaArg).ToNumber()
- if colArg.Type != ArgNumber {
- return colArg
- }
- colIdx = int(colArg.Number) - 1
- }
- if rowIdx == -1 && colIdx == -1 {
- if len(array.ToList()) != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return array.ToList()[0]
- }
- cells := fn.index(array, rowIdx, colIdx)
- if cells.Type != ArgList {
- return cells
- }
- if colIdx == -1 {
- return newMatrixFormulaArg([][]formulaArg{cells.List})
- }
- return cells.List[colIdx]
- }
- // INDIRECT function converts a text string into a cell reference. The syntax
- // of the Indirect function is:
- //
- // INDIRECT(ref_text,[a1])
- func (fn *formulaFuncs) INDIRECT(argsList *list.List) formulaArg {
- if argsList.Len() != 1 && argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "INDIRECT requires 1 or 2 arguments")
- }
- refText := argsList.Front().Value.(formulaArg).Value()
- a1 := newBoolFormulaArg(true)
- if argsList.Len() == 2 {
- if a1 = argsList.Back().Value.(formulaArg).ToBool(); a1.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- R1C1ToA1 := func(ref string) (cell string, err error) {
- parts := strings.Split(strings.TrimLeft(ref, "R"), "C")
- if len(parts) != 2 {
- return
- }
- row, err := strconv.Atoi(parts[0])
- if err != nil {
- return
- }
- col, err := strconv.Atoi(parts[1])
- if err != nil {
- return
- }
- cell, err = CoordinatesToCellName(col, row)
- return
- }
- refs := strings.Split(refText, ":")
- fromRef, toRef := refs[0], ""
- if len(refs) == 2 {
- toRef = refs[1]
- }
- if a1.Number == 0 {
- from, err := R1C1ToA1(refs[0])
- if err != nil {
- return newErrorFormulaArg(formulaErrorREF, formulaErrorREF)
- }
- fromRef = from
- if len(refs) == 2 {
- to, err := R1C1ToA1(refs[1])
- if err != nil {
- return newErrorFormulaArg(formulaErrorREF, formulaErrorREF)
- }
- toRef = to
- }
- }
- if len(refs) == 1 {
- value, err := fn.f.GetCellValue(fn.sheet, fromRef)
- if err != nil {
- return newErrorFormulaArg(formulaErrorREF, formulaErrorREF)
- }
- return newStringFormulaArg(value)
- }
- arg, _ := fn.f.parseReference(fn.ctx, fn.sheet, fromRef+":"+toRef)
- return arg
- }
- // LOOKUP function performs an approximate match lookup in a one-column or
- // one-row range, and returns the corresponding value from another one-column
- // or one-row range. The syntax of the function is:
- //
- // LOOKUP(lookup_value,lookup_vector,[result_vector])
- func (fn *formulaFuncs) LOOKUP(argsList *list.List) formulaArg {
- arrayForm, lookupValue, lookupVector, errArg := checkLookupArgs(argsList)
- if errArg.Type == ArgError {
- return errArg
- }
- cols, matchIdx, ok := iterateLookupArgs(lookupValue, lookupVector)
- if ok && matchIdx == -1 {
- matchIdx = len(cols) - 1
- }
- var column []formulaArg
- if argsList.Len() == 3 {
- column = lookupCol(argsList.Back().Value.(formulaArg), 0)
- } else if arrayForm && len(lookupVector.Matrix[0]) > 1 {
- column = lookupCol(lookupVector, 1)
- } else {
- column = cols
- }
- if matchIdx < 0 || matchIdx >= len(column) {
- return newErrorFormulaArg(formulaErrorNA, "LOOKUP no result found")
- }
- return column[matchIdx]
- }
- // lookupCol extract columns for LOOKUP.
- func lookupCol(arr formulaArg, idx int) []formulaArg {
- col := arr.List
- if arr.Type == ArgMatrix {
- col = nil
- for _, r := range arr.Matrix {
- if len(r) > 0 {
- col = append(col, r[idx])
- continue
- }
- col = append(col, newEmptyFormulaArg())
- }
- }
- return col
- }
- // ROW function returns the first row number within a supplied reference or
- // the number of the current row. The syntax of the function is:
- //
- // ROW([reference])
- func (fn *formulaFuncs) ROW(argsList *list.List) formulaArg {
- if argsList.Len() > 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ROW requires at most 1 argument")
- }
- if argsList.Len() == 1 {
- if argsList.Front().Value.(formulaArg).cellRanges != nil && argsList.Front().Value.(formulaArg).cellRanges.Len() > 0 {
- return newNumberFormulaArg(float64(argsList.Front().Value.(formulaArg).cellRanges.Front().Value.(cellRange).From.Row))
- }
- if argsList.Front().Value.(formulaArg).cellRefs != nil && argsList.Front().Value.(formulaArg).cellRefs.Len() > 0 {
- return newNumberFormulaArg(float64(argsList.Front().Value.(formulaArg).cellRefs.Front().Value.(cellRef).Row))
- }
- return newErrorFormulaArg(formulaErrorVALUE, "invalid reference")
- }
- _, row, _ := CellNameToCoordinates(fn.cell)
- return newNumberFormulaArg(float64(row))
- }
- // calcRowsMinMax calculation min and max value for given formula arguments
- // sequence of the formula function ROWS.
- func calcRowsMinMax(argsList *list.List) (min, max int) {
- if argsList.Front().Value.(formulaArg).cellRanges != nil && argsList.Front().Value.(formulaArg).cellRanges.Len() > 0 {
- crs := argsList.Front().Value.(formulaArg).cellRanges
- for cr := crs.Front(); cr != nil; cr = cr.Next() {
- if min == 0 {
- min = cr.Value.(cellRange).From.Row
- }
- if min > cr.Value.(cellRange).From.Row {
- min = cr.Value.(cellRange).From.Row
- }
- if min > cr.Value.(cellRange).To.Row {
- min = cr.Value.(cellRange).To.Row
- }
- if max < cr.Value.(cellRange).To.Row {
- max = cr.Value.(cellRange).To.Row
- }
- if max < cr.Value.(cellRange).From.Row {
- max = cr.Value.(cellRange).From.Row
- }
- }
- }
- if argsList.Front().Value.(formulaArg).cellRefs != nil && argsList.Front().Value.(formulaArg).cellRefs.Len() > 0 {
- cr := argsList.Front().Value.(formulaArg).cellRefs
- for refs := cr.Front(); refs != nil; refs = refs.Next() {
- if min == 0 {
- min = refs.Value.(cellRef).Row
- }
- if min > refs.Value.(cellRef).Row {
- min = refs.Value.(cellRef).Row
- }
- if max < refs.Value.(cellRef).Row {
- max = refs.Value.(cellRef).Row
- }
- }
- }
- return
- }
- // ROWS function takes an Excel range and returns the number of rows that are
- // contained within the range. The syntax of the function is:
- //
- // ROWS(array)
- func (fn *formulaFuncs) ROWS(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ROWS requires 1 argument")
- }
- min, max := calcRowsMinMax(argsList)
- if max == TotalRows {
- return newStringFormulaArg(strconv.Itoa(TotalRows))
- }
- result := max - min + 1
- if max == min {
- if min == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "invalid reference")
- }
- return newNumberFormulaArg(float64(1))
- }
- return newStringFormulaArg(strconv.Itoa(result))
- }
- // Web Functions
- // ENCODEURL function returns a URL-encoded string, replacing certain
- // non-alphanumeric characters with the percentage symbol (%) and a
- // hexadecimal number. The syntax of the function is:
- //
- // ENCODEURL(url)
- func (fn *formulaFuncs) ENCODEURL(argsList *list.List) formulaArg {
- if argsList.Len() != 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "ENCODEURL requires 1 argument")
- }
- token := argsList.Front().Value.(formulaArg).Value()
- return newStringFormulaArg(strings.ReplaceAll(url.QueryEscape(token), "+", "%20"))
- }
- // Financial Functions
- // validateFrequency check the number of coupon payments per year if be equal to 1, 2 or 4.
- func validateFrequency(freq float64) bool {
- return freq == 1 || freq == 2 || freq == 4
- }
- // ACCRINT function returns the accrued interest in a security that pays
- // periodic interest. The syntax of the function is:
- //
- // ACCRINT(issue,first_interest,settlement,rate,par,frequency,[basis],[calc_method])
- func (fn *formulaFuncs) ACCRINT(argsList *list.List) formulaArg {
- if argsList.Len() < 6 {
- return newErrorFormulaArg(formulaErrorVALUE, "ACCRINT requires at least 6 arguments")
- }
- if argsList.Len() > 8 {
- return newErrorFormulaArg(formulaErrorVALUE, "ACCRINT allows at most 8 arguments")
- }
- args := fn.prepareDataValueArgs(3, argsList)
- if args.Type != ArgList {
- return args
- }
- issue, settlement := args.List[0], args.List[2]
- rate := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- par := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- frequency := argsList.Front().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber || par.Type != ArgNumber || frequency.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if !validateFrequency(frequency.Number) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() >= 7 {
- if basis = argsList.Front().Next().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- if argsList.Len() == 8 {
- if cm := argsList.Back().Value.(formulaArg).ToBool(); cm.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- frac1 := yearFrac(issue.Number, settlement.Number, int(basis.Number))
- if frac1.Type != ArgNumber {
- return frac1
- }
- return newNumberFormulaArg(par.Number * rate.Number * frac1.Number)
- }
- // ACCRINTM function returns the accrued interest in a security that pays
- // interest at maturity. The syntax of the function is:
- //
- // ACCRINTM(issue,settlement,rate,[par],[basis])
- func (fn *formulaFuncs) ACCRINTM(argsList *list.List) formulaArg {
- if argsList.Len() != 4 && argsList.Len() != 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "ACCRINTM requires 4 or 5 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- issue, settlement := args.List[0], args.List[1]
- if settlement.Number < issue.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- rate := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- par := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber || par.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if par.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 5 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- frac := yearFrac(issue.Number, settlement.Number, int(basis.Number))
- if frac.Type != ArgNumber {
- return frac
- }
- return newNumberFormulaArg(frac.Number * rate.Number * par.Number)
- }
- // prepareAmorArgs checking and prepare arguments for the formula functions
- // AMORDEGRC and AMORLINC.
- func (fn *formulaFuncs) prepareAmorArgs(name string, argsList *list.List) formulaArg {
- cost := argsList.Front().Value.(formulaArg).ToNumber()
- if cost.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires cost to be number argument", name))
- }
- if cost.Number < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires cost >= 0", name))
- }
- args := list.New().Init()
- args.PushBack(argsList.Front().Next().Value.(formulaArg))
- datePurchased := fn.DATEVALUE(args)
- if datePurchased.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args.Init()
- args.PushBack(argsList.Front().Next().Next().Value.(formulaArg))
- firstPeriod := fn.DATEVALUE(args)
- if firstPeriod.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if firstPeriod.Number < datePurchased.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- salvage := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if salvage.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if salvage.Number < 0 || salvage.Number > cost.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- period := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if period.Type != ArgNumber || period.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- rate := argsList.Front().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber || rate.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 7 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- return newListFormulaArg([]formulaArg{cost, datePurchased, firstPeriod, salvage, period, rate, basis})
- }
- // AMORDEGRC function is provided for users of the French accounting system.
- // The function calculates the prorated linear depreciation of an asset for a
- // specified accounting period. The syntax of the function is:
- //
- // AMORDEGRC(cost,date_purchased,first_period,salvage,period,rate,[basis])
- func (fn *formulaFuncs) AMORDEGRC(argsList *list.List) formulaArg {
- if argsList.Len() != 6 && argsList.Len() != 7 {
- return newErrorFormulaArg(formulaErrorVALUE, "AMORDEGRC requires 6 or 7 arguments")
- }
- args := fn.prepareAmorArgs("AMORDEGRC", argsList)
- if args.Type != ArgList {
- return args
- }
- cost, datePurchased, firstPeriod, salvage, period, rate, basis := args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5], args.List[6]
- if rate.Number >= 0.5 {
- return newErrorFormulaArg(formulaErrorNUM, "AMORDEGRC requires rate to be < 0.5")
- }
- assetsLife, amorCoeff := 1/rate.Number, 2.5
- if assetsLife < 3 {
- amorCoeff = 1
- } else if assetsLife < 5 {
- amorCoeff = 1.5
- } else if assetsLife <= 6 {
- amorCoeff = 2
- }
- rate.Number *= amorCoeff
- frac := yearFrac(datePurchased.Number, firstPeriod.Number, int(basis.Number))
- if frac.Type != ArgNumber {
- return frac
- }
- nRate := float64(int((frac.Number * cost.Number * rate.Number) + 0.5))
- cost.Number -= nRate
- rest := cost.Number - salvage.Number
- for n := 0; n < int(period.Number); n++ {
- nRate = float64(int((cost.Number * rate.Number) + 0.5))
- rest -= nRate
- if rest < 0 {
- switch int(period.Number) - n {
- case 0:
- case 1:
- return newNumberFormulaArg(float64(int((cost.Number * 0.5) + 0.5)))
- default:
- return newNumberFormulaArg(0)
- }
- }
- cost.Number -= nRate
- }
- return newNumberFormulaArg(nRate)
- }
- // AMORLINC function is provided for users of the French accounting system.
- // The function calculates the prorated linear depreciation of an asset for a
- // specified accounting period. The syntax of the function is:
- //
- // AMORLINC(cost,date_purchased,first_period,salvage,period,rate,[basis])
- func (fn *formulaFuncs) AMORLINC(argsList *list.List) formulaArg {
- if argsList.Len() != 6 && argsList.Len() != 7 {
- return newErrorFormulaArg(formulaErrorVALUE, "AMORLINC requires 6 or 7 arguments")
- }
- args := fn.prepareAmorArgs("AMORLINC", argsList)
- if args.Type != ArgList {
- return args
- }
- cost, datePurchased, firstPeriod, salvage, period, rate, basis := args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5], args.List[6]
- frac := yearFrac(datePurchased.Number, firstPeriod.Number, int(basis.Number))
- if frac.Type != ArgNumber {
- return frac
- }
- rate1 := frac.Number * cost.Number * rate.Number
- if period.Number == 0 {
- return newNumberFormulaArg(rate1)
- }
- rate2 := cost.Number * rate.Number
- delta := cost.Number - salvage.Number
- periods := int((delta - rate1) / rate2)
- if int(period.Number) <= periods {
- return newNumberFormulaArg(rate2)
- } else if int(period.Number)-1 == periods {
- return newNumberFormulaArg(delta - rate2*float64(periods) - math.Nextafter(rate1, rate1))
- }
- return newNumberFormulaArg(0)
- }
- // prepareCouponArgs checking and prepare arguments for the formula functions
- // COUPDAYBS, COUPDAYS, COUPDAYSNC, COUPPCD, COUPNUM and COUPNCD.
- func (fn *formulaFuncs) prepareCouponArgs(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 3 && argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 3 or 4 arguments", name))
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- if settlement.Number >= maturity.Number {
- return newErrorFormulaArg(formulaErrorNUM, fmt.Sprintf("%s requires maturity > settlement", name))
- }
- frequency := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if frequency.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if !validateFrequency(frequency.Number) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 4 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- return newListFormulaArg([]formulaArg{settlement, maturity, frequency, basis})
- }
- // is30BasisMethod determine if the financial day count basis rules is 30/360
- // methods.
- func is30BasisMethod(basis int) bool {
- return basis == 0 || basis == 4
- }
- // getDaysInMonthRange return the day by given year, month range and day count
- // basis.
- func getDaysInMonthRange(fromMonth, toMonth int) int {
- if fromMonth > toMonth {
- return 0
- }
- return (toMonth - fromMonth + 1) * 30
- }
- // getDayOnBasis returns the day by given date and day count basis.
- func getDayOnBasis(y, m, d, basis int) int {
- if !is30BasisMethod(basis) {
- return d
- }
- day := d
- dim := getDaysInMonth(y, m)
- if day > 30 || d >= dim || day >= dim {
- day = 30
- }
- return day
- }
- // coupdays returns the number of days that base on date range and the day
- // count basis to be used.
- func coupdays(from, to time.Time, basis int) float64 {
- days := 0
- fromY, fromM, fromD := from.Date()
- toY, toM, toD := to.Date()
- fromDay, toDay := getDayOnBasis(fromY, int(fromM), fromD, basis), getDayOnBasis(toY, int(toM), toD, basis)
- if !is30BasisMethod(basis) {
- return (daysBetween(excelMinTime1900.Unix(), makeDate(toY, toM, toDay)) + 1) - (daysBetween(excelMinTime1900.Unix(), makeDate(fromY, fromM, fromDay)) + 1)
- }
- if basis == 0 {
- if (int(fromM) == 2 || fromDay < 30) && toD == 31 {
- toDay = 31
- }
- } else {
- if int(fromM) == 2 && fromDay == 30 {
- fromDay = getDaysInMonth(fromY, 2)
- }
- if int(toM) == 2 && toDay == 30 {
- toDay = getDaysInMonth(toY, 2)
- }
- }
- if fromY < toY || (fromY == toY && int(fromM) < int(toM)) {
- days = 30 - fromDay + 1
- fromD = 1
- fromDay = 1
- date := time.Date(fromY, fromM, fromD, 0, 0, 0, 0, time.UTC).AddDate(0, 1, 0)
- if date.Year() < toY {
- days += getDaysInMonthRange(int(date.Month()), 12)
- date = date.AddDate(0, 13-int(date.Month()), 0)
- }
- days += getDaysInMonthRange(int(date.Month()), int(toM)-1)
- }
- if days += toDay - fromDay; days > 0 {
- return float64(days)
- }
- return 0
- }
- // COUPDAYBS function calculates the number of days from the beginning of a
- // coupon's period to the settlement date. The syntax of the function is:
- //
- // COUPDAYBS(settlement,maturity,frequency,[basis])
- func (fn *formulaFuncs) COUPDAYBS(argsList *list.List) formulaArg {
- args := fn.prepareCouponArgs("COUPDAYBS", argsList)
- if args.Type != ArgList {
- return args
- }
- settlement := timeFromExcelTime(args.List[0].Number, false)
- pcd := timeFromExcelTime(fn.COUPPCD(argsList).Number, false)
- return newNumberFormulaArg(coupdays(pcd, settlement, int(args.List[3].Number)))
- }
- // COUPDAYS function calculates the number of days in a coupon period that
- // contains the settlement date. The syntax of the function is:
- //
- // COUPDAYS(settlement,maturity,frequency,[basis])
- func (fn *formulaFuncs) COUPDAYS(argsList *list.List) formulaArg {
- args := fn.prepareCouponArgs("COUPDAYS", argsList)
- if args.Type != ArgList {
- return args
- }
- freq := args.List[2].Number
- basis := int(args.List[3].Number)
- if basis == 1 {
- pcd := timeFromExcelTime(fn.COUPPCD(argsList).Number, false)
- next := pcd.AddDate(0, 12/int(freq), 0)
- return newNumberFormulaArg(coupdays(pcd, next, basis))
- }
- return newNumberFormulaArg(float64(getYearDays(0, basis)) / freq)
- }
- // COUPDAYSNC function calculates the number of days from the settlement date
- // to the next coupon date. The syntax of the function is:
- //
- // COUPDAYSNC(settlement,maturity,frequency,[basis])
- func (fn *formulaFuncs) COUPDAYSNC(argsList *list.List) formulaArg {
- args := fn.prepareCouponArgs("COUPDAYSNC", argsList)
- if args.Type != ArgList {
- return args
- }
- settlement := timeFromExcelTime(args.List[0].Number, false)
- basis := int(args.List[3].Number)
- ncd := timeFromExcelTime(fn.COUPNCD(argsList).Number, false)
- return newNumberFormulaArg(coupdays(settlement, ncd, basis))
- }
- // coupons is an implementation of the formula functions COUPNCD and COUPPCD.
- func (fn *formulaFuncs) coupons(name string, arg formulaArg) formulaArg {
- settlement := timeFromExcelTime(arg.List[0].Number, false)
- maturity := timeFromExcelTime(arg.List[1].Number, false)
- maturityDays := (maturity.Year()-settlement.Year())*12 + (int(maturity.Month()) - int(settlement.Month()))
- coupon := 12 / int(arg.List[2].Number)
- mod := maturityDays % coupon
- year := settlement.Year()
- month := int(settlement.Month())
- if mod == 0 && settlement.Day() >= maturity.Day() {
- month += coupon
- } else {
- month += mod
- }
- if name != "COUPNCD" {
- month -= coupon
- }
- if month > 11 {
- year++
- month -= 12
- } else if month < 0 {
- year--
- month += 12
- }
- day, lastDay := maturity.Day(), time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC)
- days := getDaysInMonth(lastDay.Year(), int(lastDay.Month()))
- if getDaysInMonth(maturity.Year(), int(maturity.Month())) == maturity.Day() {
- day = days
- } else if day > 27 && day > days {
- day = days
- }
- return newNumberFormulaArg(daysBetween(excelMinTime1900.Unix(), makeDate(year, time.Month(month), day)) + 1)
- }
- // COUPNCD function calculates the number of coupons payable, between a
- // security's settlement date and maturity date, rounded up to the nearest
- // whole coupon. The syntax of the function is:
- //
- // COUPNCD(settlement,maturity,frequency,[basis])
- func (fn *formulaFuncs) COUPNCD(argsList *list.List) formulaArg {
- args := fn.prepareCouponArgs("COUPNCD", argsList)
- if args.Type != ArgList {
- return args
- }
- return fn.coupons("COUPNCD", args)
- }
- // COUPNUM function calculates the number of coupons payable, between a
- // security's settlement date and maturity date, rounded up to the nearest
- // whole coupon. The syntax of the function is:
- //
- // COUPNUM(settlement,maturity,frequency,[basis])
- func (fn *formulaFuncs) COUPNUM(argsList *list.List) formulaArg {
- args := fn.prepareCouponArgs("COUPNUM", argsList)
- if args.Type != ArgList {
- return args
- }
- frac := yearFrac(args.List[0].Number, args.List[1].Number, 0)
- return newNumberFormulaArg(math.Ceil(frac.Number * args.List[2].Number))
- }
- // COUPPCD function returns the previous coupon date, before the settlement
- // date for a security. The syntax of the function is:
- //
- // COUPPCD(settlement,maturity,frequency,[basis])
- func (fn *formulaFuncs) COUPPCD(argsList *list.List) formulaArg {
- args := fn.prepareCouponArgs("COUPPCD", argsList)
- if args.Type != ArgList {
- return args
- }
- return fn.coupons("COUPPCD", args)
- }
- // CUMIPMT function calculates the cumulative interest paid on a loan or
- // investment, between two specified periods. The syntax of the function is:
- //
- // CUMIPMT(rate,nper,pv,start_period,end_period,type)
- func (fn *formulaFuncs) CUMIPMT(argsList *list.List) formulaArg {
- return fn.cumip("CUMIPMT", argsList)
- }
- // CUMPRINC function calculates the cumulative payment on the principal of a
- // loan or investment, between two specified periods. The syntax of the
- // function is:
- //
- // CUMPRINC(rate,nper,pv,start_period,end_period,type)
- func (fn *formulaFuncs) CUMPRINC(argsList *list.List) formulaArg {
- return fn.cumip("CUMPRINC", argsList)
- }
- // cumip is an implementation of the formula functions CUMIPMT and CUMPRINC.
- func (fn *formulaFuncs) cumip(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 6 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 6 arguments", name))
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- nper := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if nper.Type != ArgNumber {
- return nper
- }
- pv := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if pv.Type != ArgNumber {
- return pv
- }
- start := argsList.Back().Prev().Prev().Value.(formulaArg).ToNumber()
- if start.Type != ArgNumber {
- return start
- }
- end := argsList.Back().Prev().Value.(formulaArg).ToNumber()
- if end.Type != ArgNumber {
- return end
- }
- typ := argsList.Back().Value.(formulaArg).ToNumber()
- if typ.Type != ArgNumber {
- return typ
- }
- if typ.Number != 0 && typ.Number != 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if start.Number < 1 || start.Number > end.Number {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- num := 0.0
- for per := start.Number; per <= end.Number; per++ {
- args := list.New().Init()
- args.PushBack(rate)
- args.PushBack(newNumberFormulaArg(per))
- args.PushBack(nper)
- args.PushBack(pv)
- args.PushBack(newNumberFormulaArg(0))
- args.PushBack(typ)
- if name == "CUMIPMT" {
- num += fn.IPMT(args).Number
- continue
- }
- num += fn.PPMT(args).Number
- }
- return newNumberFormulaArg(num)
- }
- // calcDbArgsCompare implements common arguments' comparison for DB and DDB.
- func calcDbArgsCompare(cost, salvage, life, period formulaArg) bool {
- return (cost.Number <= 0) || ((salvage.Number / cost.Number) < 0) || (life.Number <= 0) || (period.Number < 1)
- }
- // DB function calculates the depreciation of an asset, using the Fixed
- // Declining Balance Method, for each period of the asset's lifetime. The
- // syntax of the function is:
- //
- // DB(cost,salvage,life,period,[month])
- func (fn *formulaFuncs) DB(argsList *list.List) formulaArg {
- if argsList.Len() < 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "DB requires at least 4 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "DB allows at most 5 arguments")
- }
- cost := argsList.Front().Value.(formulaArg).ToNumber()
- if cost.Type != ArgNumber {
- return cost
- }
- salvage := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if salvage.Type != ArgNumber {
- return salvage
- }
- life := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if life.Type != ArgNumber {
- return life
- }
- period := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if period.Type != ArgNumber {
- return period
- }
- month := newNumberFormulaArg(12)
- if argsList.Len() == 5 {
- if month = argsList.Back().Value.(formulaArg).ToNumber(); month.Type != ArgNumber {
- return month
- }
- }
- if cost.Number == 0 {
- return newNumberFormulaArg(0)
- }
- if calcDbArgsCompare(cost, salvage, life, period) || (month.Number < 1) {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- dr := 1 - math.Pow(salvage.Number/cost.Number, 1/life.Number)
- dr = math.Round(dr*1000) / 1000
- pd, depreciation := 0.0, 0.0
- for per := 1; per <= int(period.Number); per++ {
- if per == 1 {
- depreciation = cost.Number * dr * month.Number / 12
- } else if per == int(life.Number+1) {
- depreciation = (cost.Number - pd) * dr * (12 - month.Number) / 12
- } else {
- depreciation = (cost.Number - pd) * dr
- }
- pd += depreciation
- }
- return newNumberFormulaArg(depreciation)
- }
- // DDB function calculates the depreciation of an asset, using the Double
- // Declining Balance Method, or another specified depreciation rate. The
- // syntax of the function is:
- //
- // DDB(cost,salvage,life,period,[factor])
- func (fn *formulaFuncs) DDB(argsList *list.List) formulaArg {
- if argsList.Len() < 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "DDB requires at least 4 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "DDB allows at most 5 arguments")
- }
- cost := argsList.Front().Value.(formulaArg).ToNumber()
- if cost.Type != ArgNumber {
- return cost
- }
- salvage := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if salvage.Type != ArgNumber {
- return salvage
- }
- life := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if life.Type != ArgNumber {
- return life
- }
- period := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if period.Type != ArgNumber {
- return period
- }
- factor := newNumberFormulaArg(2)
- if argsList.Len() == 5 {
- if factor = argsList.Back().Value.(formulaArg).ToNumber(); factor.Type != ArgNumber {
- return factor
- }
- }
- if cost.Number == 0 {
- return newNumberFormulaArg(0)
- }
- if calcDbArgsCompare(cost, salvage, life, period) || (factor.Number <= 0.0) || (period.Number > life.Number) {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- pd, depreciation := 0.0, 0.0
- for per := 1; per <= int(period.Number); per++ {
- depreciation = math.Min((cost.Number-pd)*(factor.Number/life.Number), cost.Number-salvage.Number-pd)
- pd += depreciation
- }
- return newNumberFormulaArg(depreciation)
- }
- // prepareDataValueArgs convert first N arguments to data value for the
- // formula functions.
- func (fn *formulaFuncs) prepareDataValueArgs(n int, argsList *list.List) formulaArg {
- l := list.New()
- var dataValues []formulaArg
- getDateValue := func(arg formulaArg, l *list.List) formulaArg {
- switch arg.Type {
- case ArgNumber:
- break
- case ArgString:
- num := arg.ToNumber()
- if num.Type == ArgNumber {
- arg = num
- break
- }
- l.Init()
- l.PushBack(arg)
- arg = fn.DATEVALUE(l)
- if arg.Type == ArgError {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- default:
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- return arg
- }
- for i, arg := 0, argsList.Front(); i < n; arg = arg.Next() {
- dataValue := getDateValue(arg.Value.(formulaArg), l)
- if dataValue.Type != ArgNumber {
- return dataValue
- }
- dataValues = append(dataValues, dataValue)
- i++
- }
- return newListFormulaArg(dataValues)
- }
- // DISC function calculates the Discount Rate for a security. The syntax of
- // the function is:
- //
- // DISC(settlement,maturity,pr,redemption,[basis])
- func (fn *formulaFuncs) DISC(argsList *list.List) formulaArg {
- if argsList.Len() != 4 && argsList.Len() != 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "DISC requires 4 or 5 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- if maturity.Number <= settlement.Number {
- return newErrorFormulaArg(formulaErrorNUM, "DISC requires maturity > settlement")
- }
- pr := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if pr.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if pr.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "DISC requires pr > 0")
- }
- redemption := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if redemption.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if redemption.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "DISC requires redemption > 0")
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 5 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- frac := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
- if frac.Type != ArgNumber {
- return frac
- }
- return newNumberFormulaArg((redemption.Number - pr.Number) / redemption.Number / frac.Number)
- }
- // DOLLARDE function converts a dollar value in fractional notation, into a
- // dollar value expressed as a decimal. The syntax of the function is:
- //
- // DOLLARDE(fractional_dollar,fraction)
- func (fn *formulaFuncs) DOLLARDE(argsList *list.List) formulaArg {
- return fn.dollar("DOLLARDE", argsList)
- }
- // DOLLARFR function converts a dollar value in decimal notation, into a
- // dollar value that is expressed in fractional notation. The syntax of the
- // function is:
- //
- // DOLLARFR(decimal_dollar,fraction)
- func (fn *formulaFuncs) DOLLARFR(argsList *list.List) formulaArg {
- return fn.dollar("DOLLARFR", argsList)
- }
- // dollar is an implementation of the formula functions DOLLARDE and DOLLARFR.
- func (fn *formulaFuncs) dollar(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name))
- }
- dollar := argsList.Front().Value.(formulaArg).ToNumber()
- if dollar.Type != ArgNumber {
- return dollar
- }
- frac := argsList.Back().Value.(formulaArg).ToNumber()
- if frac.Type != ArgNumber {
- return frac
- }
- if frac.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if frac.Number == 0 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- cents := math.Mod(dollar.Number, 1)
- if name == "DOLLARDE" {
- cents /= frac.Number
- cents *= math.Pow(10, math.Ceil(math.Log10(frac.Number)))
- } else {
- cents *= frac.Number
- cents *= math.Pow(10, -math.Ceil(math.Log10(frac.Number)))
- }
- return newNumberFormulaArg(math.Floor(dollar.Number) + cents)
- }
- // prepareDurationArgs checking and prepare arguments for the formula
- // functions DURATION and MDURATION.
- func (fn *formulaFuncs) prepareDurationArgs(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 5 && argsList.Len() != 6 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 5 or 6 arguments", name))
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- if settlement.Number >= maturity.Number {
- return newErrorFormulaArg(formulaErrorNUM, fmt.Sprintf("%s requires maturity > settlement", name))
- }
- coupon := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if coupon.Type != ArgNumber {
- return coupon
- }
- if coupon.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, fmt.Sprintf("%s requires coupon >= 0", name))
- }
- yld := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if yld.Type != ArgNumber {
- return yld
- }
- if yld.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, fmt.Sprintf("%s requires yld >= 0", name))
- }
- frequency := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if frequency.Type != ArgNumber {
- return frequency
- }
- if !validateFrequency(frequency.Number) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 6 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- return newListFormulaArg([]formulaArg{settlement, maturity, coupon, yld, frequency, basis})
- }
- // duration is an implementation of the formula function DURATION.
- func (fn *formulaFuncs) duration(settlement, maturity, coupon, yld, frequency, basis formulaArg) formulaArg {
- frac := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
- if frac.Type != ArgNumber {
- return frac
- }
- argumments := list.New().Init()
- argumments.PushBack(settlement)
- argumments.PushBack(maturity)
- argumments.PushBack(frequency)
- argumments.PushBack(basis)
- coups := fn.COUPNUM(argumments)
- duration := 0.0
- p := 0.0
- coupon.Number *= 100 / frequency.Number
- yld.Number /= frequency.Number
- yld.Number++
- diff := frac.Number*frequency.Number - coups.Number
- for t := 1.0; t < coups.Number; t++ {
- tDiff := t + diff
- add := coupon.Number / math.Pow(yld.Number, tDiff)
- p += add
- duration += tDiff * add
- }
- add := (coupon.Number + 100) / math.Pow(yld.Number, coups.Number+diff)
- p += add
- duration += (coups.Number + diff) * add
- duration /= p
- duration /= frequency.Number
- return newNumberFormulaArg(duration)
- }
- // DURATION function calculates the Duration (specifically, the Macaulay
- // Duration) of a security that pays periodic interest, assuming a par value
- // of $100. The syntax of the function is:
- //
- // DURATION(settlement,maturity,coupon,yld,frequency,[basis])
- func (fn *formulaFuncs) DURATION(argsList *list.List) formulaArg {
- args := fn.prepareDurationArgs("DURATION", argsList)
- if args.Type != ArgList {
- return args
- }
- return fn.duration(args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5])
- }
- // EFFECT function returns the effective annual interest rate for a given
- // nominal interest rate and number of compounding periods per year. The
- // syntax of the function is:
- //
- // EFFECT(nominal_rate,npery)
- func (fn *formulaFuncs) EFFECT(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "EFFECT requires 2 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- npery := argsList.Back().Value.(formulaArg).ToNumber()
- if npery.Type != ArgNumber {
- return npery
- }
- if rate.Number <= 0 || npery.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(math.Pow(1+rate.Number/npery.Number, npery.Number) - 1)
- }
- // EUROCONVERT function convert a number to euro or from euro to a
- // participating currency. You can also use it to convert a number from one
- // participating currency to another by using the euro as an intermediary
- // (triangulation). The syntax of the function is:
- //
- // EUROCONVERT(number,sourcecurrency,targetcurrency[,fullprecision,triangulationprecision])
- func (fn *formulaFuncs) EUROCONVERT(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "EUROCONVERT requires at least 3 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "EUROCONVERT allows at most 5 arguments")
- }
- number := argsList.Front().Value.(formulaArg).ToNumber()
- if number.Type != ArgNumber {
- return number
- }
- sourceCurrency := argsList.Front().Next().Value.(formulaArg).Value()
- targetCurrency := argsList.Front().Next().Next().Value.(formulaArg).Value()
- fullPrec, triangulationPrec := newBoolFormulaArg(false), newNumberFormulaArg(0)
- if argsList.Len() >= 4 {
- if fullPrec = argsList.Front().Next().Next().Next().Value.(formulaArg).ToBool(); fullPrec.Type != ArgNumber {
- return fullPrec
- }
- }
- if argsList.Len() == 5 {
- if triangulationPrec = argsList.Back().Value.(formulaArg).ToNumber(); triangulationPrec.Type != ArgNumber {
- return triangulationPrec
- }
- }
- convertTable := map[string][]float64{
- "EUR": {1.0, 2},
- "ATS": {13.7603, 2},
- "BEF": {40.3399, 0},
- "DEM": {1.95583, 2},
- "ESP": {166.386, 0},
- "FIM": {5.94573, 2},
- "FRF": {6.55957, 2},
- "IEP": {0.787564, 2},
- "ITL": {1936.27, 0},
- "LUF": {40.3399, 0},
- "NLG": {2.20371, 2},
- "PTE": {200.482, 2},
- "GRD": {340.750, 2},
- "SIT": {239.640, 2},
- "MTL": {0.429300, 2},
- "CYP": {0.585274, 2},
- "SKK": {30.1260, 2},
- "EEK": {15.6466, 2},
- "LVL": {0.702804, 2},
- "LTL": {3.45280, 2},
- }
- source, ok := convertTable[sourceCurrency]
- if !ok {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- target, ok := convertTable[targetCurrency]
- if !ok {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if sourceCurrency == targetCurrency {
- return number
- }
- var res float64
- if sourceCurrency == "EUR" {
- res = number.Number * target[0]
- } else {
- intermediate := number.Number / source[0]
- if triangulationPrec.Number != 0 {
- ratio := math.Pow(10, triangulationPrec.Number)
- intermediate = math.Round(intermediate*ratio) / ratio
- }
- res = intermediate * target[0]
- }
- if fullPrec.Number != 1 {
- ratio := math.Pow(10, target[1])
- res = math.Round(res*ratio) / ratio
- }
- return newNumberFormulaArg(res)
- }
- // FV function calculates the Future Value of an investment with periodic
- // constant payments and a constant interest rate. The syntax of the function
- // is:
- //
- // FV(rate,nper,[pmt],[pv],[type])
- func (fn *formulaFuncs) FV(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "FV requires at least 3 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "FV allows at most 5 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- nper := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if nper.Type != ArgNumber {
- return nper
- }
- pmt := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if pmt.Type != ArgNumber {
- return pmt
- }
- pv, typ := newNumberFormulaArg(0), newNumberFormulaArg(0)
- if argsList.Len() >= 4 {
- if pv = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); pv.Type != ArgNumber {
- return pv
- }
- }
- if argsList.Len() == 5 {
- if typ = argsList.Back().Value.(formulaArg).ToNumber(); typ.Type != ArgNumber {
- return typ
- }
- }
- if typ.Number != 0 && typ.Number != 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if rate.Number != 0 {
- return newNumberFormulaArg(-pv.Number*math.Pow(1+rate.Number, nper.Number) - pmt.Number*(1+rate.Number*typ.Number)*(math.Pow(1+rate.Number, nper.Number)-1)/rate.Number)
- }
- return newNumberFormulaArg(-pv.Number - pmt.Number*nper.Number)
- }
- // FVSCHEDULE function calculates the Future Value of an investment with a
- // variable interest rate. The syntax of the function is:
- //
- // FVSCHEDULE(principal,schedule)
- func (fn *formulaFuncs) FVSCHEDULE(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "FVSCHEDULE requires 2 arguments")
- }
- pri := argsList.Front().Value.(formulaArg).ToNumber()
- if pri.Type != ArgNumber {
- return pri
- }
- principal := pri.Number
- for _, arg := range argsList.Back().Value.(formulaArg).ToList() {
- if arg.Value() == "" {
- continue
- }
- rate := arg.ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- principal *= 1 + rate.Number
- }
- return newNumberFormulaArg(principal)
- }
- // INTRATE function calculates the interest rate for a fully invested
- // security. The syntax of the function is:
- //
- // INTRATE(settlement,maturity,investment,redemption,[basis])
- func (fn *formulaFuncs) INTRATE(argsList *list.List) formulaArg {
- if argsList.Len() != 4 && argsList.Len() != 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "INTRATE requires 4 or 5 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- if maturity.Number <= settlement.Number {
- return newErrorFormulaArg(formulaErrorNUM, "INTRATE requires maturity > settlement")
- }
- investment := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if investment.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if investment.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "INTRATE requires investment > 0")
- }
- redemption := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if redemption.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if redemption.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "INTRATE requires redemption > 0")
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 5 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- frac := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
- if frac.Type != ArgNumber {
- return frac
- }
- return newNumberFormulaArg((redemption.Number - investment.Number) / investment.Number / frac.Number)
- }
- // IPMT function calculates the interest payment, during a specific period of a
- // loan or investment that is paid in constant periodic payments, with a
- // constant interest rate. The syntax of the function is:
- //
- // IPMT(rate,per,nper,pv,[fv],[type])
- func (fn *formulaFuncs) IPMT(argsList *list.List) formulaArg {
- return fn.ipmt("IPMT", argsList)
- }
- // calcIpmt is part of the implementation ipmt.
- func calcIpmt(name string, typ, per, pmt, pv, rate formulaArg) formulaArg {
- capital, interest, principal := pv.Number, 0.0, 0.0
- for i := 1; i <= int(per.Number); i++ {
- if typ.Number != 0 && i == 1 {
- interest = 0
- } else {
- interest = -capital * rate.Number
- }
- principal = pmt.Number - interest
- capital += principal
- }
- if name == "IPMT" {
- return newNumberFormulaArg(interest)
- }
- return newNumberFormulaArg(principal)
- }
- // ipmt is an implementation of the formula functions IPMT and PPMT.
- func (fn *formulaFuncs) ipmt(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 4 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 4 arguments", name))
- }
- if argsList.Len() > 6 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s allows at most 6 arguments", name))
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- per := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if per.Type != ArgNumber {
- return per
- }
- nper := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if nper.Type != ArgNumber {
- return nper
- }
- pv := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if pv.Type != ArgNumber {
- return pv
- }
- fv, typ := newNumberFormulaArg(0), newNumberFormulaArg(0)
- if argsList.Len() >= 5 {
- if fv = argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber(); fv.Type != ArgNumber {
- return fv
- }
- }
- if argsList.Len() == 6 {
- if typ = argsList.Back().Value.(formulaArg).ToNumber(); typ.Type != ArgNumber {
- return typ
- }
- }
- if typ.Number != 0 && typ.Number != 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if per.Number <= 0 || per.Number > nper.Number {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- args := list.New().Init()
- args.PushBack(rate)
- args.PushBack(nper)
- args.PushBack(pv)
- args.PushBack(fv)
- args.PushBack(typ)
- pmt := fn.PMT(args)
- return calcIpmt(name, typ, per, pmt, pv, rate)
- }
- // IRR function returns the Internal Rate of Return for a supplied series of
- // periodic cash flows (i.e. an initial investment value and a series of net
- // income values). The syntax of the function is:
- //
- // IRR(values,[guess])
- func (fn *formulaFuncs) IRR(argsList *list.List) formulaArg {
- if argsList.Len() < 1 {
- return newErrorFormulaArg(formulaErrorVALUE, "IRR requires at least 1 argument")
- }
- if argsList.Len() > 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "IRR allows at most 2 arguments")
- }
- values, guess := argsList.Front().Value.(formulaArg).ToList(), newNumberFormulaArg(0.1)
- if argsList.Len() > 1 {
- if guess = argsList.Back().Value.(formulaArg).ToNumber(); guess.Type != ArgNumber {
- return guess
- }
- }
- x1, x2 := newNumberFormulaArg(0), guess
- args := list.New().Init()
- args.PushBack(x1)
- for _, v := range values {
- args.PushBack(v)
- }
- f1 := fn.NPV(args)
- args.Front().Value = x2
- f2 := fn.NPV(args)
- for i := 0; i < maxFinancialIterations; i++ {
- if f1.Number*f2.Number < 0 {
- break
- }
- if math.Abs(f1.Number) < math.Abs(f2.Number) {
- x1.Number += 1.6 * (x1.Number - x2.Number)
- args.Front().Value = x1
- f1 = fn.NPV(args)
- continue
- }
- x2.Number += 1.6 * (x2.Number - x1.Number)
- args.Front().Value = x2
- f2 = fn.NPV(args)
- }
- if f1.Number*f2.Number > 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- args.Front().Value = x1
- f := fn.NPV(args)
- var rtb, dx, xMid, fMid float64
- if f.Number < 0 {
- rtb = x1.Number
- dx = x2.Number - x1.Number
- } else {
- rtb = x2.Number
- dx = x1.Number - x2.Number
- }
- for i := 0; i < maxFinancialIterations; i++ {
- dx *= 0.5
- xMid = rtb + dx
- args.Front().Value = newNumberFormulaArg(xMid)
- fMid = fn.NPV(args).Number
- if fMid <= 0 {
- rtb = xMid
- }
- if math.Abs(fMid) < financialPrecision || math.Abs(dx) < financialPrecision {
- break
- }
- }
- return newNumberFormulaArg(xMid)
- }
- // ISPMT function calculates the interest paid during a specific period of a
- // loan or investment. The syntax of the function is:
- //
- // ISPMT(rate,per,nper,pv)
- func (fn *formulaFuncs) ISPMT(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "ISPMT requires 4 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- per := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if per.Type != ArgNumber {
- return per
- }
- nper := argsList.Back().Prev().Value.(formulaArg).ToNumber()
- if nper.Type != ArgNumber {
- return nper
- }
- pv := argsList.Back().Value.(formulaArg).ToNumber()
- if pv.Type != ArgNumber {
- return pv
- }
- pr, payment, num := pv.Number, pv.Number/nper.Number, 0.0
- for i := 0; i <= int(per.Number); i++ {
- num = rate.Number * pr * -1
- pr -= payment
- if i == int(nper.Number) {
- num = 0
- }
- }
- return newNumberFormulaArg(num)
- }
- // MDURATION function calculates the Modified Macaulay Duration of a security
- // that pays periodic interest, assuming a par value of $100. The syntax of
- // the function is:
- //
- // MDURATION(settlement,maturity,coupon,yld,frequency,[basis])
- func (fn *formulaFuncs) MDURATION(argsList *list.List) formulaArg {
- args := fn.prepareDurationArgs("MDURATION", argsList)
- if args.Type != ArgList {
- return args
- }
- duration := fn.duration(args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5])
- if duration.Type != ArgNumber {
- return duration
- }
- return newNumberFormulaArg(duration.Number / (1 + args.List[3].Number/args.List[4].Number))
- }
- // MIRR function returns the Modified Internal Rate of Return for a supplied
- // series of periodic cash flows (i.e. a set of values, which includes an
- // initial investment value and a series of net income values). The syntax of
- // the function is:
- //
- // MIRR(values,finance_rate,reinvest_rate)
- func (fn *formulaFuncs) MIRR(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "MIRR requires 3 arguments")
- }
- values := argsList.Front().Value.(formulaArg).ToList()
- financeRate := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if financeRate.Type != ArgNumber {
- return financeRate
- }
- reinvestRate := argsList.Back().Value.(formulaArg).ToNumber()
- if reinvestRate.Type != ArgNumber {
- return reinvestRate
- }
- n, fr, rr, npvPos, npvNeg := len(values), 1+financeRate.Number, 1+reinvestRate.Number, 0.0, 0.0
- for i, v := range values {
- val := v.ToNumber()
- if val.Number >= 0 {
- npvPos += val.Number / math.Pow(rr, float64(i))
- continue
- }
- npvNeg += val.Number / math.Pow(fr, float64(i))
- }
- if npvNeg == 0 || npvPos == 0 || reinvestRate.Number <= -1 {
- return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
- }
- return newNumberFormulaArg(math.Pow(-npvPos*math.Pow(rr, float64(n))/(npvNeg*rr), 1/(float64(n)-1)) - 1)
- }
- // NOMINAL function returns the nominal interest rate for a given effective
- // interest rate and number of compounding periods per year. The syntax of
- // the function is:
- //
- // NOMINAL(effect_rate,npery)
- func (fn *formulaFuncs) NOMINAL(argsList *list.List) formulaArg {
- if argsList.Len() != 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "NOMINAL requires 2 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- npery := argsList.Back().Value.(formulaArg).ToNumber()
- if npery.Type != ArgNumber {
- return npery
- }
- if rate.Number <= 0 || npery.Number < 1 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(npery.Number * (math.Pow(rate.Number+1, 1/npery.Number) - 1))
- }
- // NPER function calculates the number of periods required to pay off a loan,
- // for a constant periodic payment and a constant interest rate. The syntax
- // of the function is:
- //
- // NPER(rate,pmt,pv,[fv],[type])
- func (fn *formulaFuncs) NPER(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "NPER requires at least 3 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "NPER allows at most 5 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- pmt := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if pmt.Type != ArgNumber {
- return pmt
- }
- pv := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if pv.Type != ArgNumber {
- return pv
- }
- fv, typ := newNumberFormulaArg(0), newNumberFormulaArg(0)
- if argsList.Len() >= 4 {
- if fv = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); fv.Type != ArgNumber {
- return fv
- }
- }
- if argsList.Len() == 5 {
- if typ = argsList.Back().Value.(formulaArg).ToNumber(); typ.Type != ArgNumber {
- return typ
- }
- }
- if typ.Number != 0 && typ.Number != 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if pmt.Number == 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if rate.Number != 0 {
- p := math.Log((pmt.Number*(1+rate.Number*typ.Number)/rate.Number-fv.Number)/(pv.Number+pmt.Number*(1+rate.Number*typ.Number)/rate.Number)) / math.Log(1+rate.Number)
- return newNumberFormulaArg(p)
- }
- return newNumberFormulaArg((-pv.Number - fv.Number) / pmt.Number)
- }
- // NPV function calculates the Net Present Value of an investment, based on a
- // supplied discount rate, and a series of future payments and income. The
- // syntax of the function is:
- //
- // NPV(rate,value1,[value2],[value3],...)
- func (fn *formulaFuncs) NPV(argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "NPV requires at least 2 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- val, i := 0.0, 1
- for arg := argsList.Front().Next(); arg != nil; arg = arg.Next() {
- num := arg.Value.(formulaArg).ToNumber()
- if num.Type != ArgNumber {
- continue
- }
- val += num.Number / math.Pow(1+rate.Number, float64(i))
- i++
- }
- return newNumberFormulaArg(val)
- }
- // aggrBetween is a part of implementation of the formula function ODDFPRICE.
- func aggrBetween(startPeriod, endPeriod float64, initialValue []float64, f func(acc []float64, index float64) []float64) []float64 {
- var s []float64
- if startPeriod <= endPeriod {
- for i := startPeriod; i <= endPeriod; i++ {
- s = append(s, i)
- }
- } else {
- for i := startPeriod; i >= endPeriod; i-- {
- s = append(s, i)
- }
- }
- return fold(f, initialValue, s)
- }
- // fold is a part of implementation of the formula function ODDFPRICE.
- func fold(f func(acc []float64, index float64) []float64, state []float64, source []float64) []float64 {
- length, value := len(source), state
- for index := 0; length > index; index++ {
- value = f(value, source[index])
- }
- return value
- }
- // changeMonth is a part of implementation of the formula function ODDFPRICE.
- func changeMonth(date time.Time, numMonths float64, returnLastMonth bool) time.Time {
- offsetDay := 0
- if returnLastMonth && date.Day() == getDaysInMonth(date.Year(), int(date.Month())) {
- offsetDay--
- }
- newDate := date.AddDate(0, int(numMonths), offsetDay)
- if returnLastMonth {
- lastDay := getDaysInMonth(newDate.Year(), int(newDate.Month()))
- return timeFromExcelTime(daysBetween(excelMinTime1900.Unix(), makeDate(newDate.Year(), newDate.Month(), lastDay))+1, false)
- }
- return newDate
- }
- // datesAggregate is a part of implementation of the formula function
- // ODDFPRICE.
- func datesAggregate(startDate, endDate time.Time, numMonths float64, f func(pcd, ncd time.Time) float64, acc float64, returnLastMonth bool) (time.Time, time.Time, float64) {
- frontDate, trailingDate := startDate, endDate
- s1 := frontDate.After(endDate) || frontDate.Equal(endDate)
- s2 := endDate.After(frontDate) || endDate.Equal(frontDate)
- stop := s2
- if numMonths > 0 {
- stop = s1
- }
- for !stop {
- trailingDate = frontDate
- frontDate = changeMonth(frontDate, numMonths, returnLastMonth)
- fn := f(frontDate, trailingDate)
- acc += fn
- s1 = frontDate.After(endDate) || frontDate.Equal(endDate)
- s2 = endDate.After(frontDate) || endDate.Equal(frontDate)
- stop = s2
- if numMonths > 0 {
- stop = s1
- }
- }
- return frontDate, trailingDate, acc
- }
- // coupNumber is a part of implementation of the formula function ODDFPRICE.
- func coupNumber(maturity, settlement, numMonths float64) float64 {
- maturityTime, settlementTime := timeFromExcelTime(maturity, false), timeFromExcelTime(settlement, false)
- my, mm, md := maturityTime.Year(), maturityTime.Month(), maturityTime.Day()
- sy, sm, sd := settlementTime.Year(), settlementTime.Month(), settlementTime.Day()
- couponsTemp, endOfMonthTemp := 0.0, getDaysInMonth(my, int(mm)) == md
- endOfMonth := endOfMonthTemp
- if !endOfMonthTemp && mm != 2 && md > 28 && md < getDaysInMonth(my, int(mm)) {
- endOfMonth = getDaysInMonth(sy, int(sm)) == sd
- }
- startDate := changeMonth(settlementTime, 0, endOfMonth)
- coupons := couponsTemp
- if startDate.After(settlementTime) {
- coupons++
- }
- date := changeMonth(startDate, numMonths, endOfMonth)
- f := func(pcd, ncd time.Time) float64 {
- return 1
- }
- _, _, result := datesAggregate(date, maturityTime, numMonths, f, coupons, endOfMonth)
- return result
- }
- // prepareOddfpriceArgs checking and prepare arguments for the formula
- // function ODDFPRICE.
- func (fn *formulaFuncs) prepareOddfpriceArgs(argsList *list.List) formulaArg {
- dateValues := fn.prepareDataValueArgs(4, argsList)
- if dateValues.Type != ArgList {
- return dateValues
- }
- settlement, maturity, issue, firstCoupon := dateValues.List[0], dateValues.List[1], dateValues.List[2], dateValues.List[3]
- if issue.Number >= settlement.Number {
- return newErrorFormulaArg(formulaErrorNUM, "ODDFPRICE requires settlement > issue")
- }
- if settlement.Number >= firstCoupon.Number {
- return newErrorFormulaArg(formulaErrorNUM, "ODDFPRICE requires first_coupon > settlement")
- }
- if firstCoupon.Number >= maturity.Number {
- return newErrorFormulaArg(formulaErrorNUM, "ODDFPRICE requires maturity > first_coupon")
- }
- rate := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- if rate.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "ODDFPRICE requires rate >= 0")
- }
- yld := argsList.Front().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if yld.Type != ArgNumber {
- return yld
- }
- if yld.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "ODDFPRICE requires yld >= 0")
- }
- redemption := argsList.Front().Next().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if redemption.Type != ArgNumber {
- return redemption
- }
- if redemption.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "ODDFPRICE requires redemption > 0")
- }
- frequency := argsList.Front().Next().Next().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if frequency.Type != ArgNumber {
- return frequency
- }
- if !validateFrequency(frequency.Number) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 9 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- return newListFormulaArg([]formulaArg{settlement, maturity, issue, firstCoupon, rate, yld, redemption, frequency, basis})
- }
- // ODDFPRICE function calculates the price per $100 face value of a security
- // with an odd (short or long) first period. The syntax of the function is:
- //
- // ODDFPRICE(settlement,maturity,issue,first_coupon,rate,yld,redemption,frequency,[basis])
- func (fn *formulaFuncs) ODDFPRICE(argsList *list.List) formulaArg {
- if argsList.Len() != 8 && argsList.Len() != 9 {
- return newErrorFormulaArg(formulaErrorVALUE, "ODDFPRICE requires 8 or 9 arguments")
- }
- args := fn.prepareOddfpriceArgs(argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity, issue, firstCoupon, rate, yld, redemption, frequency, basisArg := args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5], args.List[6], args.List[7], args.List[8]
- if basisArg.Number < 0 || basisArg.Number > 4 {
- return newErrorFormulaArg(formulaErrorNUM, "invalid basis")
- }
- issueTime := timeFromExcelTime(issue.Number, false)
- settlementTime := timeFromExcelTime(settlement.Number, false)
- maturityTime := timeFromExcelTime(maturity.Number, false)
- firstCouponTime := timeFromExcelTime(firstCoupon.Number, false)
- basis := int(basisArg.Number)
- monthDays := getDaysInMonth(maturityTime.Year(), int(maturityTime.Month()))
- returnLastMonth := monthDays == maturityTime.Day()
- numMonths := 12 / frequency.Number
- numMonthsNeg := -numMonths
- mat := changeMonth(maturityTime, numMonthsNeg, returnLastMonth)
- pcd, _, _ := datesAggregate(mat, firstCouponTime, numMonthsNeg, func(d1, d2 time.Time) float64 {
- return 0
- }, 0, returnLastMonth)
- if !pcd.Equal(firstCouponTime) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- fnArgs := list.New().Init()
- fnArgs.PushBack(settlement)
- fnArgs.PushBack(maturity)
- fnArgs.PushBack(frequency)
- fnArgs.PushBack(basisArg)
- e := fn.COUPDAYS(fnArgs)
- n := fn.COUPNUM(fnArgs)
- m := frequency.Number
- dfc := coupdays(issueTime, firstCouponTime, basis)
- if dfc < e.Number {
- dsc := coupdays(settlementTime, firstCouponTime, basis)
- a := coupdays(issueTime, settlementTime, basis)
- x := yld.Number/m + 1
- y := dsc / e.Number
- p1 := x
- p3 := math.Pow(p1, n.Number-1+y)
- term1 := redemption.Number / p3
- term2 := 100 * rate.Number / m * dfc / e.Number / math.Pow(p1, y)
- f := func(acc []float64, index float64) []float64 {
- return []float64{acc[0] + 100*rate.Number/m/math.Pow(p1, index-1+y)}
- }
- term3 := aggrBetween(2, math.Floor(n.Number), []float64{0}, f)
- p2 := rate.Number / m
- term4 := a / e.Number * p2 * 100
- return newNumberFormulaArg(term1 + term2 + term3[0] - term4)
- }
- fnArgs.Init()
- fnArgs.PushBack(issue)
- fnArgs.PushBack(firstCoupon)
- fnArgs.PushBack(frequency)
- nc := fn.COUPNUM(fnArgs)
- lastCoupon := firstCoupon.Number
- aggrFunc := func(acc []float64, index float64) []float64 {
- lastCouponTime := timeFromExcelTime(lastCoupon, false)
- earlyCoupon := daysBetween(excelMinTime1900.Unix(), makeDate(lastCouponTime.Year(), time.Month(float64(lastCouponTime.Month())+numMonthsNeg), lastCouponTime.Day())) + 1
- earlyCouponTime := timeFromExcelTime(earlyCoupon, false)
- nl := e.Number
- if basis == 1 {
- nl = coupdays(earlyCouponTime, lastCouponTime, basis)
- }
- dci := coupdays(issueTime, lastCouponTime, basis)
- if index > 1 {
- dci = nl
- }
- startDate := earlyCoupon
- if issue.Number > earlyCoupon {
- startDate = issue.Number
- }
- endDate := lastCoupon
- if settlement.Number < lastCoupon {
- endDate = settlement.Number
- }
- startDateTime := timeFromExcelTime(startDate, false)
- endDateTime := timeFromExcelTime(endDate, false)
- a := coupdays(startDateTime, endDateTime, basis)
- lastCoupon = earlyCoupon
- dcnl := acc[0]
- anl := acc[1]
- return []float64{dcnl + dci/nl, anl + a/nl}
- }
- ag := aggrBetween(math.Floor(nc.Number), 1, []float64{0, 0}, aggrFunc)
- dcnl, anl := ag[0], ag[1]
- dsc := 0.0
- fnArgs.Init()
- fnArgs.PushBack(settlement)
- fnArgs.PushBack(firstCoupon)
- fnArgs.PushBack(frequency)
- if basis == 2 || basis == 3 {
- d := timeFromExcelTime(fn.COUPNCD(fnArgs).Number, false)
- dsc = coupdays(settlementTime, d, basis)
- } else {
- d := timeFromExcelTime(fn.COUPPCD(fnArgs).Number, false)
- a := coupdays(d, settlementTime, basis)
- dsc = e.Number - a
- }
- nq := coupNumber(firstCoupon.Number, settlement.Number, numMonths)
- fnArgs.Init()
- fnArgs.PushBack(firstCoupon)
- fnArgs.PushBack(maturity)
- fnArgs.PushBack(frequency)
- fnArgs.PushBack(basisArg)
- n = fn.COUPNUM(fnArgs)
- x := yld.Number/m + 1
- y := dsc / e.Number
- p1 := x
- p3 := math.Pow(p1, y+nq+n.Number)
- term1 := redemption.Number / p3
- term2 := 100 * rate.Number / m * dcnl / math.Pow(p1, nq+y)
- f := func(acc []float64, index float64) []float64 {
- return []float64{acc[0] + 100*rate.Number/m/math.Pow(p1, index+nq+y)}
- }
- term3 := aggrBetween(1, math.Floor(n.Number), []float64{0}, f)
- term4 := 100 * rate.Number / m * anl
- return newNumberFormulaArg(term1 + term2 + term3[0] - term4)
- }
- // PDURATION function calculates the number of periods required for an
- // investment to reach a specified future value. The syntax of the function
- // is:
- //
- // PDURATION(rate,pv,fv)
- func (fn *formulaFuncs) PDURATION(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "PDURATION requires 3 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- pv := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if pv.Type != ArgNumber {
- return pv
- }
- fv := argsList.Back().Value.(formulaArg).ToNumber()
- if fv.Type != ArgNumber {
- return fv
- }
- if rate.Number <= 0 || pv.Number <= 0 || fv.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg((math.Log(fv.Number) - math.Log(pv.Number)) / math.Log(1+rate.Number))
- }
- // PMT function calculates the constant periodic payment required to pay off
- // (or partially pay off) a loan or investment, with a constant interest
- // rate, over a specified period. The syntax of the function is:
- //
- // PMT(rate,nper,pv,[fv],[type])
- func (fn *formulaFuncs) PMT(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "PMT requires at least 3 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "PMT allows at most 5 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- nper := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if nper.Type != ArgNumber {
- return nper
- }
- pv := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if pv.Type != ArgNumber {
- return pv
- }
- fv, typ := newNumberFormulaArg(0), newNumberFormulaArg(0)
- if argsList.Len() >= 4 {
- if fv = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); fv.Type != ArgNumber {
- return fv
- }
- }
- if argsList.Len() == 5 {
- if typ = argsList.Back().Value.(formulaArg).ToNumber(); typ.Type != ArgNumber {
- return typ
- }
- }
- if typ.Number != 0 && typ.Number != 1 {
- return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
- }
- if rate.Number != 0 {
- p := (-fv.Number - pv.Number*math.Pow(1+rate.Number, nper.Number)) / (1 + rate.Number*typ.Number) / ((math.Pow(1+rate.Number, nper.Number) - 1) / rate.Number)
- return newNumberFormulaArg(p)
- }
- return newNumberFormulaArg((-pv.Number - fv.Number) / nper.Number)
- }
- // PPMT function calculates the payment on the principal, during a specific
- // period of a loan or investment that is paid in constant periodic payments,
- // with a constant interest rate. The syntax of the function is:
- //
- // PPMT(rate,per,nper,pv,[fv],[type])
- func (fn *formulaFuncs) PPMT(argsList *list.List) formulaArg {
- return fn.ipmt("PPMT", argsList)
- }
- // price is an implementation of the formula function PRICE.
- func (fn *formulaFuncs) price(settlement, maturity, rate, yld, redemption, frequency, basis formulaArg) formulaArg {
- if basis.Number < 0 || basis.Number > 4 {
- return newErrorFormulaArg(formulaErrorNUM, "invalid basis")
- }
- argsList := list.New().Init()
- argsList.PushBack(settlement)
- argsList.PushBack(maturity)
- argsList.PushBack(frequency)
- argsList.PushBack(basis)
- e := fn.COUPDAYS(argsList)
- dsc := fn.COUPDAYSNC(argsList).Number / e.Number
- n := fn.COUPNUM(argsList)
- a := fn.COUPDAYBS(argsList)
- ret := 0.0
- if n.Number > 1 {
- ret = redemption.Number / math.Pow(1+yld.Number/frequency.Number, n.Number-1+dsc)
- ret -= 100 * rate.Number / frequency.Number * a.Number / e.Number
- t1 := 100 * rate.Number / frequency.Number
- t2 := 1 + yld.Number/frequency.Number
- for k := 0.0; k < n.Number; k++ {
- ret += t1 / math.Pow(t2, k+dsc)
- }
- } else {
- dsc = e.Number - a.Number
- t1 := 100*(rate.Number/frequency.Number) + redemption.Number
- t2 := (yld.Number/frequency.Number)*(dsc/e.Number) + 1
- t3 := 100 * (rate.Number / frequency.Number) * (a.Number / e.Number)
- ret = t1/t2 - t3
- }
- return newNumberFormulaArg(ret)
- }
- // PRICE function calculates the price, per $100 face value of a security that
- // pays periodic interest. The syntax of the function is:
- //
- // PRICE(settlement,maturity,rate,yld,redemption,frequency,[basis])
- func (fn *formulaFuncs) PRICE(argsList *list.List) formulaArg {
- if argsList.Len() != 6 && argsList.Len() != 7 {
- return newErrorFormulaArg(formulaErrorVALUE, "PRICE requires 6 or 7 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- rate := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- if rate.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICE requires rate >= 0")
- }
- yld := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if yld.Type != ArgNumber {
- return yld
- }
- if yld.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICE requires yld >= 0")
- }
- redemption := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if redemption.Type != ArgNumber {
- return redemption
- }
- if redemption.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICE requires redemption > 0")
- }
- frequency := argsList.Front().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if frequency.Type != ArgNumber {
- return frequency
- }
- if !validateFrequency(frequency.Number) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 7 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- return fn.price(settlement, maturity, rate, yld, redemption, frequency, basis)
- }
- // PRICEDISC function calculates the price, per $100 face value of a
- // discounted security. The syntax of the function is:
- //
- // PRICEDISC(settlement,maturity,discount,redemption,[basis])
- func (fn *formulaFuncs) PRICEDISC(argsList *list.List) formulaArg {
- if argsList.Len() != 4 && argsList.Len() != 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "PRICEDISC requires 4 or 5 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- if maturity.Number <= settlement.Number {
- return newErrorFormulaArg(formulaErrorNUM, "PRICEDISC requires maturity > settlement")
- }
- discount := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if discount.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if discount.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICEDISC requires discount > 0")
- }
- redemption := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if redemption.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if redemption.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICEDISC requires redemption > 0")
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 5 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- frac := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
- if frac.Type != ArgNumber {
- return frac
- }
- return newNumberFormulaArg(redemption.Number * (1 - discount.Number*frac.Number))
- }
- // PRICEMAT function calculates the price, per $100 face value of a security
- // that pays interest at maturity. The syntax of the function is:
- //
- // PRICEMAT(settlement,maturity,issue,rate,yld,[basis])
- func (fn *formulaFuncs) PRICEMAT(argsList *list.List) formulaArg {
- if argsList.Len() != 5 && argsList.Len() != 6 {
- return newErrorFormulaArg(formulaErrorVALUE, "PRICEMAT requires 5 or 6 arguments")
- }
- args := fn.prepareDataValueArgs(3, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity, issue := args.List[0], args.List[1], args.List[2]
- if settlement.Number >= maturity.Number {
- return newErrorFormulaArg(formulaErrorNUM, "PRICEMAT requires maturity > settlement")
- }
- if issue.Number >= settlement.Number {
- return newErrorFormulaArg(formulaErrorNUM, "PRICEMAT requires settlement > issue")
- }
- rate := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- if rate.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICEMAT requires rate >= 0")
- }
- yld := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if yld.Type != ArgNumber {
- return yld
- }
- if yld.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICEMAT requires yld >= 0")
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 6 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- dsm := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
- if dsm.Type != ArgNumber {
- return dsm
- }
- dis := yearFrac(issue.Number, settlement.Number, int(basis.Number))
- dim := yearFrac(issue.Number, maturity.Number, int(basis.Number))
- return newNumberFormulaArg(((1+dim.Number*rate.Number)/(1+dsm.Number*yld.Number) - dis.Number*rate.Number) * 100)
- }
- // PV function calculates the Present Value of an investment, based on a
- // series of future payments. The syntax of the function is:
- //
- // PV(rate,nper,pmt,[fv],[type])
- func (fn *formulaFuncs) PV(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "PV requires at least 3 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "PV allows at most 5 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- nper := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if nper.Type != ArgNumber {
- return nper
- }
- pmt := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if pmt.Type != ArgNumber {
- return pmt
- }
- fv := newNumberFormulaArg(0)
- if argsList.Len() >= 4 {
- if fv = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); fv.Type != ArgNumber {
- return fv
- }
- }
- t := newNumberFormulaArg(0)
- if argsList.Len() == 5 {
- if t = argsList.Back().Value.(formulaArg).ToNumber(); t.Type != ArgNumber {
- return t
- }
- if t.Number != 0 {
- t.Number = 1
- }
- }
- if rate.Number == 0 {
- return newNumberFormulaArg(-pmt.Number*nper.Number - fv.Number)
- }
- return newNumberFormulaArg((((1-math.Pow(1+rate.Number, nper.Number))/rate.Number)*pmt.Number*(1+rate.Number*t.Number) - fv.Number) / math.Pow(1+rate.Number, nper.Number))
- }
- // rate is an implementation of the formula function RATE.
- func (fn *formulaFuncs) rate(nper, pmt, pv, fv, t, guess formulaArg) formulaArg {
- maxIter, iter, isClose, epsMax, rate := 100, 0, false, 1e-6, guess.Number
- for iter < maxIter && !isClose {
- t1 := math.Pow(rate+1, nper.Number)
- t2 := math.Pow(rate+1, nper.Number-1)
- rt := rate*t.Number + 1
- p0 := pmt.Number * (t1 - 1)
- f1 := fv.Number + t1*pv.Number + p0*rt/rate
- n1 := nper.Number * t2 * pv.Number
- n2 := p0 * rt / math.Pow(rate, 2)
- f2 := math.Nextafter(n1, n1) - math.Nextafter(n2, n2)
- f3 := (nper.Number*pmt.Number*t2*rt + p0*t.Number) / rate
- delta := f1 / (f2 + f3)
- if math.Abs(delta) < epsMax {
- isClose = true
- }
- iter++
- rate -= delta
- }
- return newNumberFormulaArg(rate)
- }
- // RATE function calculates the interest rate required to pay off a specified
- // amount of a loan, or to reach a target amount on an investment, over a
- // given period. The syntax of the function is:
- //
- // RATE(nper,pmt,pv,[fv],[type],[guess])
- func (fn *formulaFuncs) RATE(argsList *list.List) formulaArg {
- if argsList.Len() < 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "RATE requires at least 3 arguments")
- }
- if argsList.Len() > 6 {
- return newErrorFormulaArg(formulaErrorVALUE, "RATE allows at most 6 arguments")
- }
- nper := argsList.Front().Value.(formulaArg).ToNumber()
- if nper.Type != ArgNumber {
- return nper
- }
- pmt := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if pmt.Type != ArgNumber {
- return pmt
- }
- pv := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if pv.Type != ArgNumber {
- return pv
- }
- fv := newNumberFormulaArg(0)
- if argsList.Len() >= 4 {
- if fv = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); fv.Type != ArgNumber {
- return fv
- }
- }
- t := newNumberFormulaArg(0)
- if argsList.Len() >= 5 {
- if t = argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber(); t.Type != ArgNumber {
- return t
- }
- if t.Number != 0 {
- t.Number = 1
- }
- }
- guess := newNumberFormulaArg(0.1)
- if argsList.Len() == 6 {
- if guess = argsList.Back().Value.(formulaArg).ToNumber(); guess.Type != ArgNumber {
- return guess
- }
- }
- return fn.rate(nper, pmt, pv, fv, t, guess)
- }
- // RECEIVED function calculates the amount received at maturity for a fully
- // invested security. The syntax of the function is:
- //
- // RECEIVED(settlement,maturity,investment,discount,[basis])
- func (fn *formulaFuncs) RECEIVED(argsList *list.List) formulaArg {
- if argsList.Len() < 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "RECEIVED requires at least 4 arguments")
- }
- if argsList.Len() > 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "RECEIVED allows at most 5 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- investment := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if investment.Type != ArgNumber {
- return investment
- }
- discount := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if discount.Type != ArgNumber {
- return discount
- }
- if discount.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "RECEIVED requires discount > 0")
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 5 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- frac := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
- if frac.Type != ArgNumber {
- return frac
- }
- return newNumberFormulaArg(investment.Number / (1 - discount.Number*frac.Number))
- }
- // RRI function calculates the equivalent interest rate for an investment with
- // specified present value, future value and duration. The syntax of the
- // function is:
- //
- // RRI(nper,pv,fv)
- func (fn *formulaFuncs) RRI(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "RRI requires 3 arguments")
- }
- nper := argsList.Front().Value.(formulaArg).ToNumber()
- pv := argsList.Front().Next().Value.(formulaArg).ToNumber()
- fv := argsList.Back().Value.(formulaArg).ToNumber()
- if nper.Type != ArgNumber || pv.Type != ArgNumber || fv.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if nper.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "RRI requires nper argument to be > 0")
- }
- if pv.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "RRI requires pv argument to be > 0")
- }
- if fv.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "RRI requires fv argument to be >= 0")
- }
- return newNumberFormulaArg(math.Pow(fv.Number/pv.Number, 1/nper.Number) - 1)
- }
- // SLN function calculates the straight line depreciation of an asset for one
- // period. The syntax of the function is:
- //
- // SLN(cost,salvage,life)
- func (fn *formulaFuncs) SLN(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "SLN requires 3 arguments")
- }
- cost := argsList.Front().Value.(formulaArg).ToNumber()
- salvage := argsList.Front().Next().Value.(formulaArg).ToNumber()
- life := argsList.Back().Value.(formulaArg).ToNumber()
- if cost.Type != ArgNumber || salvage.Type != ArgNumber || life.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if life.Number == 0 {
- return newErrorFormulaArg(formulaErrorNUM, "SLN requires life argument to be > 0")
- }
- return newNumberFormulaArg((cost.Number - salvage.Number) / life.Number)
- }
- // SYD function calculates the sum-of-years' digits depreciation for a
- // specified period in the lifetime of an asset. The syntax of the function
- // is:
- //
- // SYD(cost,salvage,life,per)
- func (fn *formulaFuncs) SYD(argsList *list.List) formulaArg {
- if argsList.Len() != 4 {
- return newErrorFormulaArg(formulaErrorVALUE, "SYD requires 4 arguments")
- }
- cost := argsList.Front().Value.(formulaArg).ToNumber()
- salvage := argsList.Front().Next().Value.(formulaArg).ToNumber()
- life := argsList.Back().Prev().Value.(formulaArg).ToNumber()
- per := argsList.Back().Value.(formulaArg).ToNumber()
- if cost.Type != ArgNumber || salvage.Type != ArgNumber || life.Type != ArgNumber || per.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if life.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "SYD requires life argument to be > 0")
- }
- if per.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "SYD requires per argument to be > 0")
- }
- if per.Number > life.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(((cost.Number - salvage.Number) * (life.Number - per.Number + 1) * 2) / (life.Number * (life.Number + 1)))
- }
- // TBILLEQ function calculates the bond-equivalent yield for a Treasury Bill.
- // The syntax of the function is:
- //
- // TBILLEQ(settlement,maturity,discount)
- func (fn *formulaFuncs) TBILLEQ(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "TBILLEQ requires 3 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- dsm := maturity.Number - settlement.Number
- if dsm > 365 || maturity.Number <= settlement.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- discount := argsList.Back().Value.(formulaArg).ToNumber()
- if discount.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if discount.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg((365 * discount.Number) / (360 - discount.Number*dsm))
- }
- // TBILLPRICE function returns the price, per $100 face value, of a Treasury
- // Bill. The syntax of the function is:
- //
- // TBILLPRICE(settlement,maturity,discount)
- func (fn *formulaFuncs) TBILLPRICE(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "TBILLPRICE requires 3 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- dsm := maturity.Number - settlement.Number
- if dsm > 365 || maturity.Number <= settlement.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- discount := argsList.Back().Value.(formulaArg).ToNumber()
- if discount.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if discount.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(100 * (1 - discount.Number*dsm/360))
- }
- // TBILLYIELD function calculates the yield of a Treasury Bill. The syntax of
- // the function is:
- //
- // TBILLYIELD(settlement,maturity,pr)
- func (fn *formulaFuncs) TBILLYIELD(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "TBILLYIELD requires 3 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- dsm := maturity.Number - settlement.Number
- if dsm > 365 || maturity.Number <= settlement.Number {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- pr := argsList.Back().Value.(formulaArg).ToNumber()
- if pr.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if pr.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(((100 - pr.Number) / pr.Number) * (360 / dsm))
- }
- // prepareVdbArgs checking and prepare arguments for the formula function
- // VDB.
- func (fn *formulaFuncs) prepareVdbArgs(argsList *list.List) formulaArg {
- cost := argsList.Front().Value.(formulaArg).ToNumber()
- if cost.Type != ArgNumber {
- return cost
- }
- if cost.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "VDB requires cost >= 0")
- }
- salvage := argsList.Front().Next().Value.(formulaArg).ToNumber()
- if salvage.Type != ArgNumber {
- return salvage
- }
- if salvage.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "VDB requires salvage >= 0")
- }
- life := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if life.Type != ArgNumber {
- return life
- }
- if life.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "VDB requires life > 0")
- }
- startPeriod := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if startPeriod.Type != ArgNumber {
- return startPeriod
- }
- if startPeriod.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "VDB requires start_period > 0")
- }
- endPeriod := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if endPeriod.Type != ArgNumber {
- return endPeriod
- }
- if startPeriod.Number > endPeriod.Number {
- return newErrorFormulaArg(formulaErrorNUM, "VDB requires start_period <= end_period")
- }
- if endPeriod.Number > life.Number {
- return newErrorFormulaArg(formulaErrorNUM, "VDB requires end_period <= life")
- }
- factor := newNumberFormulaArg(2)
- if argsList.Len() > 5 {
- if factor = argsList.Front().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber(); factor.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if factor.Number < 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "VDB requires factor >= 0")
- }
- }
- return newListFormulaArg([]formulaArg{cost, salvage, life, startPeriod, endPeriod, factor})
- }
- // vdb is a part of implementation of the formula function VDB.
- func (fn *formulaFuncs) vdb(cost, salvage, life, life1, period, factor formulaArg) formulaArg {
- var ddb, vdb, sln, term float64
- endInt, cs, nowSln := math.Ceil(period.Number), cost.Number-salvage.Number, false
- ddbArgs := list.New()
- for i := 1.0; i <= endInt; i++ {
- if !nowSln {
- ddbArgs.Init()
- ddbArgs.PushBack(cost)
- ddbArgs.PushBack(salvage)
- ddbArgs.PushBack(life)
- ddbArgs.PushBack(newNumberFormulaArg(i))
- ddbArgs.PushBack(factor)
- ddb = fn.DDB(ddbArgs).Number
- sln = cs / (life1.Number - i + 1)
- if sln > ddb {
- term = sln
- nowSln = true
- } else {
- term = ddb
- cs -= ddb
- }
- } else {
- term = sln
- }
- if i == endInt {
- term *= period.Number + 1 - endInt
- }
- vdb += term
- }
- return newNumberFormulaArg(vdb)
- }
- // VDB function calculates the depreciation of an asset, using the Double
- // Declining Balance Method, or another specified depreciation rate, for a
- // specified period (including partial periods). The syntax of the function
- // is:
- //
- // VDB(cost,salvage,life,start_period,end_period,[factor],[no_switch])
- func (fn *formulaFuncs) VDB(argsList *list.List) formulaArg {
- if argsList.Len() < 5 || argsList.Len() > 7 {
- return newErrorFormulaArg(formulaErrorVALUE, "VDB requires 5 or 7 arguments")
- }
- args := fn.prepareVdbArgs(argsList)
- if args.Type != ArgList {
- return args
- }
- cost, salvage, life, startPeriod, endPeriod, factor := args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5]
- noSwitch := newBoolFormulaArg(false)
- if argsList.Len() > 6 {
- if noSwitch = argsList.Back().Value.(formulaArg).ToBool(); noSwitch.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- startInt, endInt, vdb, ddbArgs := math.Floor(startPeriod.Number), math.Ceil(endPeriod.Number), newNumberFormulaArg(0), list.New()
- if noSwitch.Number == 1 {
- for i := startInt + 1; i <= endInt; i++ {
- ddbArgs.Init()
- ddbArgs.PushBack(cost)
- ddbArgs.PushBack(salvage)
- ddbArgs.PushBack(life)
- ddbArgs.PushBack(newNumberFormulaArg(i))
- ddbArgs.PushBack(factor)
- term := fn.DDB(ddbArgs)
- if i == startInt+1 {
- term.Number *= math.Min(endPeriod.Number, startInt+1) - startPeriod.Number
- } else if i == endInt {
- term.Number *= endPeriod.Number + 1 - endInt
- }
- vdb.Number += term.Number
- }
- return vdb
- }
- life1, part := life, 0.0
- if startPeriod.Number != math.Floor(startPeriod.Number) && factor.Number > 1.0 && startPeriod.Number >= life.Number/2.0 {
- part = startPeriod.Number - life.Number/2.0
- startPeriod.Number = life.Number / 2.0
- endPeriod.Number -= part
- }
- cost.Number -= fn.vdb(cost, salvage, life, life1, startPeriod, factor).Number
- return fn.vdb(cost, salvage, life, newNumberFormulaArg(life.Number-startPeriod.Number), newNumberFormulaArg(endPeriod.Number-startPeriod.Number), factor)
- }
- // prepareXArgs prepare arguments for the formula function XIRR and XNPV.
- func (fn *formulaFuncs) prepareXArgs(values, dates formulaArg) (valuesArg, datesArg []float64, err formulaArg) {
- for _, arg := range values.ToList() {
- if numArg := arg.ToNumber(); numArg.Type == ArgNumber {
- valuesArg = append(valuesArg, numArg.Number)
- continue
- }
- err = newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- return
- }
- if len(valuesArg) < 2 {
- err = newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- return
- }
- args, date := list.New(), 0.0
- for _, arg := range dates.ToList() {
- args.Init()
- args.PushBack(arg)
- dateValue := fn.DATEVALUE(args)
- if dateValue.Type != ArgNumber {
- err = newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- return
- }
- if dateValue.Number < date {
- err = newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- return
- }
- datesArg = append(datesArg, dateValue.Number)
- date = dateValue.Number
- }
- if len(valuesArg) != len(datesArg) {
- err = newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- return
- }
- err = newEmptyFormulaArg()
- return
- }
- // xirr is an implementation of the formula function XIRR.
- func (fn *formulaFuncs) xirr(values, dates []float64, guess float64) formulaArg {
- positive, negative := false, false
- for i := 0; i < len(values); i++ {
- if values[i] > 0 {
- positive = true
- }
- if values[i] < 0 {
- negative = true
- }
- }
- if !positive || !negative {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- result, epsMax, count, maxIterate, err := guess, 1e-10, 0, 50, false
- for {
- resultValue := xirrPart1(values, dates, result)
- newRate := result - resultValue/xirrPart2(values, dates, result)
- epsRate := math.Abs(newRate - result)
- result = newRate
- count++
- if epsRate <= epsMax || math.Abs(resultValue) <= epsMax {
- break
- }
- if count > maxIterate {
- err = true
- break
- }
- }
- if err || math.IsNaN(result) || math.IsInf(result, 0) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- return newNumberFormulaArg(result)
- }
- // xirrPart1 is a part of implementation of the formula function XIRR.
- func xirrPart1(values, dates []float64, rate float64) float64 {
- r := rate + 1
- result := values[0]
- vlen := len(values)
- firstDate := dates[0]
- for i := 1; i < vlen; i++ {
- result += values[i] / math.Pow(r, (dates[i]-firstDate)/365)
- }
- return result
- }
- // xirrPart2 is a part of implementation of the formula function XIRR.
- func xirrPart2(values, dates []float64, rate float64) float64 {
- r := rate + 1
- result := 0.0
- vlen := len(values)
- firstDate := dates[0]
- for i := 1; i < vlen; i++ {
- frac := (dates[i] - firstDate) / 365
- result -= frac * values[i] / math.Pow(r, frac+1)
- }
- return result
- }
- // XIRR function returns the Internal Rate of Return for a supplied series of
- // cash flows (i.e. a set of values, which includes an initial investment
- // value and a series of net income values) occurring at a series of supplied
- // dates. The syntax of the function is:
- //
- // XIRR(values,dates,[guess])
- func (fn *formulaFuncs) XIRR(argsList *list.List) formulaArg {
- if argsList.Len() != 2 && argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "XIRR requires 2 or 3 arguments")
- }
- values, dates, err := fn.prepareXArgs(argsList.Front().Value.(formulaArg), argsList.Front().Next().Value.(formulaArg))
- if err.Type != ArgEmpty {
- return err
- }
- guess := newNumberFormulaArg(0)
- if argsList.Len() == 3 {
- if guess = argsList.Back().Value.(formulaArg).ToNumber(); guess.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- if guess.Number <= -1 {
- return newErrorFormulaArg(formulaErrorVALUE, "XIRR requires guess > -1")
- }
- }
- return fn.xirr(values, dates, guess.Number)
- }
- // XNPV function calculates the Net Present Value for a schedule of cash flows
- // that is not necessarily periodic. The syntax of the function is:
- //
- // XNPV(rate,values,dates)
- func (fn *formulaFuncs) XNPV(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "XNPV requires 3 arguments")
- }
- rate := argsList.Front().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- if rate.Number <= 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "XNPV requires rate > 0")
- }
- values, dates, err := fn.prepareXArgs(argsList.Front().Next().Value.(formulaArg), argsList.Back().Value.(formulaArg))
- if err.Type != ArgEmpty {
- return err
- }
- date1, xnpv := dates[0], 0.0
- for idx, value := range values {
- xnpv += value / math.Pow(1+rate.Number, (dates[idx]-date1)/365)
- }
- return newNumberFormulaArg(xnpv)
- }
- // yield is an implementation of the formula function YIELD.
- func (fn *formulaFuncs) yield(settlement, maturity, rate, pr, redemption, frequency, basis formulaArg) formulaArg {
- priceN, yield1, yield2 := newNumberFormulaArg(0), newNumberFormulaArg(0), newNumberFormulaArg(1)
- price1 := fn.price(settlement, maturity, rate, yield1, redemption, frequency, basis)
- if price1.Type != ArgNumber {
- return price1
- }
- price2 := fn.price(settlement, maturity, rate, yield2, redemption, frequency, basis)
- yieldN := newNumberFormulaArg((yield2.Number - yield1.Number) * 0.5)
- for iter := 0; iter < 100 && priceN.Number != pr.Number; iter++ {
- priceN = fn.price(settlement, maturity, rate, yieldN, redemption, frequency, basis)
- if pr.Number == price1.Number {
- return yield1
- } else if pr.Number == price2.Number {
- return yield2
- } else if pr.Number == priceN.Number {
- return yieldN
- } else if pr.Number < price2.Number {
- yield2.Number *= 2.0
- price2 = fn.price(settlement, maturity, rate, yield2, redemption, frequency, basis)
- yieldN.Number = (yield2.Number - yield1.Number) * 0.5
- } else {
- if pr.Number < priceN.Number {
- yield1 = yieldN
- price1 = priceN
- } else {
- yield2 = yieldN
- price2 = priceN
- }
- f1 := (yield2.Number - yield1.Number) * ((pr.Number - price2.Number) / (price1.Number - price2.Number))
- yieldN.Number = yield2.Number - math.Nextafter(f1, f1)
- }
- }
- return yieldN
- }
- // YIELD function calculates the Yield of a security that pays periodic
- // interest. The syntax of the function is:
- //
- // YIELD(settlement,maturity,rate,pr,redemption,frequency,[basis])
- func (fn *formulaFuncs) YIELD(argsList *list.List) formulaArg {
- if argsList.Len() != 6 && argsList.Len() != 7 {
- return newErrorFormulaArg(formulaErrorVALUE, "YIELD requires 6 or 7 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- rate := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- if rate.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICE requires rate >= 0")
- }
- pr := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if pr.Type != ArgNumber {
- return pr
- }
- if pr.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICE requires pr > 0")
- }
- redemption := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if redemption.Type != ArgNumber {
- return redemption
- }
- if redemption.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "PRICE requires redemption >= 0")
- }
- frequency := argsList.Front().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if frequency.Type != ArgNumber {
- return frequency
- }
- if !validateFrequency(frequency.Number) {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 7 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- return fn.yield(settlement, maturity, rate, pr, redemption, frequency, basis)
- }
- // YIELDDISC function calculates the annual yield of a discounted security.
- // The syntax of the function is:
- //
- // YIELDDISC(settlement,maturity,pr,redemption,[basis])
- func (fn *formulaFuncs) YIELDDISC(argsList *list.List) formulaArg {
- if argsList.Len() != 4 && argsList.Len() != 5 {
- return newErrorFormulaArg(formulaErrorVALUE, "YIELDDISC requires 4 or 5 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- pr := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if pr.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if pr.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "YIELDDISC requires pr > 0")
- }
- redemption := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if redemption.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- if redemption.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "YIELDDISC requires redemption > 0")
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 5 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- frac := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
- if frac.Type != ArgNumber {
- return frac
- }
- return newNumberFormulaArg((redemption.Number/pr.Number - 1) / frac.Number)
- }
- // YIELDMAT function calculates the annual yield of a security that pays
- // interest at maturity. The syntax of the function is:
- //
- // YIELDMAT(settlement,maturity,issue,rate,pr,[basis])
- func (fn *formulaFuncs) YIELDMAT(argsList *list.List) formulaArg {
- if argsList.Len() != 5 && argsList.Len() != 6 {
- return newErrorFormulaArg(formulaErrorVALUE, "YIELDMAT requires 5 or 6 arguments")
- }
- args := fn.prepareDataValueArgs(2, argsList)
- if args.Type != ArgList {
- return args
- }
- settlement, maturity := args.List[0], args.List[1]
- arg := list.New().Init()
- issue := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
- if issue.Type != ArgNumber {
- arg.PushBack(argsList.Front().Next().Next().Value.(formulaArg))
- issue = fn.DATEVALUE(arg)
- if issue.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- }
- if issue.Number >= settlement.Number {
- return newErrorFormulaArg(formulaErrorNUM, "YIELDMAT requires settlement > issue")
- }
- rate := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
- if rate.Type != ArgNumber {
- return rate
- }
- if rate.Number < 0 {
- return newErrorFormulaArg(formulaErrorNUM, "YIELDMAT requires rate >= 0")
- }
- pr := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
- if pr.Type != ArgNumber {
- return pr
- }
- if pr.Number <= 0 {
- return newErrorFormulaArg(formulaErrorNUM, "YIELDMAT requires pr > 0")
- }
- basis := newNumberFormulaArg(0)
- if argsList.Len() == 6 {
- if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- dim := yearFrac(issue.Number, maturity.Number, int(basis.Number))
- if dim.Type != ArgNumber {
- return dim
- }
- dis := yearFrac(issue.Number, settlement.Number, int(basis.Number))
- dsm := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
- f1 := dim.Number * rate.Number
- result := 1 + math.Nextafter(f1, f1)
- result /= pr.Number/100 + dis.Number*rate.Number
- result--
- result /= dsm.Number
- return newNumberFormulaArg(result)
- }
- // Database Functions
- // calcDatabase defines the structure for formula database.
- type calcDatabase struct {
- col, row int
- indexMap map[int]int
- database [][]formulaArg
- criteria [][]formulaArg
- }
- // newCalcDatabase function returns formula database by given data range of
- // cells containing the database, field and criteria range.
- func newCalcDatabase(database, field, criteria formulaArg) *calcDatabase {
- db := calcDatabase{
- indexMap: make(map[int]int),
- database: database.Matrix,
- criteria: criteria.Matrix,
- }
- exp := len(database.Matrix) < 2 || len(database.Matrix[0]) < 1 ||
- len(criteria.Matrix) < 2 || len(criteria.Matrix[0]) < 1
- if field.Type != ArgEmpty {
- if db.col = db.columnIndex(database.Matrix, field); exp || db.col < 0 || len(db.database[0]) <= db.col {
- return nil
- }
- return &db
- }
- if db.col = -1; exp {
- return nil
- }
- return &db
- }
- // columnIndex return index by specifies column field within the database for
- // which user want to return the count of non-blank cells.
- func (db *calcDatabase) columnIndex(database [][]formulaArg, field formulaArg) int {
- num := field.ToNumber()
- if num.Type != ArgNumber && len(database) > 0 {
- for i := 0; i < len(database[0]); i++ {
- if title := database[0][i]; strings.EqualFold(title.Value(), field.Value()) {
- return i
- }
- }
- return -1
- }
- return int(num.Number - 1)
- }
- // criteriaEval evaluate formula criteria expression.
- func (db *calcDatabase) criteriaEval() bool {
- var (
- columns, rows = len(db.criteria[0]), len(db.criteria)
- criteria = db.criteria
- k int
- matched bool
- )
- if len(db.indexMap) == 0 {
- fields := criteria[0]
- for j := 0; j < columns; j++ {
- if k = db.columnIndex(db.database, fields[j]); k < 0 {
- return false
- }
- db.indexMap[j] = k
- }
- }
- for i := 1; !matched && i < rows; i++ {
- matched = true
- for j := 0; matched && j < columns; j++ {
- criteriaExp := db.criteria[i][j].Value()
- if criteriaExp == "" {
- continue
- }
- criteria := formulaCriteriaParser(criteriaExp)
- cell := db.database[db.row][db.indexMap[j]].Value()
- matched, _ = formulaCriteriaEval(cell, criteria)
- }
- }
- return matched
- }
- // value returns the current cell value.
- func (db *calcDatabase) value() formulaArg {
- if db.col == -1 {
- return db.database[db.row][len(db.database[db.row])-1]
- }
- return db.database[db.row][db.col]
- }
- // next will return true if find the matched cell in the database.
- func (db *calcDatabase) next() bool {
- matched, rows := false, len(db.database)
- for !matched && db.row < rows {
- if db.row++; db.row < rows {
- matched = db.criteriaEval()
- }
- }
- return matched
- }
- // database is an implementation of the formula functions DAVERAGE, DMAX and DMIN.
- func (fn *formulaFuncs) database(name string, argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 3 arguments", name))
- }
- database := argsList.Front().Value.(formulaArg)
- field := argsList.Front().Next().Value.(formulaArg)
- criteria := argsList.Back().Value.(formulaArg)
- db := newCalcDatabase(database, field, criteria)
- if db == nil {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args := list.New()
- for db.next() {
- args.PushBack(db.value())
- }
- switch name {
- case "DMAX":
- return fn.MAX(args)
- case "DMIN":
- return fn.MIN(args)
- case "DPRODUCT":
- return fn.PRODUCT(args)
- case "DSTDEV":
- return fn.STDEV(args)
- case "DSTDEVP":
- return fn.STDEVP(args)
- case "DSUM":
- return fn.SUM(args)
- case "DVAR":
- return fn.VAR(args)
- case "DVARP":
- return fn.VARP(args)
- default:
- return fn.AVERAGE(args)
- }
- }
- // DAVERAGE function calculates the average (statistical mean) of values in a
- // field (column) in a database for selected records, that satisfy
- // user-specified criteria. The syntax of the Excel Daverage function is:
- //
- // DAVERAGE(database,field,criteria)
- func (fn *formulaFuncs) DAVERAGE(argsList *list.List) formulaArg {
- return fn.database("DAVERAGE", argsList)
- }
- // dcount is an implementation of the formula functions DCOUNT and DCOUNTA.
- func (fn *formulaFuncs) dcount(name string, argsList *list.List) formulaArg {
- if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 2 arguments", name))
- }
- if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s allows at most 3 arguments", name))
- }
- field := newEmptyFormulaArg()
- criteria := argsList.Back().Value.(formulaArg)
- if argsList.Len() > 2 {
- field = argsList.Front().Next().Value.(formulaArg)
- }
- database := argsList.Front().Value.(formulaArg)
- db := newCalcDatabase(database, field, criteria)
- if db == nil {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- args := list.New()
- for db.next() {
- args.PushBack(db.value())
- }
- if name == "DCOUNT" {
- return fn.COUNT(args)
- }
- return fn.COUNTA(args)
- }
- // DCOUNT function returns the number of cells containing numeric values, in a
- // field (column) of a database for selected records only. The records to be
- // included in the count are those that satisfy a set of one or more
- // user-specified criteria. The syntax of the function is:
- //
- // DCOUNT(database,[field],criteria)
- func (fn *formulaFuncs) DCOUNT(argsList *list.List) formulaArg {
- return fn.dcount("DCOUNT", argsList)
- }
- // DCOUNTA function returns the number of non-blank cells, in a field
- // (column) of a database for selected records only. The records to be
- // included in the count are those that satisfy a set of one or more
- // user-specified criteria. The syntax of the function is:
- //
- // DCOUNTA(database,[field],criteria)
- func (fn *formulaFuncs) DCOUNTA(argsList *list.List) formulaArg {
- return fn.dcount("DCOUNTA", argsList)
- }
- // DGET function returns a single value from a column of a database. The record
- // is selected via a set of one or more user-specified criteria. The syntax of
- // the function is:
- //
- // DGET(database,field,criteria)
- func (fn *formulaFuncs) DGET(argsList *list.List) formulaArg {
- if argsList.Len() != 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "DGET requires 3 arguments")
- }
- database := argsList.Front().Value.(formulaArg)
- field := argsList.Front().Next().Value.(formulaArg)
- criteria := argsList.Back().Value.(formulaArg)
- db := newCalcDatabase(database, field, criteria)
- if db == nil {
- return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- }
- value := newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
- if db.next() {
- if value = db.value(); db.next() {
- return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
- }
- }
- return value
- }
- // DMAX function finds the maximum value in a field (column) in a database for
- // selected records only. The records to be included in the calculation are
- // defined by a set of one or more user-specified criteria. The syntax of the
- // function is:
- //
- // DMAX(database,field,criteria)
- func (fn *formulaFuncs) DMAX(argsList *list.List) formulaArg {
- return fn.database("DMAX", argsList)
- }
- // DMIN function finds the minimum value in a field (column) in a database for
- // selected records only. The records to be included in the calculation are
- // defined by a set of one or more user-specified criteria. The syntax of the
- // function is:
- //
- // DMIN(database,field,criteria)
- func (fn *formulaFuncs) DMIN(argsList *list.List) formulaArg {
- return fn.database("DMIN", argsList)
- }
- // DPRODUCT function calculates the product of a field (column) in a database
- // for selected records, that satisfy user-specified criteria. The syntax of
- // the function is:
- //
- // DPRODUCT(database,field,criteria)
- func (fn *formulaFuncs) DPRODUCT(argsList *list.List) formulaArg {
- return fn.database("DPRODUCT", argsList)
- }
- // DSTDEV function calculates the sample standard deviation of a field
- // (column) in a database for selected records only. The records to be
- // included in the calculation are defined by a set of one or more
- // user-specified criteria. The syntax of the function is:
- //
- // DSTDEV(database,field,criteria)
- func (fn *formulaFuncs) DSTDEV(argsList *list.List) formulaArg {
- return fn.database("DSTDEV", argsList)
- }
- // DSTDEVP function calculates the standard deviation of a field (column) in a
- // database for selected records only. The records to be included in the
- // calculation are defined by a set of one or more user-specified criteria.
- // The syntax of the function is:
- //
- // DSTDEVP(database,field,criteria)
- func (fn *formulaFuncs) DSTDEVP(argsList *list.List) formulaArg {
- return fn.database("DSTDEVP", argsList)
- }
- // DSUM function calculates the sum of a field (column) in a database for
- // selected records, that satisfy user-specified criteria. The syntax of the
- // function is:
- //
- // DSUM(database,field,criteria)
- func (fn *formulaFuncs) DSUM(argsList *list.List) formulaArg {
- return fn.database("DSUM", argsList)
- }
- // DVAR function calculates the sample variance of a field (column) in a
- // database for selected records only. The records to be included in the
- // calculation are defined by a set of one or more user-specified criteria.
- // The syntax of the function is:
- //
- // DVAR(database,field,criteria)
- func (fn *formulaFuncs) DVAR(argsList *list.List) formulaArg {
- return fn.database("DVAR", argsList)
- }
- // DVARP function calculates the variance (for an entire population), of the
- // values in a field (column) in a database for selected records only. The
- // records to be included in the calculation are defined by a set of one or
- // more user-specified criteria. The syntax of the function is:
- //
- // DVARP(database,field,criteria)
- func (fn *formulaFuncs) DVARP(argsList *list.List) formulaArg {
- return fn.database("DVARP", argsList)
- }
|