fmtbcd.pp 124 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2005-2006 by the Free Pascal development team
  4. and Gehard Scholz
  5. It contains the Free Pascal BCD implementation
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS for A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. { "Programming is the time between two bugs" }
  13. { (last words of the unknown programmer) }
  14. (* this program was a good test for the compiler: some bugs have been found.
  15. 1. WITH in inline funcs produces a compiler error AFTER producing an .exe file
  16. (was already known; I didn't see it in the bug list)
  17. 2. macro names were checked for being a keyword, even when starting with
  18. an '_' (produces range check when compiler is compiled with { $r+ }-mode
  19. fixed.
  20. 3. { $define program } was not possible in { $macro on } mode
  21. (keywords not allowed: doesn't make sense here)
  22. fixed.
  23. 4. the Inc/Dec ( unsigned, signed ) problem (has been similar in the
  24. bug list already)
  25. 5. when the result of an overloaded (inline) operator is ABSOLUTEd:
  26. compiler error 200110205
  27. happens only when operator is defined in a unit.
  28. 6. two range check errors in scanner.pas
  29. a) array subscripting
  30. b) value out ouf range
  31. *)
  32. { $define debug_version}
  33. // Dont use s+ (Stack checking on) because it crashes libraries, see bug 21208
  34. {$r+,q+,s-}
  35. {$mode objfpc}
  36. {$h-}
  37. {$inline on}
  38. {$macro on}
  39. {$define BCDMaxDigits := 64 } { should be even }
  40. { the next defines must be defined by hand,
  41. unless someone shows me a way how to to it with macros }
  42. {$define BCDgr4} { define this if MCDMaxDigits is greater 4, else undefine! }
  43. {$define BCDgr9} { define this if MCDMaxDigits is greater 9, else undefine! }
  44. {$define BCDgr18} { define this if MCDMaxDigits is greater 18, else undefine! }
  45. { $define BCDgr64} { define this if MCDMaxDigits is greater 64, else undefine! }
  46. { $define BCDgr180} { define this if MCDMaxDigits is greater 180, else undefine! }
  47. {$ifdef BCDgr4}
  48. {$hint BCD Digits > 4}
  49. {$endif}
  50. {$ifdef BCDgr9}
  51. {$hint BCD Digits > 9}
  52. {$endif}
  53. {$ifdef BCDgr18}
  54. {$hint BCD Digits > 18}
  55. {$endif}
  56. {$ifdef BCDgr64}
  57. {$hint BCD Digits > 64}
  58. {$endif}
  59. {$ifdef BCDgr180}
  60. {$hint BCD Digits > 180}
  61. {$endif}
  62. {$ifndef NO_SMART_LINK}
  63. { $smartlink on}
  64. {$endif}
  65. {$define some_packed} { enable this to keep some local structures PACKED }
  66. { $define as_object} { to define the tBCD record as object instead;
  67. fields then are private }
  68. { not done yet! }
  69. {$define additional_routines} { to create additional routines and operators }
  70. (* only define one of them! *)
  71. { $define integ32}
  72. {$define integ64}
  73. (* only define one of them! *)
  74. { $define real8}
  75. {$define real10}
  76. {check}
  77. {$ifndef integ32}
  78. {$ifndef integ64}
  79. {$define integ64}
  80. {$endif}
  81. {$endif}
  82. {$ifdef integ32}
  83. {$ifdef integ64}
  84. {$undef integ32}
  85. {$endif}
  86. {$endif}
  87. {check}
  88. {$ifndef real8}
  89. {$ifndef real10}
  90. {$define real8}
  91. {$endif}
  92. {$endif}
  93. {$ifdef real8}
  94. {$ifdef real10}
  95. {$undef real10}
  96. {$endif}
  97. {$endif}
  98. {$ifdef some_packed}
  99. {$define maybe_packed := packed}
  100. {$else}
  101. {$define maybe_packed := (**)}
  102. {$endif}
  103. UNIT FmtBCD;
  104. INTERFACE
  105. USES
  106. SysUtils,
  107. Variants;
  108. const
  109. MaxStringDigits = 100; { not used ! }
  110. _NoDecimal = -255; { not used ! }
  111. _DefaultDecimals = 10; { not used ! }
  112. { From DB.pas }
  113. { Max supported by Midas } { must be EVEN }
  114. MaxFmtBCDFractionSize = BCDMaxDigits + Ord ( Odd ( BCDMaxDigits ) );
  115. { Max supported by Midas }
  116. MaxFmtBCDDigits = 32; { not used ! }
  117. DefaultFmtBCDScale = 6; { not used ! }
  118. MaxBCDPrecision = 18; { not used ! }
  119. MaxBCDScale = 4; { not used ! }
  120. {$ifdef BCDgr64}
  121. { $fatal big 1}
  122. {$define bigger_BCD} { must be defined
  123. if MaxFmtBCDFractionSize > 64 }
  124. { not usable in the moment }
  125. {$endif}
  126. {$ifdef BCDgr180}
  127. { $fatal big 2}
  128. type
  129. FmtBCDStringtype = AnsiString;
  130. {$define use_Ansistring}
  131. {$else}
  132. type
  133. FmtBCDStringtype = string [ 255 ];
  134. {$undef use_Ansistring}
  135. {$endif}
  136. {$ifdef use_ansistring}
  137. {$hint ansi}
  138. {$else}
  139. {$hint -ansi}
  140. {$endif}
  141. {$ifdef integ32}
  142. {$define myInttype := LongInt}
  143. {$endif}
  144. {$ifdef integ64}
  145. {$define myInttype := int64}
  146. {$endif}
  147. {$ifndef FPUNONE}
  148. {$ifdef real8}
  149. {$define myRealtype := double}
  150. {$endif}
  151. {$ifdef real10}
  152. {$define myRealtype := extended}
  153. {$endif}
  154. {$endif}
  155. {$ifdef SUPPORT_COMP}
  156. {$define comproutines}
  157. {$endif SUPPORT_COMP}
  158. {$define __low_Fraction := 0 }
  159. {$define __high_Fraction := ( ( MaxFmtBCDFractionSize DIV 2 ) - 1 ) }
  160. type
  161. pBCD = ^ tBCD;
  162. tBCD = packed {$ifdef as_object} OBJECT {$else} record {$endif}
  163. {$ifdef as_object} PRIVATE {$endif}
  164. Precision : 0..maxfmtbcdfractionsize; { 1 (joke?)..64 }
  165. {$ifndef bigger_BCD}
  166. SignSpecialPlaces : Byte; { Sign:1, Special:1, Places:6 }
  167. {$else}
  168. Negativ : Boolean;
  169. {
  170. Special : Boolean;
  171. }
  172. Places : 0..maxfmtbcdfractionsize - 1;
  173. {$endif}
  174. Fraction : packed array [ __low_Fraction..__high_Fraction ] of Byte;
  175. { BCD Nibbles, 00..99 per Byte, high Nibble 1st }
  176. end;
  177. { Exception classes }
  178. type
  179. eBCDException = CLASS ( Exception );
  180. eBCDOverflowException = CLASS ( eBCDException );
  181. eBCDNotImplementedException = CLASS ( eBCDException );
  182. { Utility functions for TBCD access }
  183. function BCDPrecision ( const BCD : tBCD ) : Word; Inline;
  184. function BCDScale ( const BCD : tBCD ) : Word; Inline;
  185. function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline;
  186. { BCD Arithmetic}
  187. procedure BCDNegate ( var BCD : tBCD ); Inline;
  188. { !!!!!!!!!! most routines are intentionally NOT inline !!!!!!!!!! }
  189. { Returns True if successful, False if Int Digits needed to be truncated }
  190. function NormalizeBCD ( const InBCD : tBCD;
  191. var OutBCD : tBCD;
  192. const Precision,
  193. Places : Integer ) : Boolean;
  194. procedure BCDAdd ( const BCDin1,
  195. BCDin2 : tBCD;
  196. var BCDout : tBCD );
  197. procedure BCDSubtract ( const BCDin1,
  198. BCDin2 : tBCD;
  199. var BCDout : tBCD );
  200. procedure BCDMultiply ( const BCDin1,
  201. BCDin2 : tBCD;
  202. var BCDout : tBCD );
  203. {$ifndef FPUNONE}
  204. procedure BCDMultiply ( const BCDIn : tBCD;
  205. const DoubleIn : myRealtype;
  206. var BCDout : tBCD ); Inline;
  207. {$endif}
  208. procedure BCDMultiply ( const BCDIn : tBCD;
  209. const StringIn : FmtBCDStringtype;
  210. var BCDout : tBCD ); Inline;
  211. { !!! params changed to const, shouldn't give a problem }
  212. procedure BCDMultiply ( const StringIn1,
  213. StringIn2 : FmtBCDStringtype;
  214. var BCDout : tBCD ); Inline;
  215. procedure BCDDivide ( const Dividend,
  216. Divisor : tBCD;
  217. var BCDout : tBCD );
  218. {$ifndef FPUNONE}
  219. procedure BCDDivide ( const Dividend : tBCD;
  220. const Divisor : myRealtype;
  221. var BCDout : tBCD ); Inline;
  222. {$endif}
  223. procedure BCDDivide ( const Dividend : tBCD;
  224. const Divisor : FmtBCDStringtype;
  225. var BCDout : tBCD ); Inline;
  226. { !!! params changed to const, shouldn't give a problem }
  227. procedure BCDDivide ( const Dividend,
  228. Divisor : FmtBCDStringtype;
  229. var BCDout : tBCD ); Inline;
  230. { TBCD variant creation utils }
  231. procedure VarFmtBCDCreate ( var aDest : Variant;
  232. const aBCD : tBCD );
  233. function VarFmtBCDCreate : Variant;
  234. function VarFmtBCDCreate ( const aValue : FmtBCDStringtype;
  235. Precision,
  236. Scale : Word ) : Variant;
  237. {$ifndef FPUNONE}
  238. function VarFmtBCDCreate ( const aValue : myRealtype;
  239. Precision : Word = 18;
  240. Scale : Word = 4 ) : Variant;
  241. {$endif}
  242. function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant;
  243. function VarIsFmtBCD ( const aValue : Variant ) : Boolean;
  244. function VarFmtBCD : TVartype;
  245. { Convert string/Double/Integer to BCD struct }
  246. function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD;
  247. function StrToBCD ( const aValue : FmtBCDStringtype;
  248. const Format : TFormatSettings ) : tBCD;
  249. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  250. var BCD : tBCD ) : Boolean;
  251. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  252. var BCD : tBCD;
  253. const Format : TFormatSettings) : Boolean;
  254. {$ifndef FPUNONE}
  255. function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline;
  256. procedure DoubleToBCD ( const aValue : myRealtype;
  257. var BCD : tBCD );
  258. {$endif}
  259. function IntegerToBCD ( const aValue : myInttype ) : tBCD;
  260. function VarToBCD ( const aValue : Variant ) : tBCD;
  261. { From DB.pas }
  262. function CurrToBCD ( const Curr : currency;
  263. var BCD : tBCD;
  264. Precision : Integer = 32;
  265. Decimals : Integer = 4 ) : Boolean;
  266. { Convert BCD struct to string/Double/Integer }
  267. function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype;
  268. function BCDToStr ( const BCD : tBCD;
  269. const Format : TFormatSettings ) : FmtBCDStringtype;
  270. {$ifndef FPUNONE}
  271. function BCDToDouble ( const BCD : tBCD ) : myRealtype;
  272. {$endif}
  273. function BCDToInteger ( const BCD : tBCD;
  274. Truncate : Boolean = False ) : myInttype;
  275. { From DB.pas }
  276. function BCDToCurr ( const BCD : tBCD;
  277. var Curr : currency ) : Boolean;
  278. { Formatting BCD as string }
  279. function BCDToStrF ( const BCD : tBCD;
  280. Format : TFloatFormat;
  281. const Precision,
  282. Digits : Integer ) : FmtBCDStringtype;
  283. function FormatBCD ( const Format : string;
  284. BCD : tBCD ) : FmtBCDStringtype;
  285. { returns -1 if BCD1 < BCD2, 0 if BCD1 = BCD2, 1 if BCD1 > BCD2 }
  286. function BCDCompare ( const BCD1,
  287. BCD2 : tBCD ) : Integer;
  288. {$ifdef additional_routines}
  289. function CurrToBCD ( const Curr : currency ) : tBCD; Inline;
  290. {$ifdef comproutines}
  291. function CompToBCD ( const Curr : Comp ) : tBCD; Inline;
  292. function BCDToComp ( const BCD : tBCD ) : Comp; Inline;
  293. {$endif}
  294. procedure BCDAdd ( const BCDIn : tBCD;
  295. const IntIn : myInttype;
  296. var BCDout : tBCD );
  297. procedure BCDAdd ( const IntIn : myInttype;
  298. const BCDIn : tBCD;
  299. var BCDout : tBCD ); Inline;
  300. {$ifndef FPUNONE}
  301. procedure BCDAdd ( const BCDIn : tBCD;
  302. const DoubleIn : myRealtype;
  303. var BCDout : tBCD ); Inline;
  304. procedure BCDAdd ( const DoubleIn : myRealtype;
  305. const BCDIn : tBCD;
  306. var BCDout : tBCD ); Inline;
  307. {$endif}
  308. procedure BCDAdd ( const BCDIn : tBCD;
  309. const Currin : currency;
  310. var BCDout : tBCD ); Inline;
  311. procedure BCDAdd ( const Currin : currency;
  312. const BCDIn : tBCD;
  313. var BCDout : tBCD ); Inline;
  314. {$ifdef comproutines}
  315. procedure BCDAdd ( const BCDIn : tBCD;
  316. const Compin : Comp;
  317. var BCDout : tBCD ); Inline;
  318. procedure BCDAdd ( const Compin : Comp;
  319. const BCDIn : tBCD;
  320. var BCDout : tBCD ); Inline;
  321. {$endif}
  322. procedure BCDAdd ( const BCDIn : tBCD;
  323. const StringIn : FmtBCDStringtype;
  324. var BCDout : tBCD ); Inline;
  325. procedure BCDAdd ( const StringIn : FmtBCDStringtype;
  326. const BCDIn : tBCD;
  327. var BCDout : tBCD ); Inline;
  328. procedure BCDAdd ( const StringIn1,
  329. StringIn2 : FmtBCDStringtype;
  330. var BCDout : tBCD ); Inline;
  331. procedure BCDSubtract ( const BCDIn : tBCD;
  332. const IntIn : myInttype;
  333. var BCDout : tBCD );
  334. procedure BCDSubtract ( const IntIn : myInttype;
  335. const BCDIn : tBCD;
  336. var BCDout : tBCD ); Inline;
  337. {$ifndef FPUNONE}
  338. procedure BCDSubtract ( const BCDIn : tBCD;
  339. const DoubleIn : myRealtype;
  340. var BCDout : tBCD ); Inline;
  341. procedure BCDSubtract ( const DoubleIn : myRealtype;
  342. const BCDIn : tBCD;
  343. var BCDout : tBCD ); Inline;
  344. {$endif}
  345. procedure BCDSubtract ( const BCDIn : tBCD;
  346. const Currin : currency;
  347. var BCDout : tBCD ); Inline;
  348. procedure BCDSubtract ( const Currin : currency;
  349. const BCDIn : tBCD;
  350. var BCDout : tBCD ); Inline;
  351. {$ifdef comproutines}
  352. procedure BCDSubtract ( const BCDIn : tBCD;
  353. const Compin : Comp;
  354. var BCDout : tBCD ); Inline;
  355. procedure BCDSubtract ( const Compin : Comp;
  356. const BCDIn : tBCD;
  357. var BCDout : tBCD ); Inline;
  358. {$endif}
  359. procedure BCDSubtract ( const BCDIn : tBCD;
  360. const StringIn : FmtBCDStringtype;
  361. var BCDout : tBCD ); Inline;
  362. procedure BCDSubtract ( const StringIn : FmtBCDStringtype;
  363. const BCDIn : tBCD;
  364. var BCDout : tBCD ); Inline;
  365. procedure BCDSubtract ( const StringIn1,
  366. StringIn2 : FmtBCDStringtype;
  367. var BCDout : tBCD ); Inline;
  368. procedure BCDMultiply ( const BCDIn : tBCD;
  369. const IntIn : myInttype;
  370. var BCDout : tBCD );
  371. procedure BCDMultiply ( const IntIn : myInttype;
  372. const BCDIn : tBCD;
  373. var BCDout : tBCD ); Inline;
  374. {$ifndef FPUNONE}
  375. procedure BCDMultiply ( const DoubleIn : myRealtype;
  376. const BCDIn : tBCD;
  377. var BCDout : tBCD ); Inline;
  378. {$endif}
  379. procedure BCDMultiply ( const BCDIn : tBCD;
  380. const Currin : currency;
  381. var BCDout : tBCD ); Inline;
  382. procedure BCDMultiply ( const Currin : currency;
  383. const BCDIn : tBCD;
  384. var BCDout : tBCD ); Inline;
  385. {$ifdef comproutines}
  386. procedure BCDMultiply ( const BCDIn : tBCD;
  387. const Compin : Comp;
  388. var BCDout : tBCD ); Inline;
  389. procedure BCDMultiply ( const Compin : Comp;
  390. const BCDIn : tBCD;
  391. var BCDout : tBCD ); Inline;
  392. {$endif}
  393. procedure BCDMultiply ( const StringIn : FmtBCDStringtype;
  394. const BCDIn : tBCD;
  395. var BCDout : tBCD ); Inline;
  396. procedure BCDDivide ( const Dividend : tBCD;
  397. const Divisor : myInttype;
  398. var BCDout : tBCD ); Inline;
  399. procedure BCDDivide ( const Dividend : myInttype;
  400. const Divisor : tBCD;
  401. var BCDout : tBCD ); Inline;
  402. {$ifndef FPUNONE}
  403. procedure BCDDivide ( const Dividend : myRealtype;
  404. const Divisor : tBCD;
  405. var BCDout : tBCD ); Inline;
  406. {$endif}
  407. procedure BCDDivide ( const BCDIn : tBCD;
  408. const Currin : currency;
  409. var BCDout : tBCD ); Inline;
  410. procedure BCDDivide ( const Currin : currency;
  411. const BCDIn : tBCD;
  412. var BCDout : tBCD ); Inline;
  413. {$ifdef comproutines}
  414. procedure BCDDivide ( const BCDIn : tBCD;
  415. const Compin : Comp;
  416. var BCDout : tBCD ); Inline;
  417. procedure BCDDivide ( const Compin : Comp;
  418. const BCDIn : tBCD;
  419. var BCDout : tBCD ); Inline;
  420. {$endif}
  421. procedure BCDDivide ( const Dividend : FmtBCDStringtype;
  422. const Divisor : tBCD;
  423. var BCDout : tBCD ); Inline;
  424. operator = ( const BCD1,
  425. BCD2 : tBCD ) z : Boolean; Inline;
  426. operator < ( const BCD1,
  427. BCD2 : tBCD ) z : Boolean; Inline;
  428. operator > ( const BCD1,
  429. BCD2 : tBCD ) z : Boolean; Inline;
  430. operator <= ( const BCD1,
  431. BCD2 : tBCD ) z : Boolean; Inline;
  432. operator >= ( const BCD1,
  433. BCD2 : tBCD ) z : Boolean; Inline;
  434. (* ######################## not allowed: why?
  435. operator + ( const BCD : tBCD ) z : tBCD; make_Inline
  436. ##################################################### *)
  437. operator - ( const BCD : tBCD ) z : tBCD; Inline;
  438. operator + ( const BCD1,
  439. BCD2 : tBCD ) z : tBCD; Inline;
  440. operator + ( const BCD : tBCD;
  441. const i : myInttype ) z : tBCD; Inline;
  442. operator + ( const i : myInttype;
  443. const BCD : tBCD ) z : tBCD; Inline;
  444. {$ifndef FPUNONE}
  445. operator + ( const BCD : tBCD;
  446. const r : myRealtype ) z : tBCD; Inline;
  447. operator + ( const r : myRealtype;
  448. const BCD : tBCD ) z : tBCD; Inline;
  449. {$endif}
  450. operator + ( const BCD : tBCD;
  451. const c : currency ) z : tBCD; Inline;
  452. operator + ( const c : currency;
  453. const BCD : tBCD ) z : tBCD; Inline;
  454. {$ifdef comproutines}
  455. operator + ( const BCD : tBCD;
  456. const c : Comp ) z : tBCD; Inline;
  457. operator + ( const c : Comp;
  458. const BCD : tBCD ) z : tBCD; Inline;
  459. {$endif}
  460. operator + ( const BCD : tBCD;
  461. const s : FmtBCDStringtype ) z : tBCD; Inline;
  462. operator + ( const s : FmtBCDStringtype;
  463. const BCD : tBCD ) z : tBCD; Inline;
  464. operator - ( const BCD1,
  465. BCD2 : tBCD ) z : tBCD; Inline;
  466. operator - ( const BCD : tBCD;
  467. const i : myInttype ) z : tBCD; Inline;
  468. operator - ( const i : myInttype;
  469. const BCD : tBCD ) z : tBCD; Inline;
  470. {$ifndef FPUNONE}
  471. operator - ( const BCD : tBCD;
  472. const r : myRealtype ) z : tBCD; Inline;
  473. operator - ( const r : myRealtype;
  474. const BCD : tBCD ) z : tBCD; Inline;
  475. {$endif}
  476. operator - ( const BCD : tBCD;
  477. const c : currency ) z : tBCD; Inline;
  478. operator - ( const c : currency;
  479. const BCD : tBCD ) z : tBCD; Inline;
  480. {$ifdef comproutines}
  481. operator - ( const BCD : tBCD;
  482. const c : Comp ) z : tBCD; Inline;
  483. operator - ( const c : Comp;
  484. const BCD : tBCD ) z : tBCD; Inline;
  485. {$endif}
  486. operator - ( const BCD : tBCD;
  487. const s : FmtBCDStringtype ) z : tBCD; Inline;
  488. operator - ( const s : FmtBCDStringtype;
  489. const BCD : tBCD ) z : tBCD; Inline;
  490. operator * ( const BCD1,
  491. BCD2 : tBCD ) z : tBCD; Inline;
  492. operator * ( const BCD : tBCD;
  493. const i : myInttype ) z : tBCD; Inline;
  494. operator * ( const i : myInttype;
  495. const BCD : tBCD ) z : tBCD; Inline;
  496. {$ifndef FPUNONE}
  497. operator * ( const BCD : tBCD;
  498. const r : myRealtype ) z : tBCD; Inline;
  499. operator * ( const r : myRealtype;
  500. const BCD : tBCD ) z : tBCD; Inline;
  501. {$endif}
  502. operator * ( const BCD : tBCD;
  503. const c : currency ) z : tBCD; Inline;
  504. operator * ( const c : currency;
  505. const BCD : tBCD ) z : tBCD; Inline;
  506. {$ifdef comproutines}
  507. operator * ( const BCD : tBCD;
  508. const c : Comp ) z : tBCD; Inline;
  509. operator * ( const c : Comp;
  510. const BCD : tBCD ) z : tBCD; Inline;
  511. {$endif}
  512. operator * ( const BCD : tBCD;
  513. const s : FmtBCDStringtype ) z : tBCD; Inline;
  514. operator * ( const s : FmtBCDStringtype;
  515. const BCD : tBCD ) z : tBCD; Inline;
  516. operator / ( const BCD1,
  517. BCD2 : tBCD ) z : tBCD; Inline;
  518. operator / ( const BCD : tBCD;
  519. const i : myInttype ) z : tBCD; Inline;
  520. operator / ( const i : myInttype;
  521. const BCD : tBCD ) z : tBCD; Inline;
  522. {$ifndef FPUNONE}
  523. operator / ( const BCD : tBCD;
  524. const r : myRealtype ) z : tBCD; Inline;
  525. operator / ( const r : myRealtype;
  526. const BCD : tBCD ) z : tBCD; Inline;
  527. {$endif}
  528. operator / ( const BCD : tBCD;
  529. const c : currency ) z : tBCD; Inline;
  530. operator / ( const c : currency;
  531. const BCD : tBCD ) z : tBCD; Inline;
  532. {$ifdef comproutines}
  533. operator / ( const BCD : tBCD;
  534. const c : Comp ) z : tBCD; Inline;
  535. operator / ( const c : Comp;
  536. const BCD : tBCD ) z : tBCD; Inline;
  537. {$endif}
  538. operator / ( const BCD : tBCD;
  539. const s : FmtBCDStringtype ) z : tBCD; Inline;
  540. operator / ( const s : FmtBCDStringtype;
  541. const BCD : tBCD ) z : tBCD; Inline;
  542. operator := ( const i : Byte ) z : tBCD; Inline;
  543. operator := ( const BCD : tBCD ) z : Byte; Inline;
  544. operator := ( const i : Word ) z : tBCD; Inline;
  545. operator := ( const BCD : tBCD ) z : Word; Inline;
  546. operator := ( const i : longword ) z : tBCD; Inline;
  547. operator := ( const BCD : tBCD ) z : longword; Inline;
  548. {$if declared ( qword ) }
  549. operator := ( const i : qword ) z : tBCD; Inline;
  550. operator := ( const BCD : tBCD ) z : qword; Inline;
  551. {$endif}
  552. operator := ( const i : ShortInt ) z : tBCD; Inline;
  553. operator := ( const BCD : tBCD ) z : ShortInt; Inline;
  554. operator := ( const i : smallint ) z : tBCD; Inline;
  555. operator := ( const BCD : tBCD ) z : smallint; Inline;
  556. operator := ( const i : LongInt ) z : tBCD; Inline;
  557. operator := ( const BCD : tBCD ) z : LongInt; Inline;
  558. {$if declared ( int64 ) }
  559. operator := ( const i : int64 ) z : tBCD; Inline;
  560. operator := ( const BCD : tBCD ) z : int64; Inline;
  561. {$endif}
  562. {$ifndef FPUNONE}
  563. operator := ( const r : Single ) z : tBCD; Inline;
  564. operator := ( const BCD : tBCD ) z : Single; Inline;
  565. operator := ( const r : Double ) z : tBCD; Inline;
  566. operator := ( const BCD : tBCD ) z : Double; Inline;
  567. {$if sizeof ( extended ) <> sizeof ( double )}
  568. operator := ( const r : Extended ) z : tBCD; Inline;
  569. operator := ( const BCD : tBCD ) z : Extended; Inline;
  570. {$endif}
  571. {$endif}
  572. operator := ( const c : currency ) z : tBCD; Inline;
  573. operator := ( const BCD : tBCD ) z : currency; Inline;
  574. {$ifdef comproutines}
  575. operator := ( const c : Comp ) z : tBCD; Inline;
  576. operator := ( const BCD : tBCD ) z : Comp; Inline;
  577. {$endif}
  578. operator := ( const s : string ) z : tBCD; Inline;
  579. operator := ( const BCD : tBCD ) z : string; Inline;
  580. operator := ( const s : AnsiString ) z : tBCD; Inline;
  581. operator := ( const BCD : tBCD ) z : AnsiString; Inline;
  582. {$endif}
  583. function __get_null : tBCD; Inline;
  584. function __get_zero : tBCD; Inline;
  585. function __get_one : tBCD; Inline;
  586. PROPERTY
  587. NullBCD : tBCD Read __get_null;
  588. ZeroBCD : tBCD Read __get_zero;
  589. OneBCD : tBCD Read __get_one;
  590. //{$define __lo_bh := 1 * ( -( MaxFmtBCDFractionSize * 1 + 2 ) ) }
  591. //{$define __hi_bh := 1 * ( MaxFmtBCDFractionSize * 1 + 1 ) }
  592. {$define helper_declarations :=
  593. const
  594. __lo_bh = -( MaxFmtBCDFractionSize + 2 );
  595. __hi_bh = ( MaxFmtBCDFractionSize + 1 );
  596. type
  597. tBCD_helper = Maybe_Packed record
  598. Prec : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif};
  599. Plac : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif};
  600. FDig,
  601. LDig : {$ifopt r+} __lo_bh..__hi_bh {$else} Integer {$endif};
  602. Singles : Maybe_packed array [ __lo_bh..__hi_bh ]
  603. of {$ifopt r+} 0..9 {$else} Byte {$endif};
  604. Neg : Boolean;
  605. end;
  606. { in the tBCD_helper the bcd is stored for computations,
  607. shifted to the right position }
  608. // {$define __lo_bhb := 1 * ( __lo_bh + __lo_bh ) }
  609. // {$define __hi_bhb := 1 * ( __hi_bh + __hi_bh + 1 ) }
  610. const
  611. __lo_bhb = __lo_bh + __lo_bh - 1;
  612. __hi_bhb = __hi_bh + __hi_bh;
  613. type
  614. tBCD_helper_big = Maybe_Packed record
  615. Prec : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif};
  616. Plac : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif};
  617. FDig,
  618. LDig : {$ifopt r+} __lo_bhb..__hi_bhb {$else} Integer {$endif};
  619. Singles : Maybe_packed array [ __lo_bhb..__hi_bhb ]
  620. of {$ifopt r+} 0 * 0..9 * 9 * Pred ( MaxFmtBCDDigits ) {$else} Integer {$endif};
  621. Neg : Boolean;
  622. end;
  623. }
  624. {$ifdef debug_version}
  625. helper_declarations
  626. procedure unpack_BCD ( const BCD : tBCD;
  627. var bh : tBCD_helper );
  628. function pack_BCD ( var bh : tBCD_helper;
  629. var BCD : tBCD ) : Boolean;
  630. procedure dumpBCD ( const v : tBCD );
  631. {$endif}
  632. IMPLEMENTATION
  633. USES
  634. classes {$ifopt r+}, sysconst {$endif};
  635. type
  636. TFMTBcdFactory = CLASS(TPublishableVarianttype)
  637. PROTECTED
  638. function GetInstance(const v : TVarData): tObject; OVERRIDE;
  639. PUBLIC
  640. function LeftPromotion(const V: TVarData; const Operation: TVarOp; out RequiredVarType: TVarType): Boolean; override;
  641. procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp); override;
  642. procedure Clear(var V: TVarData); override;
  643. procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
  644. function CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean; override;
  645. procedure Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); override;
  646. procedure Cast(var Dest: TVarData; const Source: TVarData); override;
  647. procedure CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); override;
  648. end;
  649. TFMTBcdVarData = CLASS(TPersistent)
  650. PRIVATE
  651. FBcd : tBCD;
  652. PUBLIC
  653. constructor create;
  654. constructor create(const BCD : tBCD);
  655. PROPERTY BCD : tBCD Read FBcd Write FBcd;
  656. end;
  657. var
  658. NullBCD_ : tBCD;
  659. OneBCD_ : tBCD;
  660. function __get_null : tBCD; Inline;
  661. begin
  662. __get_null := NullBCD_;
  663. end;
  664. function __get_zero : tBCD; Inline;
  665. begin
  666. __get_zero := NullBCD_;
  667. __get_zero.Precision := 1;
  668. end;
  669. function __get_one : tBCD; Inline;
  670. begin
  671. __get_one := OneBCD_;
  672. end;
  673. type
  674. range_digits = 1..maxfmtbcdfractionsize;
  675. range_digits0 = 0..maxfmtbcdfractionsize;
  676. range_fracdigits = 0..pred ( MaxFmtBCDFractionSize );
  677. {$ifopt r+}
  678. procedure RangeError;
  679. begin
  680. raise ERangeError.Create(SRangeError);
  681. end;
  682. {$endif}
  683. {$ifndef debug_version}
  684. helper_declarations
  685. {$endif}
  686. var
  687. null_ : record
  688. case Boolean of
  689. False: ( bh : tBCD_helper );
  690. True: ( bhb : tBCD_helper_big );
  691. end;
  692. FMTBcdFactory : TFMTBcdFactory = NIL;
  693. {$ifndef bigger_BCD}
  694. const
  695. NegBit = 1 SHL 7;
  696. SpecialBit = 1 SHL 6;
  697. PlacesMask = $ff XOR ( NegBit OR SpecialBit );
  698. {$endif}
  699. {$define _select := {$define _when := if {$define _when := end else if } }
  700. {$define _then := then begin }
  701. {$define _whenother := end else begin }
  702. {$define _endselect := end } }
  703. {$ifdef debug_version}
  704. procedure dumpBCD ( const v : tBCD );
  705. var
  706. i,
  707. j : Integer;
  708. const
  709. ft : ARRAY [ Boolean ] of Char = ( 'f', 't' );
  710. begin
  711. {$ifndef bigger_BCD}
  712. Write ( 'Prec:', v.Precision, ' ',
  713. 'Neg:', ft[( v.SignSpecialPlaces AND NegBit ) <> 0], ' ',
  714. 'Special:', ft[( v.SignSpecialPlaces AND SpecialBit ) <> 0], ' ',
  715. 'Places:', v.SignSpecialPlaces AND PlacesMask, ' ' );
  716. {$else}
  717. Write ( 'Prec:', v.Precision, ' ',
  718. 'Neg:', ft[v.Negativ], ' ',
  719. 'Places:', v.Places, ' ' );
  720. {$endif}
  721. j := 0;
  722. for i := 1 TO v.Precision do
  723. if Odd ( i )
  724. then Write ( ( v.Fraction[j] AND $f0 ) SHR 4 )
  725. else begin
  726. Write ( v.Fraction[j] AND $0f );
  727. Inc ( j );
  728. end;
  729. WriteLn;
  730. end;
  731. procedure dumpbh ( const v : tBCD_helper );
  732. var
  733. i : Integer;
  734. const
  735. ft : ARRAY [ Boolean ] of Char = ( 'f', 't' );
  736. begin
  737. Write ( 'Prec:', v.Prec, ' ',
  738. 'Neg:', ft[v.Neg], ' ',
  739. 'Places:', v.Plac, ' ',
  740. 'FDig:', v.FDig, ' ',
  741. 'LDig:', v.LDig, ' ',
  742. 'Digits:', v.LDig - v.FDig + 1, ' ' );
  743. for i := v.FDig TO v.LDig do
  744. Write ( v.Singles[i] );
  745. WriteLn;
  746. end;
  747. {$endif}
  748. {$if sizeof ( integer ) = 2 }
  749. {$ifdef BCDgr4 }
  750. var
  751. myMinIntBCD : tBCD;
  752. {$endif}
  753. {$else}
  754. {$if sizeof ( integer ) = 4 }
  755. {$ifdef BCDgr9 }
  756. var
  757. myMinIntBCD : tBCD;
  758. {$endif}
  759. {$else}
  760. {$if sizeof ( integer ) = 8 }
  761. {$ifdef BCDgr18 }
  762. var
  763. myMinIntBCD : tBCD;
  764. {$endif}
  765. {$else}
  766. {$fatal You have an interesting integer type! Sorry, not supported}
  767. {$endif}
  768. {$endif}
  769. {$endif}
  770. procedure not_implemented;
  771. begin
  772. RAISE eBCDNotImplementedException.create ( 'not implemented' );
  773. end;
  774. procedure unpack_BCD ( const BCD : tBCD;
  775. var bh : tBCD_helper );
  776. var
  777. i : {$ifopt r+} __lo_bh + 1 ..__hi_bh {$else} Integer {$endif};
  778. j : {$ifopt r+} __low_fraction..__high_fraction+1 {$else} Integer {$endif};
  779. vv : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  780. begin
  781. bh := null_.bh;
  782. WITH bh,
  783. BCD do
  784. begin
  785. Prec := Precision;
  786. if Prec > 0
  787. then begin
  788. {$ifndef bigger_BCD}
  789. Plac := SignSpecialPlaces AND PlacesMask;
  790. Neg := ( SignSpecialPlaces AND NegBit ) <> 0;
  791. {$else}
  792. Plac := Places;
  793. Neg := Negativ;
  794. {$endif}
  795. LDig := Plac;
  796. FDig := LDig - Prec + 1;
  797. j := 0;
  798. i := FDig;
  799. while i <= LDig do
  800. begin
  801. vv := Fraction[j];
  802. Singles[i] := ( vv {AND $f0} ) SHR 4;
  803. if i < LDig
  804. then Singles[i+1] := vv AND $0f;
  805. Inc ( j );
  806. Inc ( i, 2 );
  807. end;
  808. end;
  809. end;
  810. end;
  811. function pack_BCD ( var bh : tBCD_helper;
  812. var BCD : tBCD ) : Boolean;
  813. { return TRUE if successful (BCD valid) }
  814. var
  815. pre : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 {$else} Integer {$endif};
  816. fra : {$ifopt r+} -1 * ( __hi_bh - __lo_bh + 1 )..__hi_bh - __lo_bh + 1 {$else} Integer {$endif};
  817. tm : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 - Pred ( MaxFmtBCDFractionSize ) {$else} Integer {$endif};
  818. i : {$ifopt r+} low ( bh.FDig ) - 1..high ( bh.LDig ) {$else} Integer {$endif};
  819. rp : {$ifopt r+} low ( BCD.Fraction )..high ( BCD.Fraction ) + 1 {$else} Integer {$endif};
  820. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  821. v : {$ifopt r+} 0..10 {$else} Integer {$endif};
  822. lnz : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  823. doround,
  824. lnzf : Boolean;
  825. begin
  826. pack_BCD := False;
  827. BCD := NullBCD;
  828. WITH BCD,
  829. bh do
  830. begin
  831. lnzf := FDig <= 0;
  832. while lnzf do // skip leading 0
  833. if Singles[FDig] = 0
  834. then begin
  835. Inc ( FDig );
  836. if FDig > 0
  837. then lnzf := False;
  838. end
  839. else lnzf := False;
  840. if FDig > 1 then FDig := 1;
  841. pre := LDig - FDig + 1;
  842. fra := Plac;
  843. doround := False;
  844. if fra >= MaxFmtBCDFractionSize
  845. then begin
  846. doround := True;
  847. tm := fra - Pred ( MaxFmtBCDFractionSize );
  848. { dec ( pre, tm ); Dec/Inc error? }
  849. pre := pre - tm;
  850. { Dec ( fra, tm ); Dec/Inc error? }
  851. fra := fra - tm;
  852. { Dec ( LDig, tm ); Dec/Inc error? }
  853. LDig := LDig - tm;
  854. end;
  855. if pre > MaxFmtBCDFractionSize
  856. then begin
  857. doround := True;
  858. tm := pre - MaxFmtBCDFractionSize;
  859. { Dec ( pre, tm ); Dec/Inc error? }
  860. pre := pre - tm;
  861. { Dec ( fra, tm ); Dec/Inc error? }
  862. fra := fra - tm;
  863. { Dec ( LDig, tm ); Dec/Inc error? }
  864. LDig := LDig - tm;
  865. end;
  866. if fra < 0
  867. then EXIT;
  868. if doround
  869. then begin
  870. v := Singles[fra + 1];
  871. if v > 4
  872. then begin
  873. ue := 1;
  874. i := LDig;
  875. while ( i >= FDig ) AND ( ue <> 0 ) do
  876. begin
  877. v := Singles[i] + ue;
  878. ue := v DIV 10;
  879. Singles[i] := v MOD 10;
  880. Dec ( i );
  881. end;
  882. if ue <> 0
  883. then begin
  884. Dec ( FDig );
  885. Singles[FDig] := ue;
  886. Dec ( LDig );
  887. Dec ( fra );
  888. if fra < 0
  889. then EXIT;
  890. end;
  891. end;
  892. end;
  893. lnzf := False;
  894. i := LDig;
  895. while ( i >= FDig ) AND ( NOT lnzf ) do // skip trailing 0
  896. begin
  897. if Singles[i] <> 0
  898. then begin
  899. lnz := i;
  900. lnzf := True;
  901. end;
  902. Dec ( i );
  903. end;
  904. if lnzf
  905. then begin
  906. tm := LDig - lnz;
  907. if tm <> 0
  908. then begin
  909. { Dec ( pre, tm ); Dec/Inc error? }
  910. pre := pre - tm;
  911. { Dec ( fra, tm ); Dec/Inc error? }
  912. fra := fra - tm;
  913. { Dec ( LDig, tm ); Dec/Inc error? }
  914. LDig := LDig - tm;
  915. if fra < 0
  916. then begin
  917. { Dec ( pre, fra ); Dec/Inc error? }
  918. pre := pre - fra;
  919. { Dec ( LDig, fra ); Dec/Inc error? }
  920. LDig := LDig - fra;
  921. fra := 0;
  922. end;
  923. end;
  924. end
  925. else begin
  926. LDig := FDig;
  927. fra := 0;
  928. pre := 0;
  929. Neg := False;
  930. end;
  931. if pre <> 0
  932. then begin
  933. Precision := pre;
  934. rp := 0;
  935. i := FDig;
  936. while i <= LDig do
  937. begin
  938. if i < LDig
  939. then Fraction[rp] := ( Singles[i] SHL 4 ) OR Singles[i + 1]
  940. else Fraction[rp] := Singles[i] SHL 4;
  941. Inc ( rp );
  942. Inc ( i, 2 );
  943. end;
  944. {$ifndef bigger_BCD}
  945. if Neg
  946. then SignSpecialPlaces := NegBit;
  947. SignSpecialPlaces := SignSpecialPlaces OR fra;
  948. {$else}
  949. Negativ := Neg;
  950. Places := fra;
  951. {$endif}
  952. end;
  953. end;
  954. pack_BCD := True;
  955. end;
  956. function BCDPrecision ( const BCD : tBCD ) : Word; Inline;
  957. begin
  958. BCDPrecision := BCD.Precision;
  959. end;
  960. function BCDScale ( const BCD : tBCD ) : Word; Inline;
  961. begin
  962. {$ifndef bigger_BCD}
  963. BCDScale := BCD.SignSpecialPlaces AND PlacesMask;
  964. {$else}
  965. BCDScale := BCD.Places;
  966. {$endif}
  967. end;
  968. function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline;
  969. begin
  970. {$ifndef bigger_BCD}
  971. IsBCDNegative := ( BCD.SignSpecialPlaces AND NegBit ) <> 0;
  972. {$else}
  973. IsBCDNegative := BCD.Negativ;
  974. {$endif}
  975. end;
  976. { BCD Arithmetic}
  977. procedure BCDNegate ( var BCD : tBCD ); Inline;
  978. begin
  979. { with-statement geht nicht !!
  980. with bcd do
  981. if precision <> 0
  982. then signspecialplaces := signspecialplaces xor negbit;
  983. }
  984. if BCD.Precision <> 0
  985. then
  986. {$ifndef bigger_BCD}
  987. BCD.SignSpecialPlaces := BCD.SignSpecialPlaces XOR NegBit;
  988. {$else}
  989. BCD.Negativ := NOT BCD.Negativ;
  990. {$endif}
  991. end;
  992. { returns -1 if BCD1 < BCD2, 0 if BCD1 = BCD2, 1 if BCD1 > BCD2 }
  993. function BCDCompare ( const BCD1,
  994. BCD2 : tBCD ) : Integer;
  995. var
  996. pl1 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  997. pl2 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  998. pr1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  999. pr2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1000. pr : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1001. idig1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1002. idig2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1003. i : {$ifopt r+} __low_Fraction..__high_Fraction + 1 {$else} Integer {$endif};
  1004. f1 : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  1005. f2 : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  1006. res : {$ifopt r+} -1..1 {$else} Integer {$endif};
  1007. neg1,
  1008. neg2 : Boolean;
  1009. // real/reduced precision if there are on left side insignificant zero digits
  1010. function BCDPrec(const BCD: tBCD): word;
  1011. var scale: word;
  1012. begin
  1013. Result := BCD.Precision;
  1014. scale := BCDScale(BCD);
  1015. i := Low(BCD.Fraction);
  1016. while (Result>0) and (Result>scale) do begin
  1017. // high nibble
  1018. if BCD.Fraction[i] shr 4 <> 0 then Exit;
  1019. Dec(Result);
  1020. if Result <= scale then Exit;
  1021. // low nibble
  1022. if BCD.Fraction[i] <> 0 then Exit;
  1023. Dec(Result);
  1024. Inc(i);
  1025. end;
  1026. end;
  1027. begin
  1028. {$ifndef bigger_BCD}
  1029. neg1 := ( BCD1.SignSpecialPlaces AND NegBit ) <> 0;
  1030. neg2 := ( BCD2.SignSpecialPlaces AND NegBit ) <> 0;
  1031. {$else}
  1032. neg1 := BCD1.Negativ;
  1033. neg2 := BCD2.Negativ;
  1034. {$endif}
  1035. _SELECT
  1036. _WHEN neg1 AND ( NOT neg2 )
  1037. _THEN result := -1;
  1038. _WHEN ( NOT neg1 ) AND neg2
  1039. _THEN result := +1;
  1040. _WHENOTHER
  1041. pr1 := BCDPrec(BCD1);
  1042. pr2 := BCDPrec(BCD2);
  1043. {$ifndef bigger_BCD}
  1044. pl1 := BCD1.SignSpecialPlaces AND PlacesMask;
  1045. pl2 := BCD2.SignSpecialPlaces AND PlacesMask;
  1046. {$else}
  1047. pl1 := BCD1.Places;
  1048. pl2 := BCD2.Places;
  1049. {$endif}
  1050. idig1 := pr1 - pl1;
  1051. idig2 := pr2 - pl2;
  1052. if idig1 <> idig2
  1053. then begin
  1054. if ( idig1 > idig2 ) = neg1
  1055. then result := -1
  1056. else result := +1;
  1057. end
  1058. else begin
  1059. if pr1 < pr2
  1060. then pr := pr1
  1061. else pr := pr2;
  1062. res := 0;
  1063. i := __low_Fraction;
  1064. while ( res = 0 ) AND ( i < ( __low_Fraction + ( pr DIV 2 ) ) ) do
  1065. begin
  1066. _SELECT
  1067. _WHEN BCD1.Fraction[i] < BCD2.Fraction[i]
  1068. _THEN res := -1
  1069. _WHEN BCD1.Fraction[i] > BCD2.Fraction[i]
  1070. _THEN res := +1;
  1071. _WHENOTHER
  1072. _endSELECT;
  1073. Inc ( i );
  1074. end;
  1075. if res = 0
  1076. then begin
  1077. if Odd ( pr )
  1078. then begin
  1079. f1 := BCD1.Fraction[i] AND $f0;
  1080. f2 := BCD2.Fraction[i] AND $f0;
  1081. _SELECT
  1082. _WHEN f1 < f2
  1083. _THEN res := -1
  1084. _WHEN f1 > f2
  1085. _THEN res := +1;
  1086. _endSELECT;
  1087. end;
  1088. if res = 0 then
  1089. if pr1 > pr2 then
  1090. res := +1
  1091. else if pr1 < pr2 then
  1092. res := -1;
  1093. end;
  1094. if neg1
  1095. then result := 0 - res
  1096. else result := res;
  1097. end;
  1098. _endSELECT
  1099. end;
  1100. { Convert string/Double/Integer to BCD struct }
  1101. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  1102. var BCD : tBCD ) : Boolean;
  1103. begin
  1104. Result := TryStrToBCD(aValue, BCD, DefaultFormatSettings);
  1105. end;
  1106. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  1107. var BCD : tBCD;
  1108. Const Format : TFormatSettings) : Boolean;
  1109. var
  1110. {$ifndef use_ansistring}
  1111. lav : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1112. i : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1113. {$else}
  1114. lav : {$ifopt r+} longword {$else} longword {$endif};
  1115. i : {$ifopt r+} longword {$else} longword {$endif};
  1116. {$endif}
  1117. ch : Char;
  1118. type
  1119. ife = ( inint, infrac, inexp );
  1120. {$define max_exp_scanned := 9999 }
  1121. var
  1122. inife : ife;
  1123. lvars : record
  1124. fp,
  1125. lp : ARRAY [ ife ]
  1126. {$ifndef use_ansistring}
  1127. of {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1128. pfnb : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1129. ps : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1130. pse : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1131. errp : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1132. {$else}
  1133. of {$ifopt r+} longword {$else} longword {$endif};
  1134. pfnb : {$ifopt r+} longword {$else} longword {$endif};
  1135. ps : {$ifopt r+} longword {$else} longword {$endif};
  1136. pse : {$ifopt r+} longword {$else} longword {$endif};
  1137. errp : {$ifopt r+} longword {$else} longword {$endif};
  1138. {$endif}
  1139. exp : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1140. p : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1141. bh : tBCD_helper;
  1142. nbf : Boolean;
  1143. end;
  1144. begin
  1145. result := True;
  1146. FillChar ( lvars, SizeOf ( lvars ), #0 );
  1147. BCD := NullBCD;
  1148. lav := Length ( aValue );
  1149. if lav <> 0
  1150. then
  1151. WITH lvars,
  1152. bh do
  1153. begin
  1154. while ( pfnb < lav ) AND ( NOT nbf ) do // skip leading spaces
  1155. begin
  1156. Inc ( pfnb );
  1157. nbf := aValue[pfnb] <> ' ';
  1158. end;
  1159. if nbf
  1160. then begin
  1161. if aValue[pfnb] IN [ '+', '-' ]
  1162. then begin
  1163. ps := pfnb; // position of sign
  1164. Inc ( pfnb );
  1165. end;
  1166. inife := low ( inife );
  1167. for i := pfnb TO lav do
  1168. begin
  1169. ch := aValue[i];
  1170. case ch of
  1171. '0'..'9': begin
  1172. case inife of
  1173. inint,
  1174. inexp: if fp[inife] = 0
  1175. then begin
  1176. if ch <> '0'
  1177. then begin
  1178. fp[inife] := i;
  1179. lp[inife] := i;
  1180. end;
  1181. end
  1182. else lp[inife] := i;
  1183. infrac: begin
  1184. if fp[infrac] = 0
  1185. then fp[infrac] := i;
  1186. if ch <> '0'
  1187. then lp[infrac] := i;
  1188. end;
  1189. end;
  1190. end;
  1191. ',',
  1192. '.': if ch = Format.DecimalSeparator then
  1193. begin
  1194. if inife <> inint then result := False
  1195. else inife := infrac;
  1196. end;
  1197. 'e',
  1198. 'E': if inife = inexp
  1199. then result := False
  1200. else inife := inexp;
  1201. '+',
  1202. '-': if ( inife = inexp ) AND ( fp[inexp] = 0 )
  1203. then pse := i // position of exponent sign
  1204. else result := False;
  1205. else begin
  1206. result := False;
  1207. errp := i;
  1208. end;
  1209. end;
  1210. end;
  1211. if not result
  1212. then begin
  1213. result := True;
  1214. for i := errp TO lav do // skip trailing spaces
  1215. if aValue[i] <> ' '
  1216. then result := False;
  1217. end;
  1218. if not result
  1219. then EXIT;
  1220. if ps <> 0
  1221. then Neg := aValue[ps] = '-';
  1222. if lp[infrac] = 0
  1223. then fp[infrac] := 0;
  1224. if fp[inexp] <> 0
  1225. then begin
  1226. exp := 0;
  1227. for i := fp[inexp] TO lp[inexp] do
  1228. if result
  1229. then
  1230. if aValue[i] <> Format.ThousandSeparator
  1231. then begin
  1232. exp := exp * 10 + ( Ord ( aValue[i] ) - Ord ( '0' ) );
  1233. if exp > 999
  1234. then result := False;
  1235. end;
  1236. if not result
  1237. then EXIT;
  1238. if pse <> 0
  1239. then
  1240. if aValue[pse] = '-'
  1241. then exp := -exp;
  1242. end;
  1243. p := -exp;
  1244. if fp[infrac] <> 0
  1245. then begin
  1246. for i := fp[infrac] TO lp[infrac] do
  1247. if aValue[i] <> Format.ThousandSeparator
  1248. then begin
  1249. if p < ( MaxFmtBCDFractionSize + 2 )
  1250. then begin
  1251. Inc ( p );
  1252. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1253. end;
  1254. end;
  1255. end;
  1256. LDig := p;
  1257. p := 1 - exp;
  1258. if fp[inint] <> 0
  1259. then
  1260. for i := lp[inint] DOWNTO fp[inint] do
  1261. if aValue[i] <> Format.ThousandSeparator
  1262. then begin
  1263. if p > - ( MaxFmtBCDFractionSize + 2 )
  1264. then begin
  1265. Dec ( p );
  1266. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1267. end
  1268. else result := False;
  1269. end;
  1270. if not result
  1271. then EXIT;
  1272. FDig := p;
  1273. if LDig < 0
  1274. then LDig := 0;
  1275. Plac := LDig;
  1276. result := pack_BCD ( bh, BCD );
  1277. end;
  1278. end;
  1279. end;
  1280. function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD;
  1281. begin
  1282. Result := StrToBCD(aValue, DefaultFormatSettings);
  1283. end;
  1284. function StrToBCD ( const aValue : FmtBCDStringtype;
  1285. Const Format : TFormatSettings ) : tBCD;
  1286. begin
  1287. if not TryStrToBCD ( aValue, Result, Format ) then
  1288. raise eBCDOverflowException.create ( 'in StrToBCD' );
  1289. end;
  1290. {$ifndef FPUNONE}
  1291. procedure DoubleToBCD ( const aValue : myRealtype;
  1292. var BCD : tBCD );
  1293. var
  1294. s : string [ 30 ];
  1295. f : TFormatSettings;
  1296. begin
  1297. Str ( aValue : 25, s );
  1298. f.DecimalSeparator := '.';
  1299. f.ThousandSeparator := #0;
  1300. BCD := StrToBCD ( s, f );
  1301. end;
  1302. function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline;
  1303. begin
  1304. DoubleToBCD ( aValue, result );
  1305. end;
  1306. {$endif}
  1307. function IntegerToBCD ( const aValue : myInttype ) : tBCD;
  1308. var
  1309. bh : tBCD_helper;
  1310. v : {$ifopt r+} 0..high ( myInttype ) {$else} Integer {$endif};
  1311. p : {$ifopt r+} low ( bh.Singles ) - 1..0 {$else} Integer {$endif};
  1312. exitloop : Boolean;
  1313. begin
  1314. _SELECT
  1315. _WHEN aValue = 0
  1316. _THEN result := ZeroBCD;
  1317. _WHEN aValue = 1
  1318. _THEN result := OneBCD;
  1319. _WHEN aValue = low ( myInttype )
  1320. _THEN
  1321. {$if declared ( myMinIntBCD ) }
  1322. result := myMinIntBCD;
  1323. {$else}
  1324. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1325. {$endif}
  1326. _WHENOTHER
  1327. bh := null_.bh;
  1328. WITH bh do
  1329. begin
  1330. Neg := aValue < 0;
  1331. if Neg
  1332. then v := -aValue
  1333. else v := +aValue;
  1334. LDig := 0;
  1335. p := 0;
  1336. REPEAT
  1337. Singles[p] := v MOD 10;
  1338. v := v DIV 10;
  1339. exitloop := v = 0;
  1340. Dec ( p );
  1341. if p < low ( Singles )
  1342. then begin
  1343. exitloop := True;
  1344. (* what to do if error occurred? *)
  1345. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1346. end;
  1347. UNTIL exitloop;
  1348. FDig := p + 1;
  1349. end;
  1350. pack_BCD ( bh, result );
  1351. _endSELECT;
  1352. end;
  1353. function CurrToBCD ( const Curr : currency;
  1354. var BCD : tBCD;
  1355. Precision : Integer = 32;
  1356. Decimals : Integer = 4 ) : Boolean;
  1357. {
  1358. this works under the assumption that a currency is an int64,
  1359. except for scale of 10000
  1360. }
  1361. var
  1362. i : int64 absolute Curr;
  1363. begin
  1364. BCD := IntegerToBCD ( i );
  1365. {$ifndef bigger_BCD}
  1366. BCD.SignSpecialPlaces := 4 OR ( BCD.SignSpecialPlaces AND NegBit );
  1367. {$else}
  1368. BCD.Places := 4;
  1369. {$endif}
  1370. if (Decimals <> 4) or (Decimals > BCD.Precision) then
  1371. Result := NormalizeBCD ( BCD, BCD, Precision, Decimals )
  1372. else
  1373. Result := True;
  1374. end;
  1375. {$ifdef comproutines}
  1376. function CompToBCD ( const Curr : Comp ) : tBCD; Inline;
  1377. var
  1378. cc : int64 absolute Curr;
  1379. begin
  1380. result := IntegerToBCD ( cc );
  1381. end;
  1382. function BCDToComp ( const BCD : tBCD ) : Comp; Inline;
  1383. var
  1384. zz : record
  1385. case Boolean of
  1386. False: ( i : int64 );
  1387. True: ( c : Comp );
  1388. end;
  1389. begin
  1390. zz.i := BCDToInteger ( BCD );
  1391. BCDToComp := zz.c;
  1392. end;
  1393. {$endif}
  1394. { Convert BCD struct to string/Double/Integer }
  1395. function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype;
  1396. begin
  1397. Result := BCDToStr(BCD, DefaultFormatSettings);
  1398. end;
  1399. function BCDToStr ( const BCD : tBCD;
  1400. Const Format : TFormatSettings ) : FmtBCDStringtype;
  1401. var
  1402. bh : tBCD_helper;
  1403. l : {$ifopt r+} 0..maxfmtbcdfractionsize + 1 + 1 {$else} Integer {$endif};
  1404. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1405. pp : {$ifopt r+} low ( bh.FDig ) - 1..1 {$else} Integer {$endif};
  1406. begin
  1407. {$ifdef use_ansistring}
  1408. result := '';
  1409. {$endif}
  1410. unpack_BCD ( BCD, bh );
  1411. WITH bh do
  1412. begin
  1413. l := 0;
  1414. if Neg then
  1415. begin
  1416. {$ifndef use_ansistring}
  1417. Inc ( l );
  1418. result[l] := '-';
  1419. {$else}
  1420. result := result + '-';
  1421. {$endif}
  1422. end;
  1423. if Plac >= Prec then
  1424. begin
  1425. // insert leading 0 before decimal point
  1426. {$ifndef use_ansistring}
  1427. Inc ( l );
  1428. result[l] := '0';
  1429. {$else}
  1430. result := result + '0';
  1431. {$endif}
  1432. end;
  1433. if Prec > 0 then
  1434. begin
  1435. if Plac > 0 then
  1436. begin
  1437. if Plac > Prec then FDig := 1;
  1438. pp := 1;
  1439. end
  1440. else
  1441. pp := low ( bh.FDig ) - 1; // there is no decimal point
  1442. for i := FDig TO LDig do
  1443. begin
  1444. if i = pp then
  1445. begin
  1446. {$ifndef use_ansistring}
  1447. Inc ( l );
  1448. result[l] := Format.DecimalSeparator;
  1449. {$else}
  1450. result := result + Format.DecimalSeparator;
  1451. {$endif}
  1452. end;
  1453. {$ifndef use_ansistring}
  1454. Inc ( l );
  1455. result[l] := Chr ( Singles[i] + Ord ( '0' ) );
  1456. {$else}
  1457. result := result + Chr ( Singles[i] + Ord ( '0' ) );
  1458. {$endif}
  1459. end;
  1460. end;
  1461. end;
  1462. {$ifndef use_ansistring}
  1463. result[0] := Chr ( l );
  1464. {$endif}
  1465. end;
  1466. {$ifndef FPUNONE}
  1467. function BCDToDouble ( const BCD : tBCD ) : myRealtype;
  1468. var
  1469. bh : tBCD_helper;
  1470. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1471. r,
  1472. e : myRealtype;
  1473. begin
  1474. unpack_BCD ( BCD, bh );
  1475. WITH bh do
  1476. begin
  1477. r := 0;
  1478. e := 1;
  1479. for i := 0 DOWNTO FDig do
  1480. begin
  1481. r := r + Singles[i] * e;
  1482. e := e * 10;
  1483. end;
  1484. e := 1;
  1485. for i := 1 TO LDig do
  1486. begin
  1487. e := e / 10;
  1488. r := r + Singles[i] * e;
  1489. end;
  1490. if Neg
  1491. then BCDToDouble := -r
  1492. else BCDToDouble := +r;
  1493. end;
  1494. end;
  1495. {$endif}
  1496. function BCDToInteger ( const BCD : tBCD;
  1497. Truncate : Boolean = False ) : myInttype;
  1498. var
  1499. bh : tBCD_helper;
  1500. res : myInttype;
  1501. i : {$ifopt r+} low ( bh.FDig )..0 {$else} Integer {$endif};
  1502. {
  1503. unclear: behaviour if overflow: abort? return 0? return something?
  1504. so: checks are missing yet
  1505. }
  1506. begin
  1507. unpack_BCD ( BCD, bh );
  1508. res := 0;
  1509. WITH bh do
  1510. begin
  1511. for i := FDig TO 0 do
  1512. res := res * 10 - Singles[i];
  1513. if NOT Truncate
  1514. then
  1515. if Plac > 0
  1516. then
  1517. if Singles[1] > 4
  1518. then Dec ( res );
  1519. if Neg
  1520. then BCDToInteger := +res
  1521. else BCDToInteger := -res;
  1522. end;
  1523. end;
  1524. { From DB.pas }
  1525. function BCDToCurr ( const BCD : tBCD;
  1526. var Curr : currency ) : Boolean;
  1527. const
  1528. MaxCurr: array[boolean] of QWord = (QWord($7FFFFFFFFFFFFFFF), QWord($8000000000000000));
  1529. var
  1530. bh : tBCD_helper;
  1531. res : QWord;
  1532. c : currency absolute res;
  1533. i : {$ifopt r+} low ( bh.FDig )..4 {$else} Integer {$endif};
  1534. {
  1535. unclear: behaviour if overflow: abort? return 0? return something?
  1536. }
  1537. begin
  1538. BCDToCurr := False;
  1539. if BCDPrecision(BCD) - BCDScale(BCD) > 15 then
  1540. Exit;
  1541. unpack_BCD ( BCD, bh );
  1542. res := 0;
  1543. WITH bh do
  1544. begin
  1545. for i := FDig TO 4 do
  1546. res := res * 10 + Singles[i];
  1547. if Plac > 4
  1548. then
  1549. if Singles[5] > 4
  1550. then Inc ( res );
  1551. if res > MaxCurr[Neg] then
  1552. Exit;
  1553. if Neg then
  1554. begin
  1555. res := not res;
  1556. inc(res);
  1557. end;
  1558. Curr := c;
  1559. BCDToCurr := True;
  1560. end;
  1561. end;
  1562. procedure BCDAdd ( const BCDin1,
  1563. BCDin2 : tBCD;
  1564. var BCDout : tBCD );
  1565. var
  1566. bhr,
  1567. bh1,
  1568. bh2 : tBCD_helper;
  1569. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1570. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1571. v : {$ifopt r+} 0..9 + 9 + 1 {$else} Integer {$endif};
  1572. BCD : tBCD;
  1573. negate : Boolean;
  1574. begin
  1575. negate := IsBCDNegative ( BCDin1 );
  1576. if negate <> IsBCDNegative ( BCDin2 )
  1577. then begin
  1578. if negate
  1579. then begin
  1580. BCD := BCDin1;
  1581. BCDNegate ( BCD );
  1582. BCDSubtract ( BCDin2, BCD, BCDout );
  1583. EXIT;
  1584. end;
  1585. BCD := BCDin2;
  1586. BCDNegate ( BCD );
  1587. BCDSubtract ( BCDin1, BCD, BCDout );
  1588. EXIT;
  1589. end;
  1590. bhr := null_.bh;
  1591. WITH bhr do
  1592. begin
  1593. unpack_BCD ( BCDin1, bh1 );
  1594. unpack_BCD ( BCDin2, bh2 );
  1595. if bh1.FDig < bh2.FDig
  1596. then FDig := bh1.FDig
  1597. else FDig := bh2.FDig;
  1598. if bh1.LDig > bh2.LDig
  1599. then LDig := bh1.LDig
  1600. else LDig := bh2.LDig;
  1601. Plac := LDig;
  1602. ue := 0;
  1603. for i := LDig DOWNTO FDig do
  1604. begin
  1605. v := bh1.Singles[i] + bh2.Singles[i] + ue;
  1606. ue := v DIV 10;
  1607. Singles[i] := v MOD 10;
  1608. end;
  1609. if ue <> 0
  1610. then begin
  1611. Dec ( FDig );
  1612. Singles[FDig] := ue;
  1613. end;
  1614. Neg := negate;
  1615. end;
  1616. if NOT pack_BCD ( bhr, BCDout )
  1617. then begin
  1618. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  1619. end;
  1620. end;
  1621. procedure BCDSubtract ( const BCDin1,
  1622. BCDin2 : tBCD;
  1623. var BCDout : tBCD );
  1624. var
  1625. bhr,
  1626. bh1,
  1627. bh2 : tBCD_helper;
  1628. cmp : {$ifopt r+} -1..1 {$else} Integer {$endif};
  1629. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1630. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1631. v : {$ifopt r+} 0 - 9 - 1..9 - 0 - 0 {$else} Integer {$endif};
  1632. negate : Boolean;
  1633. BCD : tBCD;
  1634. begin
  1635. negate := IsBCDNegative ( BCDin1 );
  1636. if negate <> IsBCDNegative ( BCDin2 )
  1637. then begin
  1638. if negate
  1639. then begin
  1640. BCD := BCDin1;
  1641. BCDNegate ( BCD );
  1642. BCDAdd ( BCDin2, BCD, BCDout );
  1643. BCDNegate ( BCDout );
  1644. EXIT;
  1645. end;
  1646. BCD := BCDin2;
  1647. BCDNegate ( BCD );
  1648. BCDAdd ( BCDin1, BCD, BCDout );
  1649. EXIT;
  1650. end;
  1651. cmp := BCDCompare ( BCDin1, BCDin2 );
  1652. if cmp = 0
  1653. then begin
  1654. BCDout := NullBCD;
  1655. EXIT;
  1656. end;
  1657. bhr := null_.bh; { n n }
  1658. WITH bhr do { > < > < }
  1659. begin { }
  1660. if ( cmp > 0 ) = negate { +123 +12 -12 -123 }
  1661. then begin { - +12 - +123 - -123 - -12 }
  1662. unpack_BCD ( BCDin1, bh2 ); { x x }
  1663. unpack_BCD ( BCDin2, bh1 ); { s s s s }
  1664. negate := NOT negate; { nn n nn n }
  1665. end
  1666. else begin
  1667. unpack_BCD ( BCDin1, bh1 );
  1668. unpack_BCD ( BCDin2, bh2 );
  1669. end;
  1670. if bh1.FDig < bh2.FDig
  1671. then FDig := bh1.FDig
  1672. else FDig := bh2.FDig;
  1673. if bh1.LDig > bh2.LDig
  1674. then LDig := bh1.LDig
  1675. else LDig := bh2.LDig;
  1676. Plac := LDig;
  1677. ue := 0;
  1678. for i := LDig DOWNTO FDig do
  1679. begin
  1680. v := Integer ( bh1.Singles[i] ) - bh2.Singles[i] - ue;
  1681. ue := 0;
  1682. if v < 0
  1683. then begin
  1684. ue := 1;
  1685. Inc ( v, 10 );
  1686. end;
  1687. Singles[i] := v;
  1688. end;
  1689. Neg := negate;
  1690. if NOT pack_BCD ( bhr, BCDout )
  1691. then begin
  1692. {should never occur!}
  1693. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  1694. end;
  1695. end;
  1696. end;
  1697. { Returns True if successful, False if Int Digits needed to be truncated }
  1698. function NormalizeBCD ( const InBCD : tBCD;
  1699. var OutBCD : tBCD;
  1700. const Precision,
  1701. Places : Integer ) : Boolean;
  1702. var
  1703. bh : tBCD_helper;
  1704. tm : {$ifopt r+} __lo_bh..__hi_bh {$else} Integer {$endif};
  1705. begin
  1706. {$ifopt r+}
  1707. if ( Precision < 0 ) OR ( Precision > MaxFmtBCDFractionSize ) then RangeError;
  1708. if ( Places < 0 ) OR ( Precision >= MaxFmtBCDFractionSize ) then RangeError;
  1709. {$endif}
  1710. if (BCDScale(InBCD) > Places) or (BCDPrecision(InBCD) < Places) then
  1711. begin
  1712. unpack_BCD ( InBCD, bh );
  1713. tm := bh.Plac - Places;
  1714. bh.Plac := Places;
  1715. { dec ( prec, tm ); Dec/Inc error? }
  1716. bh.Prec := bh.Prec - tm;
  1717. { dec ( LDig, tm ); Dec/Inc error? }
  1718. bh.LDig := bh.LDig - tm;
  1719. NormalizeBCD := tm <= 0;
  1720. if NOT pack_BCD ( bh, OutBCD ) then
  1721. RAISE eBCDOverflowException.Create ( 'in NormalizeBCD' );
  1722. end
  1723. else
  1724. begin
  1725. OutBCD := InBCD;
  1726. NormalizeBCD := True;
  1727. end
  1728. end;
  1729. procedure BCDMultiply ( const BCDin1,
  1730. BCDin2 : tBCD;
  1731. var BCDout : tBCD );
  1732. var
  1733. bh1,
  1734. bh2,
  1735. bhr : tBCD_helper;
  1736. bhrr : tBCD_helper_big;
  1737. i1 : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1738. i2 : {$ifopt r+} low ( bh2.FDig )..high ( bh2.LDig ) {$else} Integer {$endif};
  1739. i3 : {$ifopt r+} low ( bhrr.FDig )..high ( bhrr.LDig ) {$else} Integer {$endif};
  1740. v : {$ifopt r+} low ( bhrr.Singles[0] )..high ( bhrr.Singles[0] ) {$else} Integer {$endif};
  1741. ue : {$ifopt r+} low ( bhrr.Singles[0] ) DIV 10..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  1742. begin
  1743. unpack_BCD ( BCDin1, bh1 );
  1744. unpack_BCD ( BCDin2, bh2 );
  1745. if ( bh1.Prec = 0 ) OR ( bh2.Prec = 0 )
  1746. then begin
  1747. BCDout := NullBCD;
  1748. EXIT;
  1749. end;
  1750. bhr := null_.bh;
  1751. bhrr := null_.bhb;
  1752. WITH bhrr do
  1753. begin
  1754. Neg := bh1.Neg XOR bh2.Neg;
  1755. {
  1756. writeln ( __lo_bhb, ' ', __hi_bhb, ' ', bh1.fdig, ' ', bh2.fdig, ' ', low ( fdig ), ' ', low ( ldig ) );
  1757. }
  1758. FDig := bh1.FDig + bh2.FDig;
  1759. LDig := bh1.LDig + bh2.LDig;
  1760. for i1 := bh1.FDig TO bh1.LDig do
  1761. for i2 := bh2.FDig TO bh2.LDig do
  1762. begin
  1763. Inc ( Singles[i1 + i2],
  1764. bh1.Singles[i1]
  1765. * bh2.Singles[i2] );
  1766. {
  1767. write ( Singles[i1 + i2], ' ', bh1.Singles[i1], ' ', bh2.Singles[i2], ' : ' );
  1768. writeln ( Singles[i1 + i2] + bh1.Singles[i1] + bh2.Singles[i2] );
  1769. }
  1770. {
  1771. Singles[i1 + i2] := Singles[i1 + i2]
  1772. + bh1.Singles[i1]
  1773. * bh2.Singles[i2];
  1774. }
  1775. end;
  1776. {
  1777. for i3 := fdig to ldig do
  1778. write ( ' ', singles[i3] );
  1779. writeln;
  1780. }
  1781. if FDig < low ( bhr.Singles )
  1782. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1783. ue := 0;
  1784. for i3 := LDig DOWNTO FDig do
  1785. begin
  1786. v := Singles[i3] + ue;
  1787. ue := v DIV 10;
  1788. v := v MOD 10;
  1789. bhr.Singles[i3] := v;
  1790. end;
  1791. while ue <> 0 do
  1792. begin
  1793. Dec ( FDig );
  1794. if FDig < low ( bhr.Singles )
  1795. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1796. bhr.Singles[FDig] := ue MOD 10;
  1797. ue := ue DIV 10;
  1798. end;
  1799. bhr.neg := bh1.Neg XOR bh2.Neg;
  1800. bhr.Plac := LDig;
  1801. bhr.FDig := FDig;
  1802. if LDig > high ( bhr.Singles )
  1803. then bhr.LDig := high ( bhr.Singles )
  1804. else bhr.LDig := LDig;
  1805. end;
  1806. if NOT pack_BCD ( bhr, BCDout )
  1807. then begin
  1808. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1809. end;
  1810. end;
  1811. {$ifndef FPUNONE}
  1812. procedure BCDMultiply ( const BCDIn : tBCD;
  1813. const DoubleIn : myRealtype;
  1814. var BCDout : tBCD ); Inline;
  1815. begin
  1816. BCDMultiply ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  1817. end;
  1818. {$endif}
  1819. procedure BCDMultiply ( const BCDIn : tBCD;
  1820. const StringIn : FmtBCDStringtype;
  1821. var BCDout : tBCD ); Inline;
  1822. begin
  1823. BCDMultiply ( BCDIn, StrToBCD ( StringIn ), BCDout );
  1824. end;
  1825. procedure BCDMultiply ( const StringIn1,
  1826. StringIn2 : FmtBCDStringtype;
  1827. var BCDout : tBCD ); Inline;
  1828. begin
  1829. BCDMultiply ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  1830. end;
  1831. procedure BCDDivide ( const Dividend,
  1832. Divisor : tBCD;
  1833. var BCDout : tBCD );
  1834. var
  1835. bh1 : ARRAY [ Boolean ] of tBCD_helper;
  1836. bh2,
  1837. bh : tBCD_helper;
  1838. p : {$ifopt r+} low ( bh.FDig ) - high ( bh.FDig )..high ( bh.FDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1839. v1 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1840. v2 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1841. lFDig : {$ifopt r+} low ( bh.FDig )..high ( bh.FDig ) {$else} Integer {$endif};
  1842. d1 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1843. d2 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1844. d : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1845. lLdig : {$ifopt r+} low ( lFDig ) + low ( d )..high ( lFDig ) + high ( d ) {$else} Integer {$endif};
  1846. tm : {$ifopt r+} low ( lLdig ) - high ( bh2.Singles )..high ( lLdig ) - high ( bh2.Singles ) {$else} Integer {$endif};
  1847. i2 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1848. i3 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1849. ie : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1850. i4 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1851. nFDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1852. nLDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1853. dd : {$ifopt r+} 0..9 {$else} Integer {$endif};
  1854. Add : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1855. ue : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1856. v3 : {$ifopt r+} low ( bh.Singles[0] ) - high ( bh2.singles[9] ) * high ( dd ) - high ( ue )..high ( bh.Singles[0] ) - low ( bh2.singles[9] ) * low ( dd ) - low ( ue ) {$else} Integer {$endif};
  1857. v4 : {$ifopt r+} low ( bh.Singles[0] ) + low ( add )..high ( bh.Singles[0] ) + high ( add ) {$else} Integer {$endif};
  1858. FlipFlop,
  1859. nz,
  1860. sf,
  1861. sh,
  1862. fdset : Boolean;
  1863. {
  1864. bh1p : ARRAY [ Boolean ] of ^ tBCD_helper;
  1865. }
  1866. begin
  1867. { test:
  1868. bh1p[false] := @ bh1[false];
  1869. bh1p[true] := @ bh1[true];
  1870. v := bh1[false].singles[0];
  1871. v := bh1[true].singles[0];
  1872. v := bh1p[false]^.singles[0];
  1873. v := bh1p[true]^.singles[0];
  1874. v := bh1[nz].singles[0];
  1875. v := bh1p[nz]^.singles[0];
  1876. }
  1877. unpack_BCD ( Divisor, bh2 );
  1878. unpack_BCD ( Dividend, bh1[False] );
  1879. p := bh1[False].FDig - bh2.FDig;
  1880. _SELECT
  1881. _WHEN bh2.Prec = 0
  1882. _THEN RAISE eBCDException.create ( 'Division by zero' );
  1883. _WHEN bh1[False].Prec = 0
  1884. _THEN BCDout := NullBCD;
  1885. _WHEN p < low ( bh2.Singles )
  1886. _THEN RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  1887. _WHENOTHER
  1888. bh := null_.bh;
  1889. bh.Neg := bh1[False].Neg XOR bh2.Neg;
  1890. if p <= high ( bh.Singles )
  1891. then begin
  1892. bh1[True] := null_.bh;
  1893. FlipFlop := False;
  1894. fdset := p > 0;
  1895. Add := 0;
  1896. nz := True;
  1897. while nz do
  1898. WITH bh1[FlipFlop] do
  1899. begin
  1900. {
  1901. WriteLn('#####');
  1902. dumpbh ( bh1[flipflop] );
  1903. dumpbh ( bh2 );
  1904. dumpbh ( bh );
  1905. }
  1906. if ( Singles[FDig] + bh2.Singles[bh2.FDig] ) = 0
  1907. then begin
  1908. if ( FDig >= LDig )
  1909. OR ( bh2.FDig >= bh2.LDig )
  1910. then nz := False
  1911. else begin
  1912. Inc ( FDig );
  1913. Inc ( bh2.FDig );
  1914. end;
  1915. end
  1916. else begin
  1917. v1 := Singles[FDig];
  1918. v2 := bh2.Singles[bh2.FDig];
  1919. sh := v1 < v2;
  1920. if ( v1 = v2 )
  1921. then begin
  1922. nz := False;
  1923. i3 := Succ ( FDig );
  1924. ie := LDig;
  1925. while ( i3 <= ie ) AND ( NOT nz ) AND ( NOT sh ) do
  1926. begin
  1927. v1 := Singles[i3];
  1928. v2 := bh2.Singles[i3 - p];
  1929. if v1 <> v2
  1930. then begin
  1931. nz := True;
  1932. if v1 < v2
  1933. then sh := True;
  1934. end;
  1935. Inc ( i3 );
  1936. end;
  1937. end;
  1938. if NOT nz
  1939. then Add := 1
  1940. else begin
  1941. if sh
  1942. then begin
  1943. Inc ( p );
  1944. {
  1945. if p > 3 then halt;
  1946. }
  1947. if p > high ( bh.Singles )
  1948. then nz := False
  1949. else Dec ( bh2.FDig );
  1950. end
  1951. else begin
  1952. lFDig := FDig;
  1953. d1 := LDig - FDig;
  1954. d2 := bh2.LDig - bh2.FDig;
  1955. if d1 > d2
  1956. then d := d1
  1957. else d := d2;
  1958. lLdig := lFDig + d;
  1959. if lLdig > high ( bh2.Singles )
  1960. then begin
  1961. tm := ( lLdig ) - high ( bh2.Singles );
  1962. d := d - tm;
  1963. lLdig := lLdig - tm;
  1964. {runden?}
  1965. end;
  1966. sf := True;
  1967. Add := 0;
  1968. nFDig := 0;
  1969. nLDig := 0;
  1970. ue := 0;
  1971. dd := Singles[lFDig] DIV ( bh2.Singles[lFDig - p] + 1 );
  1972. if dd < 1
  1973. then dd := 1;
  1974. {
  1975. writeln ( 'p=', p, ' dd=', dd, ' lFdig=', lfdig, ' lldig=', lldig );
  1976. }
  1977. for i2 := lLdig DOWNTO lFDig do
  1978. begin
  1979. // Typecase needed on 64-bit because evaluation happens using qword...
  1980. v3 := Longint(Singles[i2]) - Longint(bh2.Singles[i2 - p] * dd) - Longint(ue);
  1981. ue := 0;
  1982. while v3 < 0 do
  1983. begin
  1984. Inc ( ue );;
  1985. v3 := v3 + 10;
  1986. end;
  1987. {
  1988. if v3 <> 0
  1989. then begin
  1990. }
  1991. bh1[NOT FlipFlop].Singles[i2] := v3;
  1992. {
  1993. nFDig := i2;
  1994. if sf
  1995. then begin
  1996. nLDig := i2;
  1997. sf := False;
  1998. end;
  1999. end;
  2000. }
  2001. end;
  2002. sf := False;
  2003. nFDig := lFDig;
  2004. nLDig := lLDig;
  2005. Inc ( Add, dd );
  2006. if sf
  2007. then nz := False
  2008. else begin
  2009. FillChar ( bh1[FlipFlop], SizeOf ( bh1[FlipFlop] ), #0 );
  2010. FlipFlop := NOT FlipFlop;
  2011. WITH bh1[FlipFlop] do
  2012. begin
  2013. FDig := nFDig;
  2014. LDig := nLDig;
  2015. end;
  2016. end;
  2017. end;
  2018. end;
  2019. if Add <> 0
  2020. then begin
  2021. if NOT fdset
  2022. then begin
  2023. bh.FDig := p;
  2024. fdset := True;
  2025. end;
  2026. if bh.LDig < p
  2027. then begin
  2028. bh.LDig := p;
  2029. if ( bh.LDig - bh.FDig ) > Succ ( MaxFmtBCDFractionSize )
  2030. then nz := False;
  2031. end;
  2032. i4 := p;
  2033. while ( Add <> 0 ) AND ( i4 >= bh.FDig ) do
  2034. begin
  2035. {
  2036. writeln ( '> ', i4, ' ', bh.Singles[i4], ' ', Add );
  2037. }
  2038. v4 := bh.Singles[i4] + Add;
  2039. Add := v4 DIV 10;
  2040. bh.Singles[i4] := v4 MOD 10;
  2041. Dec ( i4 );
  2042. end;
  2043. if Add <> 0
  2044. then begin
  2045. Dec ( bh.FDig );
  2046. bh.Singles[bh.FDig] := Add;
  2047. Add := 0;
  2048. end;
  2049. end;
  2050. end;
  2051. end;
  2052. end;
  2053. WITH bh do
  2054. begin
  2055. if LDig < 0
  2056. then LDig := 0;
  2057. if LDig > 0
  2058. then Plac := LDig
  2059. else Plac := 0;
  2060. end;
  2061. if NOT pack_BCD ( bh, BCDout )
  2062. then begin
  2063. RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  2064. end;
  2065. _endSELECT
  2066. end;
  2067. procedure BCDDivide ( const Dividend,
  2068. Divisor : FmtBCDStringtype;
  2069. var BCDout : tBCD ); Inline;
  2070. begin
  2071. BCDDivide ( StrToBCD ( Dividend ), StrToBCD ( Divisor ), BCDout );
  2072. end;
  2073. {$ifndef FPUNONE}
  2074. procedure BCDDivide ( const Dividend : tBCD;
  2075. const Divisor : myRealtype;
  2076. var BCDout : tBCD ); Inline;
  2077. begin
  2078. BCDDivide ( Dividend, DoubleToBCD ( Divisor ), BCDout );
  2079. end;
  2080. {$endif}
  2081. procedure BCDDivide ( const Dividend : tBCD;
  2082. const Divisor : FmtBCDStringtype;
  2083. var BCDout : tBCD ); Inline;
  2084. begin
  2085. BCDDivide ( Dividend, StrToBCD ( Divisor ), BCDout );
  2086. end;
  2087. { TBCD variant creation utils }
  2088. procedure VarFmtBCDCreate ( var aDest : Variant;
  2089. const aBCD : tBCD );
  2090. begin
  2091. VarClear(aDest);
  2092. TVarData(aDest).Vtype:=FMTBcdFactory.Vartype;
  2093. TVarData(aDest).VPointer:=TFMTBcdVarData.create(aBCD);
  2094. end;
  2095. function VarFmtBCDCreate : Variant;
  2096. begin
  2097. VarFmtBCDCreate ( result, NullBCD );
  2098. end;
  2099. function VarFmtBCDCreate ( const aValue : FmtBCDStringtype;
  2100. Precision,
  2101. Scale : Word ) : Variant;
  2102. begin
  2103. VarFmtBCDCreate ( result, StrToBCD ( aValue ) );
  2104. end;
  2105. {$ifndef FPUNONE}
  2106. function VarFmtBCDCreate ( const aValue : myRealtype;
  2107. Precision : Word = 18;
  2108. Scale : Word = 4 ) : Variant;
  2109. begin
  2110. VarFmtBCDCreate ( result, DoubleToBCD ( aValue ) );
  2111. end;
  2112. {$endif}
  2113. function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant;
  2114. begin
  2115. VarFmtBCDCreate ( result, aBCD );
  2116. end;
  2117. function VarIsFmtBCD ( const aValue : Variant ) : Boolean;
  2118. begin
  2119. Result:=TVarData(aValue).VType=FMTBcdFactory.VarType;
  2120. end;
  2121. function VarFmtBCD : TVartype;
  2122. begin
  2123. Result:=FMTBcdFactory.VarType;
  2124. end;
  2125. { Formatting BCD as string }
  2126. function BCDToStrF ( const BCD : tBCD;
  2127. Format : TFloatFormat;
  2128. const Precision,
  2129. Digits : Integer ) : FmtBCDStringtype;
  2130. var P, E: integer;
  2131. Negative: boolean;
  2132. DS, TS: char;
  2133. procedure RoundDecimalDigits(const d: integer);
  2134. var i,j: integer;
  2135. begin
  2136. j:=P+d;
  2137. if (Length(Result) > j) and (Result[j+1] >= '5') then
  2138. for i:=j downto 1+ord(Negative) do
  2139. begin
  2140. if Result[i] = '9' then
  2141. begin
  2142. Result[i] := '0';
  2143. if i = 1+ord(Negative) then
  2144. begin
  2145. Insert('1', Result, i);
  2146. inc(P);
  2147. inc(j);
  2148. end;
  2149. end
  2150. else if Result[i] <> DS then
  2151. begin
  2152. inc(Result[i]);
  2153. break;
  2154. end;
  2155. end;
  2156. if d = 0 then dec(j); // if decimal separator is last char then do not copy them
  2157. Result := copy(Result, 1, j);
  2158. end;
  2159. procedure AddDecimalDigits(d: integer);
  2160. var n: integer;
  2161. begin
  2162. if P > Length(Result) then // there isn't decimal separator
  2163. if d = 0 then
  2164. Exit
  2165. else
  2166. Result := Result + DS;
  2167. n := d + P - Length(Result);
  2168. if n > 0 then
  2169. Result := Result + StringOfChar('0', n)
  2170. else if n < 0 then
  2171. RoundDecimalDigits(d);
  2172. end;
  2173. procedure AddThousandSeparators;
  2174. begin
  2175. Dec(P, 3);
  2176. While (P > 1) Do
  2177. Begin
  2178. If (Result[P - 1] <> '-') And (TS <> #0) Then
  2179. Insert(TS, Result, P);
  2180. Dec(P, 3);
  2181. End;
  2182. end;
  2183. begin
  2184. Result := BCDToStr(BCD);
  2185. if Format = ffGeneral then Exit;
  2186. DS:=DefaultFormatSettings.DecimalSeparator;
  2187. TS:=DefaultFormatSettings.ThousandSeparator;
  2188. Negative := Result[1] = '-';
  2189. P := Pos(DS, Result);
  2190. if P = 0 then
  2191. P := Length(Result) + 1;
  2192. Case Format Of
  2193. ffExponent:
  2194. Begin
  2195. E := P - 2 - ord(Negative);
  2196. if (E = 0) and (Result[P-1] = '0') then // 0.###
  2197. repeat
  2198. dec(E);
  2199. until (Length(Result) <= P-E) or (Result[P-E] <> '0');
  2200. if E <> 0 then
  2201. begin
  2202. System.Delete(Result, P, 1);
  2203. dec(P, E);
  2204. Insert(DS, Result, P);
  2205. end;
  2206. AddDecimalDigits(Precision-1);
  2207. if E < 0 then
  2208. begin
  2209. System.Delete(Result, P+E-1, -E);
  2210. Result := Result + SysUtils.Format('E%.*d' , [Digits,E])
  2211. end
  2212. else
  2213. Result := Result + SysUtils.Format('E+%.*d', [Digits,E]);
  2214. End;
  2215. ffFixed:
  2216. Begin
  2217. AddDecimalDigits(Digits);
  2218. End;
  2219. ffNumber:
  2220. Begin
  2221. AddDecimalDigits(Digits);
  2222. AddThousandSeparators;
  2223. End;
  2224. ffCurrency:
  2225. Begin
  2226. //implementation based on FloatToStrFIntl()
  2227. if Negative then System.Delete(Result, 1, 1);
  2228. AddDecimalDigits(Digits);
  2229. AddThousandSeparators;
  2230. If Not Negative Then
  2231. Begin
  2232. Case FormatSettings.CurrencyFormat Of
  2233. 0: Result := FormatSettings.CurrencyString + Result;
  2234. 1: Result := Result + FormatSettings.CurrencyString;
  2235. 2: Result := FormatSettings.CurrencyString + ' ' + Result;
  2236. 3: Result := Result + ' ' + FormatSettings.CurrencyString;
  2237. End
  2238. End
  2239. Else
  2240. Begin
  2241. Case FormatSettings.NegCurrFormat Of
  2242. 0: Result := '(' + FormatSettings.CurrencyString + Result + ')';
  2243. 1: Result := '-' + FormatSettings.CurrencyString + Result;
  2244. 2: Result := FormatSettings.CurrencyString + '-' + Result;
  2245. 3: Result := FormatSettings.CurrencyString + Result + '-';
  2246. 4: Result := '(' + Result + FormatSettings.CurrencyString + ')';
  2247. 5: Result := '-' + Result + FormatSettings.CurrencyString;
  2248. 6: Result := Result + '-' + FormatSettings.CurrencyString;
  2249. 7: Result := Result + FormatSettings.CurrencyString + '-';
  2250. 8: Result := '-' + Result + ' ' + FormatSettings.CurrencyString;
  2251. 9: Result := '-' + FormatSettings.CurrencyString + ' ' + Result;
  2252. 10: Result := FormatSettings.CurrencyString + ' ' + Result + '-';
  2253. End;
  2254. End;
  2255. End;
  2256. End;
  2257. end;
  2258. function FormatBCD ( const Format : string;
  2259. BCD : tBCD ) : FmtBCDStringtype;
  2260. // Tests: tests/test/units/fmtbcd/
  2261. type
  2262. TSection=record
  2263. FmtStart, FmtEnd, // positions in Format string,
  2264. Fmt1Dig, // position of 1st digit placeholder,
  2265. FmtDS: PChar; // position of decimal point
  2266. Digits: integer; // number of all digit placeholders
  2267. DigDS: integer; // number of digit placeholders after decimal separator
  2268. HasTS, HasDS: boolean; // has thousand or decimal separator?
  2269. end;
  2270. var
  2271. PFmt: PChar;
  2272. i, j, j1, je, ReqSec, Sec, Scale: integer;
  2273. Section: TSection;
  2274. FF: TFloatFormat;
  2275. BCDStr: string; // BCDToStrF of given BCD parameter
  2276. Buf: array [0..85] of char; // output buffer
  2277. // Parses Format parameter, their sections (positive;negative;zero) and
  2278. // builds Section information for requested section
  2279. procedure ParseFormat;
  2280. var C,Q: Char;
  2281. PFmtEnd: PChar;
  2282. Section1: TSection;
  2283. begin
  2284. PFmt:=@Format[1];
  2285. PFmtEnd:=PFmt+length(Format);
  2286. Section.FmtStart:=PFmt;
  2287. Section.Fmt1Dig:=nil;
  2288. Section.Digits:=0;
  2289. Section.HasTS:=false; // has thousand separator?
  2290. Section.HasDS:=false; // has decimal separator?
  2291. Sec:=1;
  2292. while true do begin
  2293. if PFmt>=PFmtEnd then
  2294. C:=#0 // hack if short strings used
  2295. else
  2296. C:=PFmt^;
  2297. case C of
  2298. '''', '"':
  2299. begin
  2300. Q:=PFmt^;
  2301. inc(PFmt);
  2302. while (PFmt<PFmtEnd-1) and (PFmt^<>Q) do
  2303. inc(PFmt);
  2304. end;
  2305. #0, ';': // end of Format string or end of section
  2306. begin
  2307. if Sec > 1 then
  2308. Section.FmtStart:=Section.FmtEnd+1;
  2309. Section.FmtEnd:=PFmt;
  2310. if not assigned(Section.Fmt1Dig) then
  2311. Section.Fmt1Dig:=Section.FmtEnd;
  2312. if not Section.HasDS then
  2313. begin
  2314. Section.FmtDS := Section.FmtEnd;
  2315. Section.DigDS := 0;
  2316. end;
  2317. if Sec = 1 then
  2318. Section1 := Section;
  2319. if (C = #0) or (Sec=ReqSec) then
  2320. break;
  2321. Section.Fmt1Dig:=nil;
  2322. Section.Digits:=0;
  2323. Section.HasTS:=false;
  2324. Section.HasDS:=false;
  2325. inc(Sec);
  2326. end;
  2327. '.': // decimal point
  2328. begin
  2329. Section.HasDS:=true;
  2330. Section.FmtDS:=PFmt;
  2331. Section.DigDS:=0;
  2332. end;
  2333. ',': // thousand separator
  2334. Section.HasTS:=true;
  2335. '0','#': // digits placeholders
  2336. begin
  2337. if not assigned(Section.Fmt1Dig) then Section.Fmt1Dig:=PFmt;
  2338. inc(Section.Digits);
  2339. inc(Section.DigDS);
  2340. end;
  2341. end;
  2342. inc(PFmt);
  2343. end;
  2344. // if requested section does not exists or is empty use first section
  2345. if (ReqSec > Sec) or (Section.FmtStart=Section.FmtEnd) then
  2346. begin
  2347. Section := Section1;
  2348. Sec := 1;
  2349. end;
  2350. end;
  2351. procedure PutFmtDigit(var AFmt: PChar; var iBCDStr, iBuf: integer; MoveBy: integer);
  2352. var ADig, Q: Char;
  2353. begin
  2354. if (iBuf < low(Buf)) or (iBuf > high(Buf)) then
  2355. raise eBCDOverflowException.Create ( 'in FormatBCD' );
  2356. if (iBCDStr < 1) or (iBCDStr > length(BCDStr)) then
  2357. ADig:=#0
  2358. else
  2359. ADig:=BCDStr[iBCDStr];
  2360. // write remaining leading part of BCDStr if there are no more digit placeholders in Format string
  2361. if ((AFmt < Section.Fmt1Dig) and (AFmt < Section.FmtDS) and (ADig <> #0)) or
  2362. (ADig = DefaultFormatSettings.ThousandSeparator) then
  2363. begin
  2364. Buf[iBuf] := BCDStr[iBCDStr];
  2365. inc(iBCDStr, MoveBy);
  2366. inc(iBuf, MoveBy);
  2367. Exit;
  2368. end;
  2369. case AFmt^ of
  2370. '''','"':
  2371. begin
  2372. Q:=AFmt^;
  2373. inc(AFmt, MoveBy);
  2374. // write all characters between quotes
  2375. while (AFmt>Section.FmtStart) and (AFmt<Section.FmtEnd) and (AFmt^ <> Q) do
  2376. begin
  2377. Buf[iBuf] := AFmt^;
  2378. inc(AFmt, MoveBy);
  2379. inc(iBuf, MoveBy);
  2380. end;
  2381. end;
  2382. '0','.':
  2383. begin
  2384. if AFmt^ = '.' then
  2385. Buf[iBuf] := DefaultFormatSettings.DecimalSeparator
  2386. else if ADig = #0 then
  2387. Buf[iBuf] := '0'
  2388. else
  2389. Buf[iBuf] := ADig;
  2390. inc(AFmt, MoveBy);
  2391. inc(iBCDStr, MoveBy);
  2392. inc(iBuf, MoveBy);
  2393. end;
  2394. '#':
  2395. begin
  2396. if ADig = #0 then
  2397. inc(AFmt, MoveBy)
  2398. else if (ADig = '0') and (iBCDStr = 1) then // skip leading zero
  2399. begin
  2400. inc(AFmt, MoveBy);
  2401. inc(iBCDStr, MoveBy);
  2402. end
  2403. else
  2404. begin
  2405. Buf[iBuf] := ADig;
  2406. inc(AFmt, MoveBy);
  2407. inc(iBCDStr, MoveBy);
  2408. inc(iBuf, MoveBy);
  2409. end;
  2410. end;
  2411. ',':
  2412. begin
  2413. inc(AFmt, MoveBy); // thousand separators are already in BCDStr
  2414. end;
  2415. else // write character what is in Format as is
  2416. begin
  2417. Buf[iBuf] := AFmt^;
  2418. inc(AFmt, MoveBy);
  2419. inc(iBuf, MoveBy);
  2420. end;
  2421. end;
  2422. end;
  2423. begin
  2424. case BCDCompare(BCD, NullBCD) of
  2425. 1: ReqSec := 1;
  2426. 0: ReqSec := 3;
  2427. -1: ReqSec := 2;
  2428. end;
  2429. // remove sign for negative value
  2430. if ReqSec = 2 then
  2431. BCDNegate(BCD);
  2432. // parse Format into Section
  2433. ParseFormat;
  2434. if Section.FmtStart=Section.FmtEnd then // empty section
  2435. FF := ffGeneral
  2436. else if Section.HasTS then
  2437. FF := ffNumber
  2438. else
  2439. FF := ffFixed;
  2440. Scale := BCDScale(BCD);
  2441. if (FF <> ffGeneral) and (Scale > Section.DigDS) then // we need rounding
  2442. Scale := Section.DigDS;
  2443. BCDStr := BCDToStrF(BCD, FF, 64, Scale);
  2444. if (FF = ffGeneral) then
  2445. begin
  2446. Result:=BCDStr;
  2447. Exit;
  2448. end;
  2449. // write to output buffer
  2450. j1 := high(Buf); // position of 1st number before decimal point in output buffer
  2451. je := length(Buf); // position after last digit in output buffer
  2452. // output decimal part of BCDStr
  2453. if Section.HasDS and (Section.FmtEnd-Section.FmtDS>1) then // is there something after decimal point?
  2454. begin
  2455. PFmt := Section.FmtDS; // start from decimal point until end
  2456. i := length(BCDStr) - Scale + ord(Scale=0);
  2457. dec(j1, Section.FmtEnd-Section.FmtDS);
  2458. j := j1 + 1; // points to decimal separator in output buffer
  2459. while PFmt < Section.FmtEnd do
  2460. PutFmtDigit(PFmt, i, j, 1);
  2461. if j-j1=2 then // alone decimal separator at end of output buffer
  2462. dec(j);
  2463. je := j; // store position after last decimal digit (or any constant character) in output buffer
  2464. end;
  2465. // output whole number part of BCDStr
  2466. PFmt := Section.FmtDS - 1;
  2467. i := length(BCDStr) - Scale - ord(Scale<>0);
  2468. j := j1;
  2469. while (i>0) and (j>0) do
  2470. PutFmtDigit(PFmt, i, j, -1);
  2471. // output leading '0' (f.e. '001.23')
  2472. while (PFmt >= Section.FmtStart) and (PFmt^ = '0') do
  2473. PutFmtDigit(PFmt, i, j, -1);
  2474. // output sign (-), if value is negative, and does not exists 2nd section
  2475. if (ReqSec = 2) and (Sec = 1) then
  2476. begin
  2477. Buf[j]:='-';
  2478. dec(j);
  2479. end;
  2480. // output remaining chars from begining of Format (f.e. 'abc' if given Format is 'abc0.00')
  2481. while PFmt >= Section.FmtStart do
  2482. PutFmtDigit(PFmt, i, j, -1);
  2483. inc(j);
  2484. if j > high(Buf) then
  2485. Result := ''
  2486. else
  2487. SetString(Result, @Buf[j], je-j);
  2488. end;
  2489. {$ifdef additional_routines}
  2490. function CurrToBCD ( const Curr : currency ) : tBCD; Inline;
  2491. begin
  2492. CurrToBCD ( Curr, result );
  2493. end;
  2494. procedure BCDAdd ( const BCDIn : tBCD;
  2495. const IntIn : myInttype;
  2496. var BCDout : tBCD );
  2497. var
  2498. BCD : tBCD;
  2499. bhr : tBCD_helper;
  2500. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2501. ue : {$ifopt r+} 0..high ( IntIn ) - 9 {$else} Integer {$endif};
  2502. v : {$ifopt r+} 0..{high ( ue ) + 9} high ( IntIn ) {$else} Integer {$endif};
  2503. nz : Boolean;
  2504. begin
  2505. if IntIn = 0
  2506. then begin
  2507. BCDout := BCDIn;
  2508. EXIT;
  2509. end;
  2510. if IntIn = low ( myInttype )
  2511. then begin
  2512. {$if declared ( myMinIntBCD ) }
  2513. BCDAdd ( BCDIn, myMinIntBCD, BCDout );
  2514. EXIT;
  2515. {$else}
  2516. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2517. {$endif}
  2518. end;
  2519. if IsBCDNegative ( BCDIn )
  2520. then begin
  2521. BCD := BCDIn;
  2522. BCDNegate ( BCD );
  2523. if IntIn < 0
  2524. then BCDAdd ( BCD, -IntIn, BCDout )
  2525. else BCDSubtract ( BCD, IntIn, BCDout );
  2526. BCDNegate ( BCDout );
  2527. EXIT;
  2528. end;
  2529. if IntIn < 0
  2530. then begin
  2531. BCDSubtract ( BCDIn, -IntIn, BCDout );
  2532. EXIT;
  2533. end;
  2534. if IntIn > ( high ( IntIn ) - 9 )
  2535. then begin
  2536. BCDAdd ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2537. EXIT;
  2538. end;
  2539. unpack_BCD ( BCDIn, bhr );
  2540. p := 0;
  2541. nz := True;
  2542. ue := IntIn;
  2543. while nz do
  2544. begin
  2545. v := bhr.Singles[p] + ue;
  2546. bhr.Singles[p] := v MOD 10;
  2547. ue := v DIV 10;
  2548. if ue = 0
  2549. then nz := False
  2550. else Dec ( p );
  2551. end;
  2552. if p < bhr.FDig
  2553. then begin
  2554. bhr.FDig := p;
  2555. bhr.Prec := bhr.Prec + ( bhr.FDig - p );
  2556. end;
  2557. if NOT pack_BCD ( bhr, BCDout )
  2558. then begin
  2559. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2560. end;
  2561. end;
  2562. procedure BCDSubtract ( const BCDIn : tBCD;
  2563. const IntIn : myInttype;
  2564. var BCDout : tBCD );
  2565. {}
  2566. var
  2567. BCD : tBCD;
  2568. bhr : tBCD_helper;
  2569. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2570. ue : {$ifopt r+} 0..pred ( 100000000 ) {$else} Integer {$endif};
  2571. v : {$ifopt r+} -9..9 {$else} Integer {$endif};
  2572. direct : Boolean;
  2573. {}
  2574. begin
  2575. if IntIn = 0
  2576. then begin
  2577. BCDout := BCDIn;
  2578. EXIT;
  2579. end;
  2580. if IntIn = low ( myInttype )
  2581. then begin
  2582. {$if declared ( myMinIntBCD ) }
  2583. BCDSubtract ( BCDIn, myMinIntBCD, BCDout );
  2584. EXIT;
  2585. {$else}
  2586. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2587. {$endif}
  2588. end;
  2589. if IsBCDNegative ( BCDIn )
  2590. then begin
  2591. BCD := BCDIn;
  2592. BCDNegate ( BCD );
  2593. if IntIn < 0
  2594. then BCDSubtract ( BCD, -IntIn, BCDout )
  2595. else BCDAdd ( BCD, IntIn, BCDout );
  2596. BCDNegate ( BCDout );
  2597. EXIT;
  2598. end;
  2599. if IntIn < 0
  2600. then begin
  2601. BCDAdd ( BCDIn, -IntIn, BCDout );
  2602. EXIT;
  2603. end;
  2604. direct := False;
  2605. case BCDIn.Precision
  2606. -
  2607. {$ifndef bigger_BCD}
  2608. ( BCDIn.SignSpecialPlaces AND PlacesMask )
  2609. {$else}
  2610. BCDIn.Places
  2611. {$endif}
  2612. of
  2613. 2: direct := IntIn < 10;
  2614. 3: direct := IntIn < 100;
  2615. 4: direct := IntIn < 1000;
  2616. 5: direct := IntIn < 10000;
  2617. 6: direct := IntIn < 100000;
  2618. 7: direct := IntIn < 1000000;
  2619. 8: direct := IntIn < 10000000;
  2620. 9: direct := IntIn < 100000000;
  2621. end;
  2622. {
  2623. write(direct);dumpbcd(bcdin);write('[',intin,']');
  2624. }
  2625. if direct
  2626. then begin
  2627. unpack_BCD ( BCDIn, bhr );
  2628. WITH bhr do
  2629. begin
  2630. p := 0;
  2631. ue := IntIn;
  2632. while p >= FDig do
  2633. begin
  2634. v := Singles[p] - ue MOD 10;
  2635. ue := ue DIV 10;
  2636. if v < 0
  2637. then begin
  2638. v := v + 10;
  2639. ue := ue + 1;
  2640. end;
  2641. Singles[p] := v;
  2642. Dec ( p );
  2643. end;
  2644. end;
  2645. if NOT pack_BCD ( bhr, BCDout )
  2646. then begin
  2647. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2648. end;
  2649. end
  2650. else
  2651. {}
  2652. BCDSubtract ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2653. end;
  2654. procedure BCDAdd ( const IntIn : myInttype;
  2655. const BCDIn : tBCD;
  2656. var BCDout : tBCD ); Inline;
  2657. begin
  2658. BCDAdd ( BCDIn, IntIn, BCDout );
  2659. end;
  2660. {$ifndef FPUNONE}
  2661. procedure BCDAdd ( const BCDIn : tBCD;
  2662. const DoubleIn : myRealtype;
  2663. var BCDout : tBCD ); Inline;
  2664. begin
  2665. BCDAdd ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2666. end;
  2667. procedure BCDAdd ( const DoubleIn : myRealtype;
  2668. const BCDIn : tBCD;
  2669. var BCDout : tBCD ); Inline;
  2670. begin
  2671. BCDAdd ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2672. end;
  2673. {$endif}
  2674. procedure BCDAdd ( const BCDIn : tBCD;
  2675. const Currin : currency;
  2676. var BCDout : tBCD ); Inline;
  2677. begin
  2678. BCDAdd ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2679. end;
  2680. procedure BCDAdd ( const Currin : currency;
  2681. const BCDIn : tBCD;
  2682. var BCDout : tBCD ); Inline;
  2683. begin
  2684. BCDAdd ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2685. end;
  2686. {$ifdef comproutines}
  2687. procedure BCDAdd ( const BCDIn : tBCD;
  2688. const Compin : Comp;
  2689. var BCDout : tBCD ); Inline;
  2690. begin
  2691. BCDAdd ( BCDIn, CompToBCD ( Compin ), BCDout );
  2692. end;
  2693. procedure BCDAdd ( const Compin : Comp;
  2694. const BCDIn : tBCD;
  2695. var BCDout : tBCD ); Inline;
  2696. begin
  2697. BCDAdd ( CompToBCD ( Compin ), BCDIn, BCDout );
  2698. end;
  2699. {$endif}
  2700. procedure BCDAdd ( const BCDIn : tBCD;
  2701. const StringIn : FmtBCDStringtype;
  2702. var BCDout : tBCD ); Inline;
  2703. begin
  2704. BCDAdd ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2705. end;
  2706. procedure BCDAdd ( const StringIn : FmtBCDStringtype;
  2707. const BCDIn : tBCD;
  2708. var BCDout : tBCD ); Inline;
  2709. begin
  2710. BCDAdd ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2711. end;
  2712. procedure BCDAdd ( const StringIn1,
  2713. StringIn2 : FmtBCDStringtype;
  2714. var BCDout : tBCD ); Inline;
  2715. begin
  2716. BCDAdd ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2717. end;
  2718. procedure BCDSubtract ( const IntIn : myInttype;
  2719. const BCDIn : tBCD;
  2720. var BCDout : tBCD ); Inline;
  2721. begin
  2722. BCDSubtract ( BCDIn, IntIn, BCDout );
  2723. BCDNegate ( BCDout );
  2724. end;
  2725. {$ifndef FPUNONE}
  2726. procedure BCDSubtract ( const BCDIn : tBCD;
  2727. const DoubleIn : myRealtype;
  2728. var BCDout : tBCD ); Inline;
  2729. begin
  2730. BCDSubtract ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2731. end;
  2732. procedure BCDSubtract ( const DoubleIn : myRealtype;
  2733. const BCDIn : tBCD;
  2734. var BCDout : tBCD ); Inline;
  2735. begin
  2736. BCDSubtract ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2737. end;
  2738. {$endif}
  2739. procedure BCDSubtract ( const BCDIn : tBCD;
  2740. const Currin : currency;
  2741. var BCDout : tBCD ); Inline;
  2742. begin
  2743. BCDSubtract ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2744. end;
  2745. procedure BCDSubtract ( const Currin : currency;
  2746. const BCDIn : tBCD;
  2747. var BCDout : tBCD ); Inline;
  2748. begin
  2749. BCDSubtract ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2750. end;
  2751. {$ifdef comproutines}
  2752. procedure BCDSubtract ( const BCDIn : tBCD;
  2753. const Compin : Comp;
  2754. var BCDout : tBCD ); Inline;
  2755. begin
  2756. BCDSubtract ( BCDIn, CompToBCD ( Compin ), BCDout );
  2757. end;
  2758. procedure BCDSubtract ( const Compin : Comp;
  2759. const BCDIn : tBCD;
  2760. var BCDout : tBCD ); Inline;
  2761. begin
  2762. BCDSubtract ( CompToBCD ( Compin ), BCDIn, BCDout );
  2763. end;
  2764. {$endif}
  2765. procedure BCDSubtract ( const BCDIn : tBCD;
  2766. const StringIn : FmtBCDStringtype;
  2767. var BCDout : tBCD ); Inline;
  2768. begin
  2769. BCDSubtract ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2770. end;
  2771. procedure BCDSubtract ( const StringIn : FmtBCDStringtype;
  2772. const BCDIn : tBCD;
  2773. var BCDout : tBCD ); Inline;
  2774. begin
  2775. BCDSubtract ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2776. end;
  2777. procedure BCDSubtract ( const StringIn1,
  2778. StringIn2 : FmtBCDStringtype;
  2779. var BCDout : tBCD ); Inline;
  2780. begin
  2781. BCDSubtract ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2782. end;
  2783. procedure BCDMultiply ( const BCDIn : tBCD;
  2784. const IntIn : myInttype;
  2785. var BCDout : tBCD );
  2786. var
  2787. bh : tBCD_helper;
  2788. bhr : tBCD_helper;
  2789. bhrr : tBCD_helper_big;
  2790. int : {$ifopt r+} 0..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  2791. i1 : {$ifopt r+} low ( bh.Singles )..high ( bh.Singles ) {$else} Integer {$endif};
  2792. i3 : {$ifopt r+} low ( bhr.Singles )..high ( bhr.Singles ) {$else} Integer {$endif};
  2793. v : {$ifopt r+} low ( bhrr.Singles[0] ) + low ( bhrr.Singles[0] ) DIV 10..high ( bhrr.Singles[0] ) + high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  2794. ue : {$ifopt r+} 1 * ( low ( bhrr.Singles[0] ) + low ( bhrr.Singles[0] ) DIV 10 ) DIV 10
  2795. ..( high ( bhrr.Singles[0] ) + high ( bhrr.Singles[0] ) DIV 10 ) DIV 10 {$else} Integer {$endif};
  2796. begin
  2797. if IntIn = 0
  2798. then begin
  2799. BCDout := NullBCD;
  2800. EXIT;
  2801. end;
  2802. if IntIn = 1
  2803. then begin
  2804. BCDout := BCDIn;
  2805. EXIT;
  2806. end;
  2807. if IntIn = -1
  2808. then begin
  2809. BCDout := BCDIn;
  2810. BCDNegate ( BCDout );
  2811. EXIT;
  2812. end;
  2813. if IntIn = low ( myInttype )
  2814. then begin
  2815. {$if declared ( myMinIntBCD ) }
  2816. BCDMultiply ( BCDIn, myMinIntBCD, BCDout );
  2817. EXIT;
  2818. {$else}
  2819. RAISE eBCDOverflowException.create ( 'in BCDmultiply' );
  2820. {$endif}
  2821. end;
  2822. if Abs ( IntIn ) > low ( bhrr.Singles[0] ) DIV 10
  2823. then begin
  2824. BCDMultiply ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2825. EXIT;
  2826. end;
  2827. unpack_BCD ( BCDIn, bh );
  2828. if bh.Prec = 0
  2829. then begin
  2830. BCDout := NullBCD;
  2831. EXIT;
  2832. end;
  2833. bhr := null_.bh;
  2834. bhrr := null_.bhb;
  2835. int := Abs ( IntIn );
  2836. WITH bhrr do
  2837. begin
  2838. Neg := bh.Neg XOR ( IntIn < 0 );
  2839. FDig := bh.FDig;
  2840. LDig := bh.LDig;
  2841. for i1 := bh.FDig TO bh.LDig do
  2842. Singles[i1] := bh.Singles[i1] * int;
  2843. {
  2844. for i3 := fdig to ldig do
  2845. write ( ' ', singles[i3] );
  2846. writeln;
  2847. }
  2848. ue := 0;
  2849. for i3 := LDig DOWNTO FDig do
  2850. begin
  2851. v := Singles[i3] + ue;
  2852. ue := v DIV 10;
  2853. v := v MOD 10;
  2854. bhr.Singles[i3] := v;
  2855. end;
  2856. while ue <> 0 do
  2857. begin
  2858. Dec ( FDig );
  2859. if FDig < low ( bhr.Singles )
  2860. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2861. bhr.Singles[FDig] := ue MOD 10;
  2862. ue := ue DIV 10;
  2863. end;
  2864. bhr.Plac := LDig;
  2865. bhr.FDig := FDig;
  2866. if LDig > high ( bhr.Singles )
  2867. then bhr.LDig := high ( bhr.Singles )
  2868. else bhr.LDig := LDig;
  2869. end;
  2870. if NOT pack_BCD ( bhr, BCDout )
  2871. then begin
  2872. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2873. end;
  2874. end;
  2875. procedure BCDMultiply ( const IntIn : myInttype;
  2876. const BCDIn : tBCD;
  2877. var BCDout : tBCD ); Inline;
  2878. begin
  2879. BCDMultiply ( BCDIn, IntIn, BCDout );
  2880. end;
  2881. {$ifndef FPUNONE}
  2882. procedure BCDMultiply ( const DoubleIn : myRealtype;
  2883. const BCDIn : tBCD;
  2884. var BCDout : tBCD ); Inline;
  2885. begin
  2886. BCDMultiply ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2887. end;
  2888. {$endif}
  2889. procedure BCDMultiply ( const BCDIn : tBCD;
  2890. const Currin : currency;
  2891. var BCDout : tBCD ); Inline;
  2892. begin
  2893. BCDMultiply ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2894. end;
  2895. procedure BCDMultiply ( const Currin : currency;
  2896. const BCDIn : tBCD;
  2897. var BCDout : tBCD ); Inline;
  2898. begin
  2899. BCDMultiply ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2900. end;
  2901. {$ifdef comproutines}
  2902. procedure BCDMultiply ( const BCDIn : tBCD;
  2903. const Compin : Comp;
  2904. var BCDout : tBCD ); Inline;
  2905. begin
  2906. BCDMultiply ( BCDIn, CompToBCD ( Compin ), BCDout );
  2907. end;
  2908. procedure BCDMultiply ( const Compin : Comp;
  2909. const BCDIn : tBCD;
  2910. var BCDout : tBCD ); Inline;
  2911. begin
  2912. BCDMultiply ( CompToBCD ( Compin ), BCDIn, BCDout );
  2913. end;
  2914. {$endif}
  2915. procedure BCDMultiply ( const StringIn : FmtBCDStringtype;
  2916. const BCDIn : tBCD;
  2917. var BCDout : tBCD ); Inline;
  2918. begin
  2919. BCDMultiply ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2920. end;
  2921. procedure BCDDivide ( const Dividend : tBCD;
  2922. const Divisor : myInttype;
  2923. var BCDout : tBCD ); Inline;
  2924. begin
  2925. BCDDivide ( Dividend, IntegerToBCD ( Divisor ), BCDout );
  2926. end;
  2927. procedure BCDDivide ( const Dividend : myInttype;
  2928. const Divisor : tBCD;
  2929. var BCDout : tBCD ); Inline;
  2930. begin
  2931. BCDDivide ( IntegerToBCD ( Dividend ), Divisor, BCDout );
  2932. end;
  2933. {$ifndef FPUNONE}
  2934. procedure BCDDivide ( const Dividend : myRealtype;
  2935. const Divisor : tBCD;
  2936. var BCDout : tBCD ); Inline;
  2937. begin
  2938. BCDDivide ( DoubleToBCD ( Dividend ), Divisor, BCDout );
  2939. end;
  2940. {$endif}
  2941. procedure BCDDivide ( const BCDIn : tBCD;
  2942. const Currin : currency;
  2943. var BCDout : tBCD ); Inline;
  2944. begin
  2945. BCDDivide ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2946. end;
  2947. procedure BCDDivide ( const Currin : currency;
  2948. const BCDIn : tBCD;
  2949. var BCDout : tBCD ); Inline;
  2950. begin
  2951. BCDDivide ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2952. end;
  2953. {$ifdef comproutines}
  2954. procedure BCDDivide ( const BCDIn : tBCD;
  2955. const Compin : Comp;
  2956. var BCDout : tBCD ); Inline;
  2957. begin
  2958. BCDDivide ( BCDIn, CompToBCD ( Compin ), BCDout );
  2959. end;
  2960. procedure BCDDivide ( const Compin : Comp;
  2961. const BCDIn : tBCD;
  2962. var BCDout : tBCD ); Inline;
  2963. begin
  2964. BCDDivide ( CompToBCD ( Compin ), BCDIn, BCDout );
  2965. end;
  2966. {$endif}
  2967. procedure BCDDivide ( const Dividend : FmtBCDStringtype;
  2968. const Divisor : tBCD;
  2969. var BCDout : tBCD ); Inline;
  2970. begin
  2971. BCDDivide ( StrToBCD ( Dividend ), Divisor, BCDout );
  2972. end;
  2973. operator = ( const BCD1,
  2974. BCD2 : tBCD ) z : Boolean; Inline;
  2975. begin
  2976. z := BCDCompare ( BCD1, BCD2 ) = 0;
  2977. end;
  2978. operator < ( const BCD1,
  2979. BCD2 : tBCD ) z : Boolean; Inline;
  2980. begin
  2981. z := BCDCompare ( BCD1, BCD2 ) < 0;
  2982. end;
  2983. operator > ( const BCD1,
  2984. BCD2 : tBCD ) z : Boolean; Inline;
  2985. begin
  2986. z := BCDCompare ( BCD1, BCD2 ) > 0;
  2987. end;
  2988. operator <= ( const BCD1,
  2989. BCD2 : tBCD ) z : Boolean; Inline;
  2990. begin
  2991. z := BCDCompare ( BCD1, BCD2 ) <= 0;
  2992. end;
  2993. operator >= ( const BCD1,
  2994. BCD2 : tBCD ) z : Boolean; Inline;
  2995. begin
  2996. z := BCDCompare ( BCD1, BCD2 ) >= 0;
  2997. end;
  2998. (* ######################## not allowed: why?
  2999. operator + ( const BCD : tBCD ) z : tBCD; Inline;
  3000. begin
  3001. z := bcd;
  3002. end;
  3003. ##################################################### *)
  3004. operator - ( const BCD : tBCD ) z : tBCD; Inline;
  3005. begin
  3006. z := BCD;
  3007. BCDNegate ( z );
  3008. end;
  3009. operator + ( const BCD1,
  3010. BCD2 : tBCD ) z : tBCD; Inline;
  3011. begin
  3012. BCDAdd ( BCD1, BCD2, z );
  3013. end;
  3014. operator + ( const BCD : tBCD;
  3015. const i : myInttype ) z : tBCD; Inline;
  3016. begin
  3017. BCDAdd ( BCD, i, z );
  3018. end;
  3019. operator + ( const i : myInttype;
  3020. const BCD : tBCD ) z : tBCD; Inline;
  3021. begin
  3022. BCDAdd ( i, BCD, z );
  3023. end;
  3024. {$ifndef FPUNONE}
  3025. operator + ( const BCD : tBCD;
  3026. const r : myRealtype ) z : tBCD; Inline;
  3027. begin
  3028. BCDAdd ( BCD, DoubleToBCD ( r ), z );
  3029. end;
  3030. operator + ( const r : myRealtype;
  3031. const BCD : tBCD ) z : tBCD; Inline;
  3032. begin
  3033. BCDAdd ( DoubleToBCD ( r ), BCD, z );
  3034. end;
  3035. {$endif}
  3036. operator + ( const BCD : tBCD;
  3037. const c : currency ) z : tBCD; Inline;
  3038. begin
  3039. BCDAdd ( BCD, CurrToBCD ( c ), z );
  3040. end;
  3041. operator + ( const c : currency;
  3042. const BCD : tBCD ) z : tBCD; Inline;
  3043. begin
  3044. BCDAdd ( CurrToBCD ( c ), BCD, z );
  3045. end;
  3046. {$ifdef comproutines}
  3047. operator + ( const BCD : tBCD;
  3048. const c : Comp ) z : tBCD; Inline;
  3049. begin
  3050. BCDAdd ( BCD, CompToBCD ( c ), z );
  3051. end;
  3052. operator + ( const c : Comp;
  3053. const BCD : tBCD ) z : tBCD; Inline;
  3054. begin
  3055. BCDAdd ( CompToBCD ( c ), BCD, z );
  3056. end;
  3057. {$endif}
  3058. operator + ( const BCD : tBCD;
  3059. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3060. begin
  3061. BCDAdd ( BCD, StrToBCD ( s ), z );
  3062. end;
  3063. operator + ( const s : FmtBCDStringtype;
  3064. const BCD : tBCD ) z : tBCD; Inline;
  3065. begin
  3066. BCDAdd ( StrToBCD ( s ), BCD, z );
  3067. end;
  3068. operator - ( const BCD1,
  3069. BCD2 : tBCD ) z : tBCD; Inline;
  3070. begin
  3071. BCDSubtract ( BCD1, BCD2, z );
  3072. end;
  3073. operator - ( const BCD : tBCD;
  3074. const i : myInttype ) z : tBCD; Inline;
  3075. begin
  3076. BCDSubtract ( BCD, i, z );
  3077. end;
  3078. operator - ( const i : myInttype;
  3079. const BCD : tBCD ) z : tBCD; Inline;
  3080. begin
  3081. BCDSubtract ( BCD, i, z );
  3082. BCDNegate ( z );
  3083. end;
  3084. {$ifndef FPUNONE}
  3085. operator - ( const BCD : tBCD;
  3086. const r : myRealtype ) z : tBCD; Inline;
  3087. begin
  3088. BCDSubtract ( BCD, DoubleToBCD ( r ), z );
  3089. end;
  3090. operator - ( const r : myRealtype;
  3091. const BCD : tBCD ) z : tBCD; Inline;
  3092. begin
  3093. BCDSubtract ( DoubleToBCD ( r ), BCD, z );
  3094. end;
  3095. {$endif}
  3096. operator - ( const BCD : tBCD;
  3097. const c : currency ) z : tBCD; Inline;
  3098. begin
  3099. BCDSubtract ( BCD, CurrToBCD ( c ), z );
  3100. end;
  3101. operator - ( const c : currency;
  3102. const BCD : tBCD ) z : tBCD; Inline;
  3103. begin
  3104. BCDSubtract ( CurrToBCD ( c ), BCD, z );
  3105. end;
  3106. {$ifdef comproutines}
  3107. operator - ( const BCD : tBCD;
  3108. const c : Comp ) z : tBCD; Inline;
  3109. begin
  3110. BCDSubtract ( BCD, CompToBCD ( c ), z );
  3111. end;
  3112. operator - ( const c : Comp;
  3113. const BCD : tBCD ) z : tBCD; Inline;
  3114. begin
  3115. BCDSubtract ( CompToBCD ( c ), BCD, z );
  3116. end;
  3117. {$endif}
  3118. operator - ( const BCD : tBCD;
  3119. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3120. begin
  3121. BCDSubtract ( BCD, StrToBCD ( s ), z );
  3122. end;
  3123. operator - ( const s : FmtBCDStringtype;
  3124. const BCD : tBCD ) z : tBCD; Inline;
  3125. begin
  3126. BCDSubtract ( StrToBCD ( s ), BCD, z );
  3127. end;
  3128. operator * ( const BCD1,
  3129. BCD2 : tBCD ) z : tBCD; Inline;
  3130. begin
  3131. BCDMultiply ( BCD1, BCD2, z );
  3132. end;
  3133. operator * ( const BCD : tBCD;
  3134. const i : myInttype ) z : tBCD; Inline;
  3135. begin
  3136. BCDMultiply ( BCD, i, z );
  3137. end;
  3138. operator * ( const i : myInttype;
  3139. const BCD : tBCD ) z : tBCD; Inline;
  3140. begin
  3141. BCDMultiply ( BCD, i, z );
  3142. end;
  3143. {$ifndef FPUNONE}
  3144. operator * ( const BCD : tBCD;
  3145. const r : myRealtype ) z : tBCD; Inline;
  3146. begin
  3147. BCDMultiply ( BCD, DoubleToBCD ( r ), z );
  3148. end;
  3149. operator * ( const r : myRealtype;
  3150. const BCD : tBCD ) z : tBCD; Inline;
  3151. begin
  3152. BCDMultiply ( DoubleToBCD ( r ), BCD, z );
  3153. end;
  3154. {$endif}
  3155. operator * ( const BCD : tBCD;
  3156. const c : currency ) z : tBCD; Inline;
  3157. begin
  3158. BCDMultiply ( BCD, CurrToBCD ( c ), z );
  3159. end;
  3160. operator * ( const c : currency;
  3161. const BCD : tBCD ) z : tBCD; Inline;
  3162. begin
  3163. BCDMultiply ( CurrToBCD ( c ), BCD, z );
  3164. end;
  3165. {$ifdef comproutines}
  3166. operator * ( const BCD : tBCD;
  3167. const c : Comp ) z : tBCD; Inline;
  3168. begin
  3169. BCDMultiply ( BCD, CompToBCD ( c ), z );
  3170. end;
  3171. operator * ( const c : Comp;
  3172. const BCD : tBCD ) z : tBCD; Inline;
  3173. begin
  3174. BCDMultiply ( CompToBCD ( c ), BCD, z );
  3175. end;
  3176. {$endif}
  3177. operator * ( const BCD : tBCD;
  3178. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3179. begin
  3180. BCDMultiply ( BCD, StrToBCD ( s ), z );
  3181. end;
  3182. operator * ( const s : FmtBCDStringtype;
  3183. const BCD : tBCD ) z : tBCD; Inline;
  3184. begin
  3185. BCDMultiply ( StrToBCD ( s ), BCD, z );
  3186. end;
  3187. operator / ( const BCD1,
  3188. BCD2 : tBCD ) z : tBCD; Inline;
  3189. begin
  3190. BCDDivide ( BCD1, BCD2, z );
  3191. end;
  3192. operator / ( const BCD : tBCD;
  3193. const i : myInttype ) z : tBCD; Inline;
  3194. begin
  3195. BCDDivide ( BCD, i, z );
  3196. end;
  3197. operator / ( const i : myInttype;
  3198. const BCD : tBCD ) z : tBCD; Inline;
  3199. begin
  3200. BCDDivide ( IntegerToBCD ( i ), BCD, z );
  3201. end;
  3202. {$ifndef FPUNONE}
  3203. operator / ( const BCD : tBCD;
  3204. const r : myRealtype ) z : tBCD; Inline;
  3205. begin
  3206. BCDDivide ( BCD, DoubleToBCD ( r ), z );
  3207. end;
  3208. operator / ( const r : myRealtype;
  3209. const BCD : tBCD ) z : tBCD; Inline;
  3210. begin
  3211. BCDDivide ( DoubleToBCD ( r ), BCD, z );
  3212. end;
  3213. {$endif}
  3214. operator / ( const BCD : tBCD;
  3215. const c : currency ) z : tBCD; Inline;
  3216. begin
  3217. BCDDivide ( BCD, CurrToBCD ( c ), z );
  3218. end;
  3219. operator / ( const c : currency;
  3220. const BCD : tBCD ) z : tBCD; Inline;
  3221. begin
  3222. BCDDivide ( CurrToBCD ( c ), BCD, z );
  3223. end;
  3224. {$ifdef comproutines}
  3225. operator / ( const BCD : tBCD;
  3226. const c : Comp ) z : tBCD; Inline;
  3227. begin
  3228. BCDDivide ( BCD, CompToBCD ( c ), z );
  3229. end;
  3230. operator / ( const c : Comp;
  3231. const BCD : tBCD ) z : tBCD; Inline;
  3232. begin
  3233. BCDDivide ( CompToBCD ( c ), BCD, z );
  3234. end;
  3235. {$endif}
  3236. operator / ( const BCD : tBCD;
  3237. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3238. begin
  3239. BCDDivide ( BCD, StrToBCD ( s ), z );
  3240. end;
  3241. operator / ( const s : FmtBCDStringtype;
  3242. const BCD : tBCD ) z : tBCD; Inline;
  3243. begin
  3244. BCDDivide ( StrToBCD ( s ), BCD, z );
  3245. end;
  3246. operator := ( const i : Byte ) z : tBCD; Inline;
  3247. begin
  3248. z := IntegerToBCD ( myInttype ( i ) );
  3249. end;
  3250. operator := ( const BCD : tBCD ) z : Byte; Inline;
  3251. begin
  3252. z := BCDToInteger ( BCD );
  3253. end;
  3254. operator := ( const i : Word ) z : tBCD; Inline;
  3255. begin
  3256. z := IntegerToBCD ( myInttype ( i ) );
  3257. end;
  3258. operator := ( const BCD : tBCD ) z : Word; Inline;
  3259. begin
  3260. z := BCDToInteger ( BCD );
  3261. end;
  3262. operator := ( const i : longword ) z : tBCD; Inline;
  3263. begin
  3264. z := IntegerToBCD ( myInttype ( i ) );
  3265. end;
  3266. operator := ( const BCD : tBCD ) z : longword; Inline;
  3267. begin
  3268. z := BCDToInteger ( BCD );
  3269. end;
  3270. {$if declared ( qword ) }
  3271. operator := ( const i : qword ) z : tBCD; Inline;
  3272. begin
  3273. z := IntegerToBCD ( myInttype ( i ) );
  3274. end;
  3275. operator := ( const BCD : tBCD ) z : qword; Inline;
  3276. begin
  3277. z := BCDToInteger ( BCD );
  3278. end;
  3279. {$endif}
  3280. operator := ( const i : ShortInt ) z : tBCD; Inline;
  3281. begin
  3282. z := IntegerToBCD ( myInttype ( i ) );
  3283. end;
  3284. operator := ( const BCD : tBCD ) z : ShortInt; Inline;
  3285. begin
  3286. z := BCDToInteger ( BCD );
  3287. end;
  3288. operator := ( const i : smallint ) z : tBCD; Inline;
  3289. begin
  3290. z := IntegerToBCD ( myInttype ( i ) );
  3291. end;
  3292. operator := ( const BCD : tBCD ) z : smallint; Inline;
  3293. begin
  3294. z := BCDToInteger ( BCD );
  3295. end;
  3296. operator := ( const i : LongInt ) z : tBCD; Inline;
  3297. begin
  3298. z := IntegerToBCD ( myInttype ( i ) );
  3299. end;
  3300. operator := ( const BCD : tBCD ) z : LongInt; Inline;
  3301. begin
  3302. z := BCDToInteger ( BCD );
  3303. end;
  3304. {$if declared ( int64 ) }
  3305. operator := ( const i : int64 ) z : tBCD; Inline;
  3306. begin
  3307. z := IntegerToBCD ( myInttype ( i ) );
  3308. end;
  3309. operator := ( const BCD : tBCD ) z : int64; Inline;
  3310. begin
  3311. z := BCDToInteger ( BCD );
  3312. end;
  3313. {$endif}
  3314. {$ifndef FPUNONE}
  3315. operator := ( const r : Single ) z : tBCD; Inline;
  3316. begin
  3317. z := DoubleToBCD ( myRealtype ( r ) );
  3318. end;
  3319. operator := ( const BCD : tBCD ) z : Single; Inline;
  3320. begin
  3321. z := BCDToDouble ( BCD );
  3322. end;
  3323. operator := ( const r : Double ) z : tBCD; Inline;
  3324. begin
  3325. z := DoubleToBCD ( myRealtype ( r ) );
  3326. end;
  3327. operator := ( const BCD : tBCD ) z : Double; Inline;
  3328. begin
  3329. z := BCDToDouble ( BCD );
  3330. end;
  3331. {$if sizeof ( extended ) <> sizeof ( double )}
  3332. operator := ( const r : Extended ) z : tBCD; Inline;
  3333. begin
  3334. z := DoubleToBCD ( {myRealtype (} r {)} );
  3335. end;
  3336. operator := ( const BCD : tBCD ) z : Extended; Inline;
  3337. begin
  3338. z := BCDToDouble ( BCD );
  3339. end;
  3340. {$endif}
  3341. {$endif}
  3342. operator := ( const c : currency ) z : tBCD; Inline;
  3343. begin
  3344. CurrToBCD ( c, z );
  3345. end;
  3346. operator := ( const BCD : tBCD ) z : currency; Inline;
  3347. begin
  3348. BCDToCurr ( BCD, z );
  3349. end;
  3350. {$ifdef comproutines}
  3351. {$undef makedirect}
  3352. {$ifdef makedirect}
  3353. operator := ( const c : Comp ) z : tBCD; Inline;
  3354. var
  3355. cc : int64 absolute c;
  3356. begin
  3357. z := IntegerToBCD ( cc );
  3358. end;
  3359. { $define version1} { only one of these may be defined! }
  3360. { $define version2} { version 1 produces a compiler error (with INLINE only!)}
  3361. {$define version3} { I wasn't able to reduce the problem, sorry }
  3362. {$ifdef version1}
  3363. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3364. var
  3365. zz : Comp absolute z;
  3366. begin
  3367. zz := BCDToInteger ( BCD );
  3368. end;
  3369. {$endif}
  3370. {$ifdef version2}
  3371. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3372. var
  3373. zz : int64;
  3374. zzz : Comp absolute zz;
  3375. begin
  3376. zz := BCDToInteger ( BCD );
  3377. z := zzz;
  3378. end;
  3379. {$endif}
  3380. {$ifdef version3}
  3381. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3382. var
  3383. zz : record
  3384. case Boolean of
  3385. False: ( i : int64 );
  3386. True: ( c : Comp );
  3387. end;
  3388. begin
  3389. zz.i := BCDToInteger ( BCD );
  3390. z := zz.c;
  3391. end;
  3392. {$endif}
  3393. {$else}
  3394. operator := ( const c : Comp ) z : tBCD; Inline;
  3395. begin
  3396. z := CompToBCD ( c );
  3397. end;
  3398. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3399. begin
  3400. z := BCDToComp ( BCD );
  3401. end;
  3402. {$endif}
  3403. {$endif}
  3404. operator := ( const s : string ) z : tBCD; Inline;
  3405. begin
  3406. z := StrToBCD ( s );
  3407. end;
  3408. operator := ( const BCD : tBCD ) z : string; Inline;
  3409. begin
  3410. z := BCDToStr ( BCD );
  3411. end;
  3412. operator := ( const s : AnsiString ) z : tBCD; Inline;
  3413. begin
  3414. z := StrToBCD ( s );
  3415. end;
  3416. operator := ( const BCD : tBCD ) z : AnsiString; Inline;
  3417. begin
  3418. z := BCDToStr ( BCD );
  3419. end;
  3420. {$endif}
  3421. Function VariantToBCD(const VargSrc : TVarData) : TBCD;
  3422. begin
  3423. with VargSrc do
  3424. case vType and not varTypeMask of
  3425. 0: case vType of
  3426. varEmpty : Result := 0;
  3427. varSmallInt : Result := vSmallInt;
  3428. varShortInt : Result := vShortInt;
  3429. varInteger : Result := vInteger;
  3430. varSingle : Result := vSingle;
  3431. varDouble : Result := vDouble;
  3432. varCurrency : Result := vCurrency;
  3433. varDate : Result := vDate;
  3434. varBoolean : Result := Integer(vBoolean);
  3435. varVariant : Result := VariantToBCD(PVarData(vPointer)^);
  3436. varByte : Result := vByte;
  3437. varWord : Result := vWord;
  3438. varLongWord : Result := vLongWord;
  3439. varInt64 : Result := vInt64;
  3440. varQword : Result := vQWord;
  3441. varString : Result := AnsiString(vString);
  3442. varOleStr : Result := WideString(vOleStr);
  3443. varUString : Result := UnicodeString(vString);
  3444. else
  3445. if vType=VarFmtBCD then
  3446. Result := TFMTBcdVarData(vPointer).BCD
  3447. else
  3448. not_implemented;
  3449. end;
  3450. varByRef: if Assigned(vPointer) then case vType and varTypeMask of
  3451. varSmallInt : Result := PSmallInt(vPointer)^;
  3452. varShortInt : Result := PShortInt(vPointer)^;
  3453. varInteger : Result := PInteger(vPointer)^;
  3454. varSingle : Result := PSingle(vPointer)^;
  3455. varDouble : Result := PDouble(vPointer)^;
  3456. varCurrency : Result := PCurrency(vPointer)^;
  3457. varDate : Result := PDate(vPointer)^;
  3458. varBoolean : Result := SmallInt(PWordBool(vPointer)^);
  3459. varVariant : Result := VariantToBCD(PVarData(vPointer)^);
  3460. varByte : Result := PByte(vPointer)^;
  3461. varWord : Result := PWord(vPointer)^;
  3462. varLongWord : Result := PLongWord(vPointer)^;
  3463. varInt64 : Result := PInt64(vPointer)^;
  3464. varQword : Result := PQWord(vPointer)^;
  3465. else { other vtype }
  3466. not_implemented;
  3467. end else { pointer is nil }
  3468. not_implemented;
  3469. else { array or something like that }
  3470. not_implemented;
  3471. end;
  3472. end;
  3473. function VarToBCD ( const aValue : Variant ) : tBCD;
  3474. begin
  3475. Result:=VariantToBCD(TVarData(aValue));
  3476. end;
  3477. constructor TFMTBcdVarData.create;
  3478. begin
  3479. inherited create;
  3480. FBcd:=NullBCD;
  3481. end;
  3482. constructor TFMTBcdVarData.create(const BCD : tBCD);
  3483. begin
  3484. inherited create;
  3485. FBcd:=BCD;
  3486. end;
  3487. function TFMTBcdFactory.GetInstance(const v : TVarData): tObject;
  3488. begin
  3489. result:=tObject(v.VPointer);
  3490. end;
  3491. function TFMTBcdFactory.LeftPromotion(const V: TVarData; const Operation: TVarOp; out RequiredVarType: TVarType): Boolean;
  3492. // mantis 38496
  3493. begin
  3494. if v.vtype in FloatVarTypes then // floats can accept full result of a mixed float-bcd operation
  3495. RequiredVarType := v.vtype
  3496. else
  3497. RequiredVarType := VarType;
  3498. result:=true;
  3499. end;
  3500. procedure TFMTBcdFactory.BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp);
  3501. var l, r: TBCD;
  3502. begin
  3503. l:=VariantToBCD(Left);
  3504. r:=VariantToBCD(Right);
  3505. case Operation of
  3506. opAdd:
  3507. l:=l+r;
  3508. opSubtract:
  3509. l:=l-r;
  3510. opMultiply:
  3511. l:=l*r;
  3512. opDivide:
  3513. l:=l/r;
  3514. else
  3515. RaiseInvalidOp;
  3516. end;
  3517. if Left.vType = VarType then
  3518. TFMTBcdVarData(Left.VPointer).BCD := l
  3519. else if Left.vType = varDouble then
  3520. Left.vDouble := l
  3521. else
  3522. RaiseInvalidOp;
  3523. end;
  3524. procedure TFMTBcdFactory.Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult);
  3525. var l, r: TBCD;
  3526. CmpRes: integer;
  3527. begin
  3528. l:=VariantToBCD(Left);
  3529. r:=VariantToBCD(Right);
  3530. CmpRes := BCDCompare(l,r);
  3531. if CmpRes=0 then
  3532. Relationship := crEqual
  3533. else if CmpRes<0 then
  3534. Relationship := crLessThan
  3535. else
  3536. Relationship := crGreaterThan;
  3537. end;
  3538. function TFMTBcdFactory.CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean;
  3539. var l, r: TBCD;
  3540. begin
  3541. l:=VariantToBCD(Left);
  3542. r:=VariantToBCD(Right);
  3543. case Operation of
  3544. opCmpEq:
  3545. Result := l=r;
  3546. opCmpNe:
  3547. Result := l<>r;
  3548. opCmpLt:
  3549. Result := l<r;
  3550. opCmpLe:
  3551. Result := l<=r;
  3552. opCmpGt:
  3553. Result := l>r;
  3554. opCmpGe:
  3555. Result := l>=r;
  3556. else
  3557. RaiseInvalidOp;
  3558. end;
  3559. end;
  3560. procedure TFMTBcdFactory.Clear(var V: TVarData);
  3561. begin
  3562. FreeAndNil(tObject(V.VPointer));
  3563. V.VType:=varEmpty;
  3564. end;
  3565. procedure TFMTBcdFactory.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
  3566. begin
  3567. if Indirect then
  3568. Dest.VPointer:=Source.VPointer
  3569. else
  3570. Dest.VPointer:=TFMTBcdVarData.Create(TFMTBcdVarData(Source.VPointer).BCD);
  3571. Dest.VType:=VarType;
  3572. end;
  3573. procedure TFMTBcdFactory.Cast(var Dest: TVarData; const Source: TVarData);
  3574. begin
  3575. not_implemented;
  3576. end;
  3577. procedure TFMTBcdFactory.CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType);
  3578. var v: TVarData;
  3579. begin
  3580. if Source.vType=VarType then
  3581. if aVarType = varString then
  3582. VarDataFromStr(Dest, BCDToStr(TFMTBcdVarData(Source.vPointer).BCD))
  3583. else
  3584. begin
  3585. VarDataInit(v);
  3586. v.vType:=varDouble;
  3587. v.vDouble:=BCDToDouble(TFMTBcdVarData(Source.vPointer).BCD);
  3588. VarDataCastTo(Dest, v, aVarType); //now cast Double to any requested type
  3589. { finalizing v is not necessary here (Double is a simple type) }
  3590. end
  3591. else
  3592. inherited;
  3593. end;
  3594. {$if declared ( myMinIntBCD ) }
  3595. (*
  3596. {$if sizeof ( integer ) = 2 }
  3597. {$ifdef BCDgr4 }
  3598. const
  3599. myMinIntBCDValue : packed array [ 1..3 ] of Char = #$32#$76#$80;
  3600. {$endif}
  3601. {$else}
  3602. {$if sizeof ( integer ) = 4 }
  3603. *)
  3604. {$ifdef BCDgr9 }
  3605. const
  3606. myMinIntBCDValue : packed array [ 1..10 ] of Char = #$21#$47#$48#$36#$48;
  3607. {$endif}
  3608. (*
  3609. {$else}
  3610. {$if sizeof ( integer ) = 8 }
  3611. {$ifdef BCDgr18 }
  3612. const
  3613. myMinIntBCDValue : packed array [ 1..19 ] of Char = #$92#$23#$37#$20#$36#$85#$47#$75#$80#$80;
  3614. {$endif}
  3615. {$else}
  3616. {$fatal You have an interesting integer type! Sorry, not supported}
  3617. {$endif}
  3618. {$endif}
  3619. {$endif}
  3620. *)
  3621. {$endif}
  3622. initialization
  3623. FillChar ( null_, SizeOf ( null_ ), #0 );
  3624. FillChar ( NullBCD_, SizeOf ( NullBCD_ ), #0 );
  3625. FillChar ( OneBCD_, SizeOf ( OneBCD_ ), #0 );
  3626. OneBCD_.Precision := 1;
  3627. OneBCD_.Fraction[low ( OneBCD_.Fraction )] := $10;
  3628. {$if declared ( myMinIntBCD ) }
  3629. FillChar ( myMinIntBCD, SizeOf ( myMinIntBCD ), #0 );
  3630. {$ifndef bigger_BCD}
  3631. myMinIntBCD.SignSpecialPlaces := NegBit;
  3632. {$else}
  3633. myMinIntBCD.Negativ := True;
  3634. {$endif}
  3635. {$if sizeof ( integer ) = 2 }
  3636. {$ifdef BCDgr4 }
  3637. myMinIntBCD.Precision := 5;
  3638. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3639. {$endif}
  3640. {$else}
  3641. {$if sizeof ( integer ) = 4 }
  3642. {$ifdef BCDgr9 }
  3643. myMinIntBCD.Precision := 10;
  3644. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3645. {$endif}
  3646. {$else}
  3647. {$if sizeof ( integer ) = 8 }
  3648. {$ifdef BCDgr18 }
  3649. myMinIntBCD.Precision := 19;
  3650. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3651. {$endif}
  3652. {$else}
  3653. {$fatal You have an interesting integer type! Sorry, not supported}
  3654. {$endif}
  3655. {$endif}
  3656. {$endif}
  3657. {$endif}
  3658. FMTBcdFactory:=TFMTBcdFactory.create;
  3659. finalization
  3660. FreeAndNil(FMTBcdFactory)
  3661. end.