fmtbcd.pp 106 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768
  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. {$r+,q+,s+}
  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. {$note BCD Digits > 4}
  49. {$endif}
  50. {$ifdef BCDgr9}
  51. {$note BCD Digits > 9}
  52. {$endif}
  53. {$ifdef BCDgr18}
  54. {$note BCD Digits > 18}
  55. {$endif}
  56. {$ifdef BCDgr64}
  57. {$note BCD Digits > 64}
  58. {$endif}
  59. {$ifdef BCDgr180}
  60. {$note 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. { dateutils,}
  108. Variants;
  109. const
  110. MaxStringDigits = 100; { not used ! }
  111. _NoDecimal = -255; { not used ! }
  112. _DefaultDecimals = 10; { not used ! }
  113. { From DB.pas }
  114. { Max supported by Midas } { must be EVEN }
  115. MaxFmtBCDFractionSize = BCDMaxDigits + Ord ( Odd ( BCDMaxDigits ) );
  116. { Max supported by Midas }
  117. MaxFmtBCDDigits = 32; { not used ! }
  118. DefaultFmtBCDScale = 6; { not used ! }
  119. MaxBCDPrecision = 18; { not used ! }
  120. MaxBCDScale = 4; { not used ! }
  121. {$ifdef BCDgr64}
  122. { $fatal big 1}
  123. {$define bigger_BCD} { must be defined
  124. if MaxFmtBCDFractionSize > 64 }
  125. { not usable in the moment }
  126. {$endif}
  127. {$ifdef BCDgr180}
  128. { $fatal big 2}
  129. type
  130. FmtBCDStringtype = AnsiString;
  131. {$define use_Ansistring}
  132. {$else}
  133. type
  134. FmtBCDStringtype = string [ 255 ];
  135. {$undef use_Ansistring}
  136. {$endif}
  137. {$ifdef use_ansistring}
  138. {$note ansi}
  139. {$else}
  140. {$note -ansi}
  141. {$endif}
  142. {$ifdef integ32}
  143. {$define myInttype := LongInt}
  144. {$endif}
  145. {$ifdef integ64}
  146. {$define myInttype := int64}
  147. {$endif}
  148. {$ifdef real8}
  149. {$define myRealtype := double}
  150. {$endif}
  151. {$ifdef real10}
  152. {$define myRealtype := extended}
  153. {$endif}
  154. {$ifdef SUPPORT_COMP}
  155. {$define comproutines}
  156. {$endif SUPPORT_COMP}
  157. {$define __low_Fraction := 0 }
  158. {$define __high_Fraction := ( ( MaxFmtBCDFractionSize DIV 2 ) - 1 ) }
  159. type
  160. pBCD = ^ tBCD;
  161. tBCD = packed {$ifdef as_object} OBJECT {$else} record {$endif}
  162. {$ifdef as_object} PRIVATE {$endif}
  163. Precision : 0..maxfmtbcdfractionsize; { 1 (joke?)..64 }
  164. {$ifndef bigger_BCD}
  165. SignSpecialPlaces : Byte; { Sign:1, Special:1, Places:6 }
  166. {$else}
  167. Negativ : Boolean;
  168. {
  169. Special : Boolean;
  170. }
  171. Places : 0..maxfmtbcdfractionsize - 1;
  172. {$endif}
  173. Fraction : packed array [ __low_Fraction..__high_Fraction ] of Byte;
  174. { BCD Nibbles, 00..99 per Byte, high Nibble 1st }
  175. end;
  176. type
  177. tDecimalPoint = ( DecimalPoint_is_Point, DecimalPoint_is_Comma, DecimalPoint_is_System );
  178. { Exception classes }
  179. type
  180. eBCDException = CLASS ( Exception );
  181. eBCDOverflowException = CLASS ( eBCDException );
  182. eBCDNotImplementedException = CLASS ( eBCDException );
  183. var
  184. DecimalPoint : tDecimalPoint = DecimalPoint_is_Point;
  185. { Utility functions for TBCD access }
  186. function BCDPrecision ( const BCD : tBCD ) : Word; Inline;
  187. function BCDScale ( const BCD : tBCD ) : Word; Inline;
  188. function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline;
  189. { BCD Arithmetic}
  190. procedure BCDNegate ( var BCD : tBCD ); Inline;
  191. { !!!!!!!!!! most routines are intentionally NOT inline !!!!!!!!!! }
  192. { Returns True if successful, False if Int Digits needed to be truncated }
  193. function NormalizeBCD ( const InBCD : tBCD;
  194. var OutBCD : tBCD;
  195. const Prec,
  196. Scale : Word ) : Boolean;
  197. procedure BCDAdd ( const BCDin1,
  198. BCDin2 : tBCD;
  199. var BCDout : tBCD );
  200. procedure BCDSubtract ( const BCDin1,
  201. BCDin2 : tBCD;
  202. var BCDout : tBCD );
  203. procedure BCDMultiply ( const BCDin1,
  204. BCDin2 : tBCD;
  205. var BCDout : tBCD );
  206. procedure BCDMultiply ( const BCDIn : tBCD;
  207. const DoubleIn : myRealtype;
  208. var BCDout : tBCD ); Inline;
  209. procedure BCDMultiply ( const BCDIn : tBCD;
  210. const StringIn : FmtBCDStringtype;
  211. var BCDout : tBCD ); Inline;
  212. { !!! params changed to const, shouldn't give a problem }
  213. procedure BCDMultiply ( const StringIn1,
  214. StringIn2 : FmtBCDStringtype;
  215. var BCDout : tBCD ); Inline;
  216. procedure BCDDivide ( const Dividend,
  217. Divisor : tBCD;
  218. var BCDout : tBCD );
  219. procedure BCDDivide ( const Dividend : tBCD;
  220. const Divisor : myRealtype;
  221. var BCDout : tBCD ); Inline;
  222. procedure BCDDivide ( const Dividend : tBCD;
  223. const Divisor : FmtBCDStringtype;
  224. var BCDout : tBCD ); Inline;
  225. { !!! params changed to const, shouldn't give a problem }
  226. procedure BCDDivide ( const Dividend,
  227. Divisor : FmtBCDStringtype;
  228. var BCDout : tBCD ); Inline;
  229. { TBCD variant creation utils }
  230. procedure VarFmtBCDCreate ( var aDest : Variant;
  231. const aBCD : tBCD );
  232. function VarFmtBCDCreate : Variant;
  233. function VarFmtBCDCreate ( const aValue : FmtBCDStringtype;
  234. Precision,
  235. Scale : Word ) : Variant;
  236. function VarFmtBCDCreate ( const aValue : myRealtype;
  237. Precision : Word = 18;
  238. Scale : Word = 4 ) : Variant;
  239. function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant;
  240. function VarIsFmtBCD ( const aValue : Variant ) : Boolean;
  241. function VarFmtBCD : TVartype;
  242. { Convert string/Double/Integer to BCD struct }
  243. function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD;
  244. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  245. var BCD : tBCD ) : Boolean;
  246. function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline;
  247. procedure DoubleToBCD ( const aValue : myRealtype;
  248. var BCD : tBCD );
  249. function IntegerToBCD ( const aValue : myInttype ) : tBCD;
  250. function VarToBCD ( const aValue : Variant ) : tBCD;
  251. { From DB.pas }
  252. function CurrToBCD ( const Curr : currency;
  253. var BCD : tBCD;
  254. Precision : Integer = 32;
  255. Decimals : Integer = 4 ) : Boolean;
  256. { Convert BCD struct to string/Double/Integer }
  257. function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype;
  258. function BCDToDouble ( const BCD : tBCD ) : myRealtype;
  259. function BCDToInteger ( const BCD : tBCD;
  260. Truncate : Boolean = False ) : myInttype;
  261. { From DB.pas }
  262. function BCDToCurr ( const BCD : tBCD;
  263. var Curr : currency ) : Boolean;
  264. { Formatting BCD as string }
  265. function BCDToStrF ( const BCD : tBCD;
  266. Format : TFloatFormat;
  267. const Precision,
  268. Digits : Integer ) : FmtBCDStringtype;
  269. function FormatBCD ( const Format : string;
  270. BCD : tBCD ) : FmtBCDStringtype;
  271. { returns -1 if BCD1 < BCD2, 0 if BCD1 = BCD2, 1 if BCD1 > BCD2 }
  272. function BCDCompare ( const BCD1,
  273. BCD2 : tBCD ) : Integer;
  274. {$ifdef additional_routines}
  275. function CurrToBCD ( const Curr : currency ) : tBCD; Inline;
  276. {$ifdef comproutines}
  277. function CompToBCD ( const Curr : Comp ) : tBCD; Inline;
  278. function BCDToComp ( const BCD : tBCD ) : Comp; Inline;
  279. {$endif}
  280. procedure BCDAdd ( const BCDIn : tBCD;
  281. const IntIn : myInttype;
  282. var BCDout : tBCD );
  283. procedure BCDAdd ( const IntIn : myInttype;
  284. const BCDIn : tBCD;
  285. var BCDout : tBCD ); Inline;
  286. procedure BCDAdd ( const BCDIn : tBCD;
  287. const DoubleIn : myRealtype;
  288. var BCDout : tBCD ); Inline;
  289. procedure BCDAdd ( const DoubleIn : myRealtype;
  290. const BCDIn : tBCD;
  291. var BCDout : tBCD ); Inline;
  292. procedure BCDAdd ( const BCDIn : tBCD;
  293. const Currin : currency;
  294. var BCDout : tBCD ); Inline;
  295. procedure BCDAdd ( const Currin : currency;
  296. const BCDIn : tBCD;
  297. var BCDout : tBCD ); Inline;
  298. {$ifdef comproutines}
  299. procedure BCDAdd ( const BCDIn : tBCD;
  300. const Compin : Comp;
  301. var BCDout : tBCD ); Inline;
  302. procedure BCDAdd ( const Compin : Comp;
  303. const BCDIn : tBCD;
  304. var BCDout : tBCD ); Inline;
  305. {$endif}
  306. procedure BCDAdd ( const BCDIn : tBCD;
  307. const StringIn : FmtBCDStringtype;
  308. var BCDout : tBCD ); Inline;
  309. procedure BCDAdd ( const StringIn : FmtBCDStringtype;
  310. const BCDIn : tBCD;
  311. var BCDout : tBCD ); Inline;
  312. procedure BCDAdd ( const StringIn1,
  313. StringIn2 : FmtBCDStringtype;
  314. var BCDout : tBCD ); Inline;
  315. procedure BCDSubtract ( const BCDIn : tBCD;
  316. const IntIn : myInttype;
  317. var BCDout : tBCD );
  318. procedure BCDSubtract ( const IntIn : myInttype;
  319. const BCDIn : tBCD;
  320. var BCDout : tBCD ); Inline;
  321. procedure BCDSubtract ( const BCDIn : tBCD;
  322. const DoubleIn : myRealtype;
  323. var BCDout : tBCD ); Inline;
  324. procedure BCDSubtract ( const DoubleIn : myRealtype;
  325. const BCDIn : tBCD;
  326. var BCDout : tBCD ); Inline;
  327. procedure BCDSubtract ( const BCDIn : tBCD;
  328. const Currin : currency;
  329. var BCDout : tBCD ); Inline;
  330. procedure BCDSubtract ( const Currin : currency;
  331. const BCDIn : tBCD;
  332. var BCDout : tBCD ); Inline;
  333. {$ifdef comproutines}
  334. procedure BCDSubtract ( const BCDIn : tBCD;
  335. const Compin : Comp;
  336. var BCDout : tBCD ); Inline;
  337. procedure BCDSubtract ( const Compin : Comp;
  338. const BCDIn : tBCD;
  339. var BCDout : tBCD ); Inline;
  340. {$endif}
  341. procedure BCDSubtract ( const BCDIn : tBCD;
  342. const StringIn : FmtBCDStringtype;
  343. var BCDout : tBCD ); Inline;
  344. procedure BCDSubtract ( const StringIn : FmtBCDStringtype;
  345. const BCDIn : tBCD;
  346. var BCDout : tBCD ); Inline;
  347. procedure BCDSubtract ( const StringIn1,
  348. StringIn2 : FmtBCDStringtype;
  349. var BCDout : tBCD ); Inline;
  350. procedure BCDMultiply ( const BCDIn : tBCD;
  351. const IntIn : myInttype;
  352. var BCDout : tBCD );
  353. procedure BCDMultiply ( const IntIn : myInttype;
  354. const BCDIn : tBCD;
  355. var BCDout : tBCD ); Inline;
  356. procedure BCDMultiply ( const DoubleIn : myRealtype;
  357. const BCDIn : tBCD;
  358. var BCDout : tBCD ); Inline;
  359. procedure BCDMultiply ( const BCDIn : tBCD;
  360. const Currin : currency;
  361. var BCDout : tBCD ); Inline;
  362. procedure BCDMultiply ( const Currin : currency;
  363. const BCDIn : tBCD;
  364. var BCDout : tBCD ); Inline;
  365. {$ifdef comproutines}
  366. procedure BCDMultiply ( const BCDIn : tBCD;
  367. const Compin : Comp;
  368. var BCDout : tBCD ); Inline;
  369. procedure BCDMultiply ( const Compin : Comp;
  370. const BCDIn : tBCD;
  371. var BCDout : tBCD ); Inline;
  372. {$endif}
  373. procedure BCDMultiply ( const StringIn : FmtBCDStringtype;
  374. const BCDIn : tBCD;
  375. var BCDout : tBCD ); Inline;
  376. procedure BCDDivide ( const Dividend : tBCD;
  377. const Divisor : myInttype;
  378. var BCDout : tBCD ); Inline;
  379. procedure BCDDivide ( const Dividend : myInttype;
  380. const Divisor : tBCD;
  381. var BCDout : tBCD ); Inline;
  382. procedure BCDDivide ( const Dividend : myRealtype;
  383. const Divisor : tBCD;
  384. var BCDout : tBCD ); Inline;
  385. procedure BCDDivide ( const BCDIn : tBCD;
  386. const Currin : currency;
  387. var BCDout : tBCD ); Inline;
  388. procedure BCDDivide ( const Currin : currency;
  389. const BCDIn : tBCD;
  390. var BCDout : tBCD ); Inline;
  391. {$ifdef comproutines}
  392. procedure BCDDivide ( const BCDIn : tBCD;
  393. const Compin : Comp;
  394. var BCDout : tBCD ); Inline;
  395. procedure BCDDivide ( const Compin : Comp;
  396. const BCDIn : tBCD;
  397. var BCDout : tBCD ); Inline;
  398. {$endif}
  399. procedure BCDDivide ( const Dividend : FmtBCDStringtype;
  400. const Divisor : tBCD;
  401. var BCDout : tBCD ); Inline;
  402. operator = ( const BCD1,
  403. BCD2 : tBCD ) z : Boolean; Inline;
  404. operator < ( const BCD1,
  405. BCD2 : tBCD ) z : Boolean; Inline;
  406. operator > ( const BCD1,
  407. BCD2 : tBCD ) z : Boolean; Inline;
  408. operator <= ( const BCD1,
  409. BCD2 : tBCD ) z : Boolean; Inline;
  410. operator >= ( const BCD1,
  411. BCD2 : tBCD ) z : Boolean; Inline;
  412. (* ######################## not allowed: why?
  413. operator + ( const BCD : tBCD ) z : tBCD; make_Inline
  414. ##################################################### *)
  415. operator - ( const BCD : tBCD ) z : tBCD; Inline;
  416. operator + ( const BCD1,
  417. BCD2 : tBCD ) z : tBCD; Inline;
  418. operator + ( const BCD : tBCD;
  419. const i : myInttype ) z : tBCD; Inline;
  420. operator + ( const i : myInttype;
  421. const BCD : tBCD ) z : tBCD; Inline;
  422. operator + ( const BCD : tBCD;
  423. const r : myRealtype ) z : tBCD; Inline;
  424. operator + ( const r : myRealtype;
  425. const BCD : tBCD ) z : tBCD; Inline;
  426. operator + ( const BCD : tBCD;
  427. const c : currency ) z : tBCD; Inline;
  428. operator + ( const c : currency;
  429. const BCD : tBCD ) z : tBCD; Inline;
  430. {$ifdef comproutines}
  431. operator + ( const BCD : tBCD;
  432. const c : Comp ) z : tBCD; Inline;
  433. operator + ( const c : Comp;
  434. const BCD : tBCD ) z : tBCD; Inline;
  435. {$endif}
  436. operator + ( const BCD : tBCD;
  437. const s : FmtBCDStringtype ) z : tBCD; Inline;
  438. operator + ( const s : FmtBCDStringtype;
  439. const BCD : tBCD ) z : tBCD; Inline;
  440. operator - ( const BCD1,
  441. BCD2 : tBCD ) z : tBCD; Inline;
  442. operator - ( const BCD : tBCD;
  443. const i : myInttype ) z : tBCD; Inline;
  444. operator - ( const i : myInttype;
  445. const BCD : tBCD ) z : tBCD; Inline;
  446. operator - ( const BCD : tBCD;
  447. const r : myRealtype ) z : tBCD; Inline;
  448. operator - ( const r : myRealtype;
  449. const BCD : tBCD ) z : tBCD; Inline;
  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. operator * ( const BCD : tBCD;
  471. const r : myRealtype ) z : tBCD; Inline;
  472. operator * ( const r : myRealtype;
  473. const BCD : tBCD ) z : tBCD; Inline;
  474. operator * ( const BCD : tBCD;
  475. const c : currency ) z : tBCD; Inline;
  476. operator * ( const c : currency;
  477. const BCD : tBCD ) z : tBCD; Inline;
  478. {$ifdef comproutines}
  479. operator * ( const BCD : tBCD;
  480. const c : Comp ) z : tBCD; Inline;
  481. operator * ( const c : Comp;
  482. const BCD : tBCD ) z : tBCD; Inline;
  483. {$endif}
  484. operator * ( const BCD : tBCD;
  485. const s : FmtBCDStringtype ) z : tBCD; Inline;
  486. operator * ( const s : FmtBCDStringtype;
  487. const BCD : tBCD ) z : tBCD; Inline;
  488. operator / ( const BCD1,
  489. BCD2 : tBCD ) z : tBCD; Inline;
  490. operator / ( const BCD : tBCD;
  491. const i : myInttype ) z : tBCD; Inline;
  492. operator / ( const i : myInttype;
  493. const BCD : tBCD ) z : tBCD; Inline;
  494. operator / ( const BCD : tBCD;
  495. const r : myRealtype ) z : tBCD; Inline;
  496. operator / ( const r : myRealtype;
  497. const BCD : tBCD ) z : tBCD; Inline;
  498. operator / ( const BCD : tBCD;
  499. const c : currency ) z : tBCD; Inline;
  500. operator / ( const c : currency;
  501. const BCD : tBCD ) z : tBCD; Inline;
  502. {$ifdef comproutines}
  503. operator / ( const BCD : tBCD;
  504. const c : Comp ) z : tBCD; Inline;
  505. operator / ( const c : Comp;
  506. const BCD : tBCD ) z : tBCD; Inline;
  507. {$endif}
  508. operator / ( const BCD : tBCD;
  509. const s : FmtBCDStringtype ) z : tBCD; Inline;
  510. operator / ( const s : FmtBCDStringtype;
  511. const BCD : tBCD ) z : tBCD; Inline;
  512. operator := ( const i : Byte ) z : tBCD; Inline;
  513. operator := ( const BCD : tBCD ) z : Byte; Inline;
  514. operator := ( const i : Word ) z : tBCD; Inline;
  515. operator := ( const BCD : tBCD ) z : Word; Inline;
  516. operator := ( const i : longword ) z : tBCD; Inline;
  517. operator := ( const BCD : tBCD ) z : longword; Inline;
  518. {$if declared ( qword ) }
  519. operator := ( const i : qword ) z : tBCD; Inline;
  520. operator := ( const BCD : tBCD ) z : qword; Inline;
  521. {$endif}
  522. operator := ( const i : ShortInt ) z : tBCD; Inline;
  523. operator := ( const BCD : tBCD ) z : ShortInt; Inline;
  524. operator := ( const i : smallint ) z : tBCD; Inline;
  525. operator := ( const BCD : tBCD ) z : smallint; Inline;
  526. operator := ( const i : LongInt ) z : tBCD; Inline;
  527. operator := ( const BCD : tBCD ) z : LongInt; Inline;
  528. {$if declared ( int64 ) }
  529. operator := ( const i : int64 ) z : tBCD; Inline;
  530. operator := ( const BCD : tBCD ) z : int64; Inline;
  531. {$endif}
  532. operator := ( const r : Single ) z : tBCD; Inline;
  533. operator := ( const BCD : tBCD ) z : Single; Inline;
  534. operator := ( const r : Double ) z : tBCD; Inline;
  535. operator := ( const BCD : tBCD ) z : Double; Inline;
  536. {$if sizeof ( extended ) <> sizeof ( double )}
  537. operator := ( const r : Extended ) z : tBCD; Inline;
  538. operator := ( const BCD : tBCD ) z : Extended; Inline;
  539. {$endif}
  540. operator := ( const c : currency ) z : tBCD; Inline;
  541. operator := ( const BCD : tBCD ) z : currency; Inline;
  542. {$ifdef comproutines}
  543. operator := ( const c : Comp ) z : tBCD; Inline;
  544. operator := ( const BCD : tBCD ) z : Comp; Inline;
  545. {$endif}
  546. operator := ( const s : string ) z : tBCD; Inline;
  547. operator := ( const BCD : tBCD ) z : string; Inline;
  548. operator := ( const s : AnsiString ) z : tBCD; Inline;
  549. operator := ( const BCD : tBCD ) z : AnsiString; Inline;
  550. {$endif}
  551. function __get_null : tBCD; Inline;
  552. function __get_one : tBCD; Inline;
  553. PROPERTY
  554. NullBCD : tBCD Read __get_null;
  555. OneBCD : tBCD Read __get_one;
  556. //{$define __lo_bh := 1 * ( -( MaxFmtBCDFractionSize * 1 + 2 ) ) }
  557. //{$define __hi_bh := 1 * ( MaxFmtBCDFractionSize * 1 + 1 ) }
  558. {$define helper_declarations :=
  559. const
  560. __lo_bh = -( MaxFmtBCDFractionSize + 2 );
  561. __hi_bh = ( MaxFmtBCDFractionSize + 1 );
  562. type
  563. tBCD_helper = Maybe_Packed record
  564. Prec : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif};
  565. Plac : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif};
  566. FDig,
  567. LDig : {$ifopt r+} __lo_bh..__hi_bh {$else} Integer {$endif};
  568. Singles : Maybe_packed array [ __lo_bh..__hi_bh ]
  569. of {$ifopt r+} 0..9 {$else} Byte {$endif};
  570. Neg : Boolean;
  571. end;
  572. { in the tBCD_helper the bcd is stored for computations,
  573. shifted to the right position }
  574. { {$define __lo_bhb := 1 * ( __lo_bh + __lo_bh ) } }
  575. { {$define __hi_bhb := 1 * ( __hi_bh + __hi_bh + 1 ) } }
  576. const
  577. __lo_bhb = __lo_bh + __lo_bh - 1;
  578. __hi_bhb = __hi_bh + __hi_bh;
  579. type
  580. tBCD_helper_big = Maybe_Packed record
  581. Prec : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif};
  582. Plac : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif};
  583. FDig,
  584. LDig : {$ifopt r+} __lo_bhb..__hi_bhb {$else} Integer {$endif};
  585. Singles : Maybe_packed array [ __lo_bhb..__hi_bhb ]
  586. of {$ifopt r+} 0 * 0..9 * 9 * Pred ( MaxFmtBCDDigits ) {$else} Integer {$endif};
  587. Neg : Boolean;
  588. end;
  589. }
  590. {$ifdef debug_version}
  591. helper_declarations
  592. procedure unpack_BCD ( const BCD : tBCD;
  593. var bh : tBCD_helper );
  594. function pack_BCD ( var bh : tBCD_helper;
  595. var BCD : tBCD ) : Boolean;
  596. procedure dumpBCD ( const v : tBCD );
  597. {$endif}
  598. IMPLEMENTATION
  599. USES
  600. classes;
  601. type
  602. TFMTBcdFactory = CLASS(TPublishableVarianttype)
  603. PROTECTED
  604. function GetInstance(const v : TVarData): tObject; OVERRIDE;
  605. PUBLIC
  606. procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp);
  607. end;
  608. TFMTBcdVarData = CLASS(TPersistent)
  609. PRIVATE
  610. FBcd : tBCD;
  611. PUBLIC
  612. constructor create;
  613. constructor create(const BCD : tBCD);
  614. PROPERTY BCD : tBCD Read FBcd Write FBcd;
  615. end;
  616. var
  617. NullBCD_ : tBCD;
  618. OneBCD_ : tBCD;
  619. function __get_null : tBCD; Inline;
  620. begin
  621. __get_null := NullBCD_;
  622. end;
  623. function __get_one : tBCD; Inline;
  624. begin
  625. __get_one := OneBCD_;
  626. end;
  627. type
  628. range_digits = 1..maxfmtbcdfractionsize;
  629. range_digits0 = 0..maxfmtbcdfractionsize;
  630. range_fracdigits = 0..pred ( MaxFmtBCDFractionSize );
  631. {$ifopt r+}
  632. var
  633. rcheck : 0..0;
  634. rbad : Byte = 1;
  635. {$endif}
  636. {$ifndef debug_version}
  637. helper_declarations
  638. {$endif}
  639. var
  640. null_ : record
  641. case Boolean of
  642. False: ( bh : tBCD_helper );
  643. True: ( bhb : tBCD_helper_big );
  644. end;
  645. FMTBcdFactory : TFMTBcdFactory = NIL;
  646. {$ifndef bigger_BCD}
  647. const
  648. NegBit = 1 SHL 7;
  649. SpecialBit = 1 SHL 6;
  650. PlacesMask = $ff XOR ( NegBit OR SpecialBit );
  651. {$endif}
  652. {$define _select := {$define _when := if {$define _when := end else if } }
  653. {$define _then := then begin }
  654. {$define _whenother := end else begin }
  655. {$define _endselect := end } }
  656. {$ifdef debug_version}
  657. procedure dumpBCD ( const v : tBCD );
  658. var
  659. i,
  660. j : Integer;
  661. const
  662. ft : ARRAY [ Boolean ] of Char = ( 'f', 't' );
  663. begin
  664. {$ifndef bigger_BCD}
  665. Write ( 'Prec:', v.Precision, ' ',
  666. 'Neg:', ft[( v.SignSpecialPlaces AND NegBit ) <> 0], ' ',
  667. 'Special:', ft[( v.SignSpecialPlaces AND SpecialBit ) <> 0], ' ',
  668. 'Places:', v.SignSpecialPlaces AND PlacesMask, ' ' );
  669. {$else}
  670. Write ( 'Prec:', v.Precision, ' ',
  671. 'Neg:', ft[v.Negativ], ' ',
  672. 'Places:', v.Places, ' ' );
  673. {$endif}
  674. j := 0;
  675. for i := 1 TO v.Precision do
  676. if Odd ( i )
  677. then Write ( ( v.Fraction[j] AND $f0 ) SHR 4 )
  678. else begin
  679. Write ( v.Fraction[j] AND $0f );
  680. Inc ( j );
  681. end;
  682. WriteLn;
  683. end;
  684. procedure dumpbh ( const v : tBCD_helper );
  685. var
  686. i : Integer;
  687. const
  688. ft : ARRAY [ Boolean ] of Char = ( 'f', 't' );
  689. begin
  690. Write ( 'Prec:', v.Prec, ' ',
  691. 'Neg:', ft[v.Neg], ' ',
  692. 'Places:', v.Plac, ' ',
  693. 'FDig:', v.FDig, ' ',
  694. 'LDig:', v.LDig, ' ',
  695. 'Digits:', v.LDig - v.FDig + 1, ' ' );
  696. for i := v.FDig TO v.LDig do
  697. Write ( v.Singles[i] );
  698. WriteLn;
  699. end;
  700. {$endif}
  701. {$if sizeof ( integer ) = 2 }
  702. {$ifdef BCDgr4 }
  703. var
  704. myMinIntBCD : tBCD;
  705. {$endif}
  706. {$else}
  707. {$if sizeof ( integer ) = 4 }
  708. {$ifdef BCDgr9 }
  709. var
  710. myMinIntBCD : tBCD;
  711. {$endif}
  712. {$else}
  713. {$if sizeof ( integer ) = 8 }
  714. {$ifdef BCDgr18 }
  715. var
  716. myMinIntBCD : tBCD;
  717. {$endif}
  718. {$else}
  719. {$fatal You have an interesting integer type! Sorry, not supported}
  720. {$endif}
  721. {$endif}
  722. {$endif}
  723. procedure not_implemented;
  724. begin
  725. RAISE eBCDNotImplementedException.create ( 'not implemented' );
  726. end;
  727. procedure unpack_BCD ( const BCD : tBCD;
  728. var bh : tBCD_helper );
  729. var
  730. i : {$ifopt r+} __lo_bh + 1 ..__hi_bh {$else} Integer {$endif};
  731. j : {$ifopt r+} -1..__high_fraction {$else} Integer {$endif};
  732. vv : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  733. begin
  734. bh := null_.bh;
  735. WITH bh,
  736. BCD do
  737. begin
  738. Prec := Precision;
  739. if Prec > 0
  740. then begin
  741. {$ifndef bigger_BCD}
  742. Plac := SignSpecialPlaces AND PlacesMask;
  743. Neg := ( SignSpecialPlaces AND NegBit ) <> 0;
  744. {$else}
  745. Plac := Places;
  746. Neg := Negativ;
  747. {$endif}
  748. LDig := Plac;
  749. FDig := LDig - Prec + 1;
  750. j := -1;
  751. i := FDig;
  752. while i <= LDig do
  753. begin
  754. Inc ( j );
  755. vv := Fraction[j];
  756. Singles[i] := ( vv {AND $f0} ) SHR 4;
  757. if i < LDig
  758. then Singles[i+1] := vv AND $0f;
  759. Inc ( i, 2 );
  760. end;
  761. end;
  762. end;
  763. end;
  764. function pack_BCD ( var bh : tBCD_helper;
  765. var BCD : tBCD ) : Boolean;
  766. { return TRUE if successful (BCD valid) }
  767. var
  768. pre : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 {$else} Integer {$endif};
  769. fra : {$ifopt r+} -1 * ( __hi_bh - __lo_bh + 1 )..__hi_bh - __lo_bh + 1 {$else} Integer {$endif};
  770. tm : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 - Pred ( MaxFmtBCDFractionSize ) {$else} Integer {$endif};
  771. i : {$ifopt r+} low ( bh.FDig ) - 1..high ( bh.LDig ) {$else} Integer {$endif};
  772. rp : {$ifopt r+} low ( BCD.Fraction )..high ( BCD.Fraction ) + 1 {$else} Integer {$endif};
  773. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  774. v : {$ifopt r+} 0..10 {$else} Integer {$endif};
  775. lnz : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  776. doround,
  777. lnzf : Boolean;
  778. begin
  779. pack_BCD := False;
  780. BCD := NullBCD;
  781. WITH BCD,
  782. bh do
  783. begin
  784. lnzf := FDig < 0;
  785. while lnzf do
  786. if Singles[FDig] = 0
  787. then begin
  788. Inc ( FDig );
  789. if FDig = 0
  790. then lnzf := False;
  791. end
  792. else lnzf := False;
  793. pre := LDig - FDig + 1;
  794. fra := Plac;
  795. doround := False;
  796. if fra >= MaxFmtBCDFractionSize
  797. then begin
  798. doround := True;
  799. tm := fra - Pred ( MaxFmtBCDFractionSize );
  800. { dec ( pre, tm ); Dec/Inc error? }
  801. pre := pre - tm;
  802. { Dec ( fra, tm ); Dec/Inc error? }
  803. fra := fra - tm;
  804. { Dec ( LDig, tm ); Dec/Inc error? }
  805. LDig := LDig - tm;
  806. end;
  807. if pre > MaxFmtBCDFractionSize
  808. then begin
  809. doround := True;
  810. tm := pre - MaxFmtBCDFractionSize;
  811. { Dec ( pre, tm ); Dec/Inc error? }
  812. pre := pre - tm;
  813. { Dec ( fra, tm ); Dec/Inc error? }
  814. fra := fra - tm;
  815. { Dec ( LDig, tm ); Dec/Inc error? }
  816. LDig := LDig - tm;
  817. end;
  818. if fra < 0
  819. then EXIT;
  820. if doround
  821. then begin
  822. v := Singles[fra + 1];
  823. if v > 4
  824. then begin
  825. ue := 1;
  826. i := LDig;
  827. while ( i >= FDig ) AND ( ue <> 0 ) do
  828. begin
  829. v := Singles[i] + ue;
  830. ue := v DIV 10;
  831. Singles[i] := v MOD 10;
  832. Dec ( i );
  833. end;
  834. if ue <> 0
  835. then begin
  836. Dec ( FDig );
  837. Singles[FDig] := ue;
  838. Dec ( LDig );
  839. Dec ( fra );
  840. if fra < 0
  841. then EXIT;
  842. end;
  843. end;
  844. end;
  845. lnzf := False;
  846. i := LDig;
  847. while ( i >= FDig ) AND ( NOT lnzf ) do
  848. begin
  849. if Singles[i] <> 0
  850. then begin
  851. lnz := i;
  852. lnzf := True;
  853. end;
  854. Dec ( i );
  855. end;
  856. if lnzf
  857. then begin
  858. tm := LDig - lnz;
  859. if tm <> 0
  860. then begin
  861. { Dec ( pre, tm ); Dec/Inc error? }
  862. pre := pre - tm;
  863. { Dec ( fra, tm ); Dec/Inc error? }
  864. fra := fra - tm;
  865. { Dec ( LDig, tm ); Dec/Inc error? }
  866. LDig := LDig - tm;
  867. if fra < 0
  868. then begin
  869. { Dec ( pre, fra ); Dec/Inc error? }
  870. pre := pre - fra;
  871. { Dec ( LDig, fra ); Dec/Inc error? }
  872. LDig := LDig - fra;
  873. fra := 0;
  874. end;
  875. end;
  876. end
  877. else begin
  878. LDig := FDig;
  879. fra := 0;
  880. pre := 0;
  881. Neg := False;
  882. end;
  883. if pre <> 0
  884. then begin
  885. Precision := pre;
  886. rp := 0;
  887. i := FDig;
  888. while i <= LDig do
  889. begin
  890. if i < LDig
  891. then Fraction[rp] := ( Singles[i] SHL 4 ) OR Singles[i + 1]
  892. else Fraction[rp] := Singles[i] SHL 4;
  893. Inc ( rp );
  894. Inc ( i, 2 );
  895. end;
  896. {$ifndef bigger_BCD}
  897. if Neg
  898. then SignSpecialPlaces := NegBit;
  899. SignSpecialPlaces := SignSpecialPlaces OR fra;
  900. {$else}
  901. Negativ := Neg;
  902. Places := fra;
  903. {$endif}
  904. end;
  905. end;
  906. pack_BCD := True;
  907. end;
  908. procedure SetDecimals ( var dp,
  909. dc : Char );
  910. begin
  911. case DecimalPoint of
  912. DecimalPoint_is_Point: begin
  913. dp := '.';
  914. dc := ',';
  915. end;
  916. DecimalPoint_is_Comma: begin
  917. dp := ',';
  918. dc := '.';
  919. end;
  920. { find out language-specific ? }
  921. DecimalPoint_is_System: begin
  922. dp := DecimalSeparator;
  923. dc := ThousandSeparator;
  924. end;
  925. end;
  926. end;
  927. function BCDPrecision ( const BCD : tBCD ) : Word; Inline;
  928. begin
  929. BCDPrecision := BCD.Precision;
  930. end;
  931. function BCDScale ( const BCD : tBCD ) : Word; Inline;
  932. begin
  933. {$ifndef bigger_BCD}
  934. BCDScale := BCD.SignSpecialPlaces AND PlacesMask;
  935. {$else}
  936. BCDScale := BCD.Places;
  937. {$endif}
  938. end;
  939. function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline;
  940. begin
  941. {$ifndef bigger_BCD}
  942. IsBCDNegative := ( BCD.SignSpecialPlaces AND NegBit ) <> 0;
  943. {$else}
  944. IsBCDNegative := BCD.Negativ;
  945. {$endif}
  946. end;
  947. { BCD Arithmetic}
  948. procedure BCDNegate ( var BCD : tBCD ); Inline;
  949. begin
  950. { with-statement geht nicht !!
  951. with bcd do
  952. if precision <> 0
  953. then signspecialplaces := signspecialplaces xor negbit;
  954. }
  955. if BCD.Precision <> 0
  956. then
  957. {$ifndef bigger_BCD}
  958. BCD.SignSpecialPlaces := BCD.SignSpecialPlaces XOR NegBit;
  959. {$else}
  960. BCD.Negativ := NOT BCD.Negativ;
  961. {$endif}
  962. end;
  963. { returns -1 if BCD1 < BCD2, 0 if BCD1 = BCD2, 1 if BCD1 > BCD2 }
  964. function BCDCompare ( const BCD1,
  965. BCD2 : tBCD ) : Integer;
  966. var
  967. pl1 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  968. pl2 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  969. pr1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  970. pr2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  971. pr : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  972. idig1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  973. idig2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  974. i : {$ifopt r+} __low_Fraction..__high_Fraction + 1 {$else} Integer {$endif};
  975. f1 : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  976. f2 : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  977. res : {$ifopt r+} -1..1 {$else} Integer {$endif};
  978. neg1,
  979. neg2 : Boolean;
  980. begin
  981. {$ifndef bigger_BCD}
  982. neg1 := ( BCD1.SignSpecialPlaces AND NegBit ) <> 0;
  983. neg2 := ( BCD2.SignSpecialPlaces AND NegBit ) <> 0;
  984. {$else}
  985. neg1 := BCD1.Negativ;
  986. neg2 := BCD2.Negativ;
  987. {$endif}
  988. _SELECT
  989. _WHEN neg1 AND ( NOT neg2 )
  990. _THEN result := -1;
  991. _WHEN ( NOT neg1 ) AND neg2
  992. _THEN result := +1;
  993. _WHENOTHER
  994. pr1 := BCD1.Precision;
  995. pr2 := BCD2.Precision;
  996. {$ifndef bigger_BCD}
  997. pl1 := BCD1.SignSpecialPlaces AND PlacesMask;
  998. pl2 := BCD2.SignSpecialPlaces AND PlacesMask;
  999. {$else}
  1000. pl1 := BCD1.Places;
  1001. pl2 := BCD2.Places;
  1002. {$endif}
  1003. idig1 := pr1 - pl1;
  1004. idig2 := pr2 - pl2;
  1005. if idig1 <> idig2
  1006. then begin
  1007. if ( idig1 > idig2 ) = neg1
  1008. then result := -1
  1009. else result := +1;
  1010. end
  1011. else begin
  1012. if pr1 < pr2
  1013. then pr := pr1
  1014. else pr := pr2;
  1015. res := 0;
  1016. i := __low_Fraction;
  1017. while ( res = 0 ) AND ( i < ( __low_Fraction + ( pr DIV 2 ) ) ) do
  1018. begin
  1019. {
  1020. if BCD1.Fraction[i] < BCD2.Fraction[i]
  1021. then res := -1
  1022. else
  1023. if BCD1.Fraction[i] > BCD2.Fraction[i]
  1024. then res := +1;
  1025. }
  1026. _SELECT
  1027. _WHEN BCD1.Fraction[i] < BCD2.Fraction[i]
  1028. _THEN res := -1
  1029. _WHEN BCD1.Fraction[i] > BCD2.Fraction[i]
  1030. _THEN res := +1;
  1031. _WHENOTHER
  1032. _endSELECT;
  1033. Inc ( i );
  1034. end;
  1035. if res = 0
  1036. then begin
  1037. if Odd ( pr )
  1038. then begin
  1039. f1 := BCD1.Fraction[i] AND $f0;
  1040. f2 := BCD2.Fraction[i] AND $f0;
  1041. {
  1042. if f1 < f2
  1043. then res := -1
  1044. else
  1045. if f1 > f2
  1046. then res := +1;
  1047. }
  1048. _SELECT
  1049. _WHEN f1 < f2
  1050. _THEN res := -1
  1051. _WHEN f1 > f2
  1052. _THEN res := +1;
  1053. _endSELECT;
  1054. end;
  1055. end;
  1056. if neg1
  1057. then result := 0 - res
  1058. else result := res;
  1059. end;
  1060. _endSELECT
  1061. end;
  1062. { Convert string/Double/Integer to BCD struct }
  1063. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  1064. var BCD : tBCD ) : Boolean;
  1065. { shall this return TRUE when error and FALSE when o.k. or the other way round ? }
  1066. var
  1067. {$ifndef use_ansistring}
  1068. lav : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1069. i : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1070. {$else}
  1071. lav : {$ifopt r+} longword {$else} longword {$endif};
  1072. i : {$ifopt r+} longword {$else} longword {$endif};
  1073. {$endif}
  1074. ch : Char;
  1075. dp,
  1076. dc : Char;
  1077. type
  1078. ife = ( inint, infrac, inexp );
  1079. {$define max_exp_scanned := 9999 }
  1080. var
  1081. inife : ife;
  1082. lvars : record
  1083. fp,
  1084. lp : ARRAY [ ife ]
  1085. {$ifndef use_ansistring}
  1086. of {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1087. pfnb : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1088. ps : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1089. pse : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1090. errp : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1091. {$else}
  1092. of {$ifopt r+} longword {$else} longword {$endif};
  1093. pfnb : {$ifopt r+} longword {$else} longword {$endif};
  1094. ps : {$ifopt r+} longword {$else} longword {$endif};
  1095. pse : {$ifopt r+} longword {$else} longword {$endif};
  1096. errp : {$ifopt r+} longword {$else} longword {$endif};
  1097. {$endif}
  1098. exp : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1099. p : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1100. bh : tBCD_helper;
  1101. nbf : Boolean;
  1102. end;
  1103. begin
  1104. result := False;
  1105. FillChar ( lvars, SizeOf ( lvars ), #0 );
  1106. BCD := NullBCD;
  1107. lav := Length ( aValue );
  1108. if lav <> 0
  1109. then
  1110. WITH lvars,
  1111. bh do
  1112. begin
  1113. SetDecimals ( dp, dc );
  1114. while ( pfnb < lav ) AND ( NOT nbf ) do
  1115. begin
  1116. Inc ( pfnb );
  1117. nbf := aValue[pfnb] <> ' ';
  1118. end;
  1119. if nbf
  1120. then begin
  1121. if aValue[pfnb] IN [ '+', '-' ]
  1122. then begin
  1123. ps := pfnb;
  1124. Inc ( pfnb );
  1125. end;
  1126. inife := low ( inife );
  1127. for i := pfnb TO lav do
  1128. begin
  1129. ch := aValue[i];
  1130. case ch of
  1131. '0'..'9': begin
  1132. case inife of
  1133. inint,
  1134. inexp: if fp[inife] = 0
  1135. then begin
  1136. if ch <> '0'
  1137. then begin
  1138. fp[inife] := i;
  1139. lp[inife] := i;
  1140. end;
  1141. end
  1142. else lp[inife] := i;
  1143. infrac: begin
  1144. if fp[infrac] = 0
  1145. then fp[infrac] := i;
  1146. if ch <> '0'
  1147. then lp[infrac] := i;
  1148. end;
  1149. end;
  1150. end;
  1151. ',',
  1152. '.': if ch = dp
  1153. then begin
  1154. if inife <> inint
  1155. then result := True
  1156. else inife := infrac;
  1157. end;
  1158. 'e',
  1159. 'E': if inife = inexp
  1160. then result := True
  1161. else inife := inexp;
  1162. '+',
  1163. '-': if ( inife = inexp ) AND ( fp[inexp] = 0 )
  1164. then pse := i
  1165. else result := True;
  1166. else begin
  1167. result := True;
  1168. errp := i;
  1169. end;
  1170. end;
  1171. end;
  1172. if result
  1173. then begin
  1174. result := False;
  1175. for i := errp TO lav do
  1176. if aValue[i] <> ' '
  1177. then result := True;
  1178. end;
  1179. if result
  1180. then EXIT;
  1181. if ps <> 0
  1182. then Neg := aValue[ps] = '-';
  1183. if lp[infrac] = 0
  1184. then fp[infrac] := 0;
  1185. if fp[inexp] <> 0
  1186. then begin
  1187. exp := 0;
  1188. for i := fp[inexp] TO lp[inexp] do
  1189. if NOT result
  1190. then
  1191. if aValue[i] <> dc
  1192. then begin
  1193. exp := exp * 10 + ( Ord ( aValue[i] ) - Ord ( '0' ) );
  1194. if exp > 999
  1195. then result := True;
  1196. end;
  1197. if result
  1198. then EXIT;
  1199. if pse <> 0
  1200. then
  1201. if aValue[pse] = '-'
  1202. then exp := -exp;
  1203. end;
  1204. p := -exp;
  1205. if fp[infrac] <> 0
  1206. then begin
  1207. for i := fp[infrac] TO lp[infrac] do
  1208. if aValue[i] <> dc
  1209. then begin
  1210. if p < ( MaxFmtBCDFractionSize + 2 )
  1211. then begin
  1212. Inc ( p );
  1213. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1214. end;
  1215. end;
  1216. end;
  1217. LDig := p;
  1218. p := 1 - exp;
  1219. if fp[inint] <> 0
  1220. then
  1221. for i := lp[inint] DOWNTO fp[inint] do
  1222. if aValue[i] <> dc
  1223. then begin
  1224. if p > - ( MaxFmtBCDFractionSize + 2 )
  1225. then begin
  1226. Dec ( p );
  1227. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1228. end
  1229. else result := True;
  1230. end;
  1231. if result
  1232. then EXIT;
  1233. FDig := p;
  1234. if LDig < 0
  1235. then LDig := 0;
  1236. Plac := LDig;
  1237. result := NOT pack_BCD ( bh, BCD );
  1238. end;
  1239. end;
  1240. end;
  1241. function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD;
  1242. var
  1243. BCD : tBCD;
  1244. begin
  1245. if TryStrToBCD ( aValue, BCD )
  1246. then begin
  1247. RAISE eBCDOverflowException.create ( 'in StrToBCD' );
  1248. end
  1249. else StrToBCD := BCD;
  1250. end;
  1251. procedure DoubleToBCD ( const aValue : myRealtype;
  1252. var BCD : tBCD );
  1253. var
  1254. s : string [ 30 ];
  1255. dp : tDecimalPoint;
  1256. begin
  1257. Str ( aValue : 25, s );
  1258. dp := DecimalPoint;
  1259. DecimalPoint := DecimalPoint_is_Point;
  1260. BCD := StrToBCD ( s );
  1261. DecimalPoint := dp;
  1262. end;
  1263. function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline;
  1264. begin
  1265. DoubleToBCD ( aValue, result );
  1266. end;
  1267. function IntegerToBCD ( const aValue : myInttype ) : tBCD;
  1268. var
  1269. bh : tBCD_helper;
  1270. v : {$ifopt r+} 0..high ( myInttype ) {$else} Integer {$endif};
  1271. p : {$ifopt r+} low ( bh.Singles ) - 1..0 {$else} Integer {$endif};
  1272. Error,
  1273. exitloop : Boolean;
  1274. begin
  1275. _SELECT
  1276. _WHEN aValue = 0
  1277. _THEN result := NullBCD;
  1278. _WHEN aValue = 1
  1279. _THEN result := OneBCD;
  1280. _WHEN aValue = low ( myInttype )
  1281. _THEN
  1282. {$if declared ( myMinIntBCD ) }
  1283. result := myMinIntBCD;
  1284. {$else}
  1285. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1286. {$endif}
  1287. _WHENOTHER
  1288. bh := null_.bh;
  1289. WITH bh do
  1290. begin
  1291. Neg := aValue < 0;
  1292. if Neg
  1293. then v := -aValue
  1294. else v := +aValue;
  1295. LDig := 0;
  1296. p := 0;
  1297. Error := False;
  1298. REPEAT
  1299. Singles[p] := v MOD 10;
  1300. v := v DIV 10;
  1301. exitloop := v = 0;
  1302. Dec ( p );
  1303. if p < low ( Singles )
  1304. then begin
  1305. exitloop := True;
  1306. Error := True;
  1307. (* what to do if error occured? *)
  1308. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1309. end;
  1310. UNTIL exitloop;
  1311. FDig := p + 1;
  1312. end;
  1313. pack_BCD ( bh, result );
  1314. _endSELECT;
  1315. end;
  1316. function VarToBCD ( const aValue : Variant ) : tBCD;
  1317. begin
  1318. not_implemented;
  1319. end;
  1320. function CurrToBCD ( const Curr : currency;
  1321. var BCD : tBCD;
  1322. Precision : Integer = 32;
  1323. Decimals : Integer = 4 ) : Boolean;
  1324. {
  1325. this works under the assumption that a currency is an int64,
  1326. except for scale of 10000
  1327. }
  1328. var
  1329. i : int64 absolute Curr;
  1330. begin
  1331. BCD := IntegerToBCD ( i );
  1332. {$ifndef bigger_BCD}
  1333. BCD.SignSpecialPlaces := 4 OR ( BCD.SignSpecialPlaces AND NegBit );
  1334. {$else}
  1335. BCD.Places := 4;
  1336. {$endif}
  1337. if Decimals <> 4 then
  1338. Result := NormalizeBCD ( BCD, BCD, Precision, Decimals )
  1339. else
  1340. CurrToBCD := True;
  1341. end;
  1342. {$ifdef comproutines}
  1343. function CompToBCD ( const Curr : Comp ) : tBCD; Inline;
  1344. var
  1345. cc : int64 absolute Curr;
  1346. begin
  1347. result := IntegerToBCD ( cc );
  1348. end;
  1349. function BCDToComp ( const BCD : tBCD ) : Comp; Inline;
  1350. var
  1351. zz : record
  1352. case Boolean of
  1353. False: ( i : int64 );
  1354. True: ( c : Comp );
  1355. end;
  1356. begin
  1357. zz.i := BCDToInteger ( BCD );
  1358. BCDToComp := zz.c;
  1359. end;
  1360. {$endif}
  1361. { Convert BCD struct to string/Double/Integer }
  1362. function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype;
  1363. var
  1364. bh : tBCD_helper;
  1365. l : {$ifopt r+} 0..maxfmtbcdfractionsize + 1 + 1 {$else} Integer {$endif};
  1366. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1367. pp : {$ifopt r+} low ( bh.FDig ) - 1..1 {$else} Integer {$endif};
  1368. begin
  1369. {$ifdef use_ansistring}
  1370. result := '';
  1371. {$endif}
  1372. unpack_BCD ( BCD, bh );
  1373. WITH bh do
  1374. begin
  1375. l := 0;
  1376. if Neg
  1377. then begin
  1378. {$ifndef use_ansistring}
  1379. Inc ( l );
  1380. result[1] := '-';
  1381. {$else}
  1382. result := result + '-';
  1383. {$endif}
  1384. end;
  1385. if Prec = Plac
  1386. then begin
  1387. {$ifndef use_ansistring}
  1388. Inc ( l );
  1389. result[1] := '0';
  1390. {$else}
  1391. result := result + '0';
  1392. {$endif}
  1393. end;
  1394. if Prec > 0
  1395. then begin
  1396. pp := low ( bh.FDig ) - 1;
  1397. if Plac > 0
  1398. then pp := 1;
  1399. for i := FDig TO LDig do
  1400. begin
  1401. if i = pp
  1402. then begin
  1403. {$ifndef use_ansistring}
  1404. Inc ( l );
  1405. result[l] := '.';
  1406. {$else}
  1407. result := result + '.';
  1408. {$endif}
  1409. end;
  1410. {$ifndef use_ansistring}
  1411. Inc ( l );
  1412. result[l] := Chr ( Singles[i] + Ord ( '0' ) );
  1413. {$else}
  1414. result := result + Chr ( Singles[i] + Ord ( '0' ) );
  1415. {$endif}
  1416. end;
  1417. end;
  1418. end;
  1419. {$ifndef use_ansistring}
  1420. result[0] := Chr ( l );
  1421. {$endif}
  1422. end;
  1423. function BCDToDouble ( const BCD : tBCD ) : myRealtype;
  1424. var
  1425. bh : tBCD_helper;
  1426. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1427. r,
  1428. e : myRealtype;
  1429. begin
  1430. unpack_BCD ( BCD, bh );
  1431. WITH bh do
  1432. begin
  1433. r := 0;
  1434. e := 1;
  1435. for i := 0 DOWNTO FDig do
  1436. begin
  1437. r := r + Singles[i] * e;
  1438. e := e * 10;
  1439. end;
  1440. e := 1;
  1441. for i := 1 TO LDig do
  1442. begin
  1443. e := e / 10;
  1444. r := r + Singles[i] * e;
  1445. end;
  1446. if Neg
  1447. then BCDToDouble := -r
  1448. else BCDToDouble := +r;
  1449. end;
  1450. end;
  1451. function BCDToInteger ( const BCD : tBCD;
  1452. Truncate : Boolean = False ) : myInttype;
  1453. var
  1454. bh : tBCD_helper;
  1455. res : myInttype;
  1456. i : {$ifopt r+} low ( bh.FDig )..0 {$else} Integer {$endif};
  1457. {
  1458. unclear: behaviour if overflow: abort? return 0? return something?
  1459. so: checks are missing yet
  1460. }
  1461. begin
  1462. unpack_BCD ( BCD, bh );
  1463. res := 0;
  1464. WITH bh do
  1465. begin
  1466. for i := FDig TO 0 do
  1467. res := res * 10 - Singles[i];
  1468. if NOT Truncate
  1469. then
  1470. if Plac > 0
  1471. then
  1472. if Singles[1] > 4
  1473. then Dec ( res );
  1474. if Neg
  1475. then BCDToInteger := +res
  1476. else BCDToInteger := -res;
  1477. end;
  1478. end;
  1479. { From DB.pas }
  1480. function BCDToCurr ( const BCD : tBCD;
  1481. var Curr : currency ) : Boolean;
  1482. var
  1483. bh : tBCD_helper;
  1484. res : int64;
  1485. c : currency absolute res;
  1486. i : {$ifopt r+} low ( bh.FDig )..4 {$else} Integer {$endif};
  1487. {
  1488. unclear: behaviour if overflow: abort? return 0? return something?
  1489. }
  1490. begin
  1491. BCDToCurr := True;
  1492. unpack_BCD ( BCD, bh );
  1493. res := 0;
  1494. WITH bh do
  1495. begin
  1496. for i := FDig TO 4 do
  1497. res := res * 10 + Singles[i];
  1498. if Plac > 4
  1499. then
  1500. if Singles[5] > 4
  1501. then Inc ( res );
  1502. if Neg
  1503. then Curr := -c
  1504. else Curr := +c;
  1505. end;
  1506. end;
  1507. procedure BCDAdd ( const BCDin1,
  1508. BCDin2 : tBCD;
  1509. var BCDout : tBCD );
  1510. var
  1511. bhr,
  1512. bh1,
  1513. bh2 : tBCD_helper;
  1514. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1515. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1516. v : {$ifopt r+} 0..9 + 9 + 1 {$else} Integer {$endif};
  1517. BCD : tBCD;
  1518. negate : Boolean;
  1519. begin
  1520. negate := IsBCDNegative ( BCDin1 );
  1521. if negate <> IsBCDNegative ( BCDin2 )
  1522. then begin
  1523. if negate
  1524. then begin
  1525. BCD := BCDin1;
  1526. BCDNegate ( BCD );
  1527. BCDSubtract ( BCDin2, BCD, BCDout );
  1528. EXIT;
  1529. end;
  1530. BCD := BCDin2;
  1531. BCDNegate ( BCD );
  1532. BCDSubtract ( BCDin1, BCD, BCDout );
  1533. EXIT;
  1534. end;
  1535. bhr := null_.bh;
  1536. WITH bhr do
  1537. begin
  1538. unpack_BCD ( BCDin1, bh1 );
  1539. unpack_BCD ( BCDin2, bh2 );
  1540. if bh1.FDig < bh2.FDig
  1541. then FDig := bh1.FDig
  1542. else FDig := bh2.FDig;
  1543. if bh1.LDig > bh2.LDig
  1544. then LDig := bh1.LDig
  1545. else LDig := bh2.LDig;
  1546. Plac := LDig;
  1547. ue := 0;
  1548. for i := LDig DOWNTO FDig do
  1549. begin
  1550. v := bh1.Singles[i] + bh2.Singles[i] + ue;
  1551. ue := v DIV 10;
  1552. Singles[i] := v MOD 10;
  1553. end;
  1554. if ue <> 0
  1555. then begin
  1556. Dec ( FDig );
  1557. Singles[FDig] := ue;
  1558. end;
  1559. Neg := negate;
  1560. end;
  1561. if NOT pack_BCD ( bhr, BCDout )
  1562. then begin
  1563. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  1564. end;
  1565. end;
  1566. procedure BCDSubtract ( const BCDin1,
  1567. BCDin2 : tBCD;
  1568. var BCDout : tBCD );
  1569. var
  1570. bhr,
  1571. bh1,
  1572. bh2 : tBCD_helper;
  1573. cmp : {$ifopt r+} -1..1 {$else} Integer {$endif};
  1574. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1575. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1576. v : {$ifopt r+} 0 - 9 - 1..9 - 0 - 0 {$else} Integer {$endif};
  1577. negate : Boolean;
  1578. BCD : tBCD;
  1579. begin
  1580. negate := IsBCDNegative ( BCDin1 );
  1581. if negate <> IsBCDNegative ( BCDin2 )
  1582. then begin
  1583. if negate
  1584. then begin
  1585. BCD := BCDin1;
  1586. BCDNegate ( BCD );
  1587. BCDAdd ( BCDin2, BCD, BCDout );
  1588. BCDNegate ( BCDout );
  1589. EXIT;
  1590. end;
  1591. BCD := BCDin2;
  1592. BCDNegate ( BCD );
  1593. BCDAdd ( BCDin1, BCD, BCDout );
  1594. EXIT;
  1595. end;
  1596. cmp := BCDCompare ( BCDin1, BCDin2 );
  1597. if cmp = 0
  1598. then begin
  1599. BCDout := NullBCD;
  1600. EXIT;
  1601. end;
  1602. bhr := null_.bh; { n n }
  1603. WITH bhr do { > < > < }
  1604. begin { }
  1605. if ( cmp > 0 ) = negate { +123 +12 -12 -123 }
  1606. then begin { - +12 - +123 - -123 - -12 }
  1607. unpack_BCD ( BCDin1, bh2 ); { x x }
  1608. unpack_BCD ( BCDin2, bh1 ); { s s s s }
  1609. negate := NOT negate; { nn n nn n }
  1610. end
  1611. else begin
  1612. unpack_BCD ( BCDin1, bh1 );
  1613. unpack_BCD ( BCDin2, bh2 );
  1614. end;
  1615. if bh1.FDig < bh2.FDig
  1616. then FDig := bh1.FDig
  1617. else FDig := bh2.FDig;
  1618. if bh1.LDig > bh2.LDig
  1619. then LDig := bh1.LDig
  1620. else LDig := bh2.LDig;
  1621. Plac := LDig;
  1622. ue := 0;
  1623. for i := LDig DOWNTO FDig do
  1624. begin
  1625. v := Integer ( bh1.Singles[i] ) - bh2.Singles[i] - ue;
  1626. ue := 0;
  1627. if v < 0
  1628. then begin
  1629. ue := 1;
  1630. Inc ( v, 10 );
  1631. end;
  1632. Singles[i] := v;
  1633. end;
  1634. Neg := negate;
  1635. if NOT pack_BCD ( bhr, BCDout )
  1636. then begin
  1637. {should never occur!}
  1638. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  1639. end;
  1640. end;
  1641. end;
  1642. { Returns True if successful, False if Int Digits needed to be truncated }
  1643. function NormalizeBCD ( const InBCD : tBCD;
  1644. var OutBCD : tBCD;
  1645. const Prec,
  1646. Scale : Word ) : Boolean;
  1647. var
  1648. bh : tBCD_helper;
  1649. tm : {$ifopt r+} 1..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  1650. begin
  1651. NormalizeBCD := True;
  1652. {$ifopt r+}
  1653. if ( Prec < 0 ) OR ( Prec > MaxFmtBCDFractionSize ) then rcheck := rbad;
  1654. if ( Scale < 0 ) OR ( Prec >= MaxFmtBCDFractionSize ) then rcheck := rbad;
  1655. {$endif}
  1656. if BCDScale ( InBCD ) > Scale
  1657. then begin
  1658. unpack_BCD ( InBCD, bh );
  1659. WITH bh do
  1660. begin
  1661. tm := Plac - Scale;
  1662. Plac := Scale;
  1663. { dec ( prec, tm ); Dec/Inc error? }
  1664. Prec := Prec - tm;
  1665. { dec ( ldig, tm ); Dec/Inc error? }
  1666. LDig := LDig - tm;
  1667. NormalizeBCD := False;
  1668. end;
  1669. if NOT pack_BCD ( bh, OutBCD )
  1670. then begin
  1671. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  1672. end;
  1673. end;
  1674. end;
  1675. procedure BCDMultiply ( const BCDin1,
  1676. BCDin2 : tBCD;
  1677. var BCDout : tBCD );
  1678. var
  1679. bh1,
  1680. bh2,
  1681. bhr : tBCD_helper;
  1682. bhrr : tBCD_helper_big;
  1683. i1 : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1684. i2 : {$ifopt r+} low ( bh2.FDig )..high ( bh2.LDig ) {$else} Integer {$endif};
  1685. i3 : {$ifopt r+} low ( bhrr.FDig )..high ( bhrr.LDig ) {$else} Integer {$endif};
  1686. v : {$ifopt r+} low ( bhrr.Singles[0] )..high ( bhrr.Singles[0] ) {$else} Integer {$endif};
  1687. ue : {$ifopt r+} low ( bhrr.Singles[0] ) DIV 10..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  1688. begin
  1689. unpack_BCD ( BCDin1, bh1 );
  1690. unpack_BCD ( BCDin2, bh2 );
  1691. if ( bh1.Prec = 0 ) OR ( bh2.Prec = 0 )
  1692. then begin
  1693. BCDout := NullBCD;
  1694. EXIT;
  1695. end;
  1696. bhr := null_.bh;
  1697. bhrr := null_.bhb;
  1698. WITH bhrr do
  1699. begin
  1700. Neg := bh1.Neg XOR bh2.Neg;
  1701. {
  1702. writeln ( __lo_bhb, ' ', __hi_bhb, ' ', bh1.fdig, ' ', bh2.fdig, ' ', low ( fdig ), ' ', low ( ldig ) );
  1703. }
  1704. FDig := bh1.FDig + bh2.FDig;
  1705. LDig := bh1.LDig + bh2.LDig;
  1706. for i1 := bh1.FDig TO bh1.LDig do
  1707. for i2 := bh2.FDig TO bh2.LDig do
  1708. begin
  1709. Inc ( Singles[i1 + i2],
  1710. bh1.Singles[i1]
  1711. * bh2.Singles[i2] );
  1712. {
  1713. write ( Singles[i1 + i2], ' ', bh1.Singles[i1], ' ', bh2.Singles[i2], ' : ' );
  1714. writeln ( Singles[i1 + i2] + bh1.Singles[i1] + bh2.Singles[i2] );
  1715. }
  1716. {
  1717. Singles[i1 + i2] := Singles[i1 + i2]
  1718. + bh1.Singles[i1]
  1719. * bh2.Singles[i2];
  1720. }
  1721. end;
  1722. {
  1723. for i3 := fdig to ldig do
  1724. write ( ' ', singles[i3] );
  1725. writeln;
  1726. }
  1727. if FDig < low ( bhr.Singles )
  1728. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1729. ue := 0;
  1730. for i3 := LDig DOWNTO FDig do
  1731. begin
  1732. v := Singles[i3] + ue;
  1733. ue := v DIV 10;
  1734. v := v MOD 10;
  1735. bhr.Singles[i3] := v;
  1736. end;
  1737. while ue <> 0 do
  1738. begin
  1739. Dec ( FDig );
  1740. if FDig < low ( bhr.Singles )
  1741. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1742. bhr.Singles[FDig] := ue MOD 10;
  1743. ue := ue DIV 10;
  1744. end;
  1745. bhr.Plac := LDig;
  1746. bhr.FDig := FDig;
  1747. if LDig > high ( bhr.Singles )
  1748. then bhr.LDig := high ( bhr.Singles )
  1749. else bhr.LDig := LDig;
  1750. end;
  1751. if NOT pack_BCD ( bhr, BCDout )
  1752. then begin
  1753. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1754. end;
  1755. end;
  1756. procedure BCDMultiply ( const BCDIn : tBCD;
  1757. const DoubleIn : myRealtype;
  1758. var BCDout : tBCD ); Inline;
  1759. begin
  1760. BCDMultiply ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  1761. end;
  1762. procedure BCDMultiply ( const BCDIn : tBCD;
  1763. const StringIn : FmtBCDStringtype;
  1764. var BCDout : tBCD ); Inline;
  1765. begin
  1766. BCDMultiply ( BCDIn, StrToBCD ( StringIn ), BCDout );
  1767. end;
  1768. procedure BCDMultiply ( const StringIn1,
  1769. StringIn2 : FmtBCDStringtype;
  1770. var BCDout : tBCD ); Inline;
  1771. begin
  1772. BCDMultiply ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  1773. end;
  1774. procedure BCDDivide ( const Dividend,
  1775. Divisor : tBCD;
  1776. var BCDout : tBCD );
  1777. var
  1778. bh1 : ARRAY [ Boolean ] of tBCD_helper;
  1779. bh2,
  1780. bh : tBCD_helper;
  1781. p : {$ifopt r+} low ( bh.FDig ) - high ( bh.FDig )..high ( bh.FDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1782. v1 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1783. v2 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1784. lFDig : {$ifopt r+} low ( bh.FDig )..high ( bh.FDig ) {$else} Integer {$endif};
  1785. d1 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1786. d2 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1787. d : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1788. lLdig : {$ifopt r+} low ( lFDig ) + low ( d )..high ( lFDig ) + high ( d ) {$else} Integer {$endif};
  1789. tm : {$ifopt r+} low ( lLdig ) - high ( bh2.Singles )..high ( lLdig ) - high ( bh2.Singles ) {$else} Integer {$endif};
  1790. i2 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1791. i3 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1792. ie : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1793. i4 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1794. nFDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1795. nLDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1796. dd : {$ifopt r+} 0..9 {$else} Integer {$endif};
  1797. Add : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1798. ue : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1799. 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};
  1800. v4 : {$ifopt r+} low ( bh.Singles[0] ) + low ( add )..high ( bh.Singles[0] ) + high ( add ) {$else} Integer {$endif};
  1801. FlipFlop,
  1802. nz,
  1803. sf,
  1804. sh,
  1805. fdset : Boolean;
  1806. {
  1807. bh1p : ARRAY [ Boolean ] of ^ tBCD_helper;
  1808. }
  1809. begin
  1810. { test:
  1811. bh1p[false] := @ bh1[false];
  1812. bh1p[true] := @ bh1[true];
  1813. v := bh1[false].singles[0];
  1814. v := bh1[true].singles[0];
  1815. v := bh1p[false]^.singles[0];
  1816. v := bh1p[true]^.singles[0];
  1817. v := bh1[nz].singles[0];
  1818. v := bh1p[nz]^.singles[0];
  1819. }
  1820. unpack_BCD ( Divisor, bh2 );
  1821. unpack_BCD ( Dividend, bh1[False] );
  1822. p := bh1[False].FDig - bh2.FDig;
  1823. _SELECT
  1824. _WHEN bh2.Prec = 0
  1825. _THEN RAISE eBCDException.create ( 'Division by zero' );
  1826. _WHEN bh1[False].Prec = 0
  1827. _THEN BCDout := NullBCD;
  1828. _WHEN p < low ( bh2.Singles )
  1829. _THEN RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  1830. _WHENOTHER
  1831. bh := null_.bh;
  1832. bh.Neg := bh1[False].Neg XOR bh2.Neg;
  1833. if p <= high ( bh.Singles )
  1834. then begin
  1835. bh1[True] := null_.bh;
  1836. FlipFlop := False;
  1837. fdset := p > 0;
  1838. if fdset
  1839. then bh.FDig := 0;
  1840. add := 0;
  1841. nz := True;
  1842. while nz do
  1843. WITH bh1[FlipFlop] do
  1844. begin
  1845. {
  1846. WriteLn('#####');
  1847. dumpbh ( bh1[flipflop] );
  1848. dumpbh ( bh2 );
  1849. dumpbh ( bh );
  1850. }
  1851. if ( Singles[FDig] + bh2.Singles[bh2.FDig] ) = 0
  1852. then begin
  1853. if ( FDig >= LDig )
  1854. OR ( bh2.FDig >= bh2.LDig )
  1855. then nz := False
  1856. else begin
  1857. Inc ( FDig );
  1858. Inc ( bh2.FDig );
  1859. end;
  1860. end
  1861. else begin
  1862. v1 := Singles[FDig];
  1863. v2 := bh2.Singles[bh2.FDig];
  1864. sh := v1 < v2;
  1865. if ( v1 = v2 )
  1866. then begin
  1867. nz := False;
  1868. i3 := Succ ( FDig );
  1869. ie := LDig;
  1870. while ( i3 <= ie ) AND ( NOT nz ) AND ( NOT sh ) do
  1871. begin
  1872. v1 := Singles[i3];
  1873. v2 := bh2.Singles[i3 - p];
  1874. if v1 <> v2
  1875. then begin
  1876. nz := True;
  1877. if v1 < v2
  1878. then sh := True;
  1879. end;
  1880. Inc ( i3 );
  1881. end;
  1882. end;
  1883. if NOT nz
  1884. then Add := 1
  1885. else begin
  1886. if sh
  1887. then begin
  1888. Inc ( p );
  1889. {
  1890. if p > 3 then halt;
  1891. }
  1892. if p > high ( bh.Singles )
  1893. then nz := False
  1894. else Dec ( bh2.FDig );
  1895. end
  1896. else begin
  1897. lFDig := FDig;
  1898. d1 := LDig - FDig;
  1899. d2 := bh2.LDig - bh2.FDig;
  1900. if d1 > d2
  1901. then d := d1
  1902. else d := d2;
  1903. lLdig := lFDig + d;
  1904. if lLdig > high ( bh2.Singles )
  1905. then begin
  1906. tm := ( lLdig ) - high ( bh2.Singles );
  1907. d := d - tm;
  1908. lLdig := lLdig - tm;
  1909. {runden?}
  1910. end;
  1911. sf := True;
  1912. Add := 0;
  1913. nFDig := 0;
  1914. nLDig := 0;
  1915. ue := 0;
  1916. dd := Singles[lFDig] DIV ( bh2.Singles[lFDig - p] + 1 );
  1917. {
  1918. dd := 1;
  1919. }
  1920. if dd < 1
  1921. then dd := 1;
  1922. {
  1923. writeln ( 'p=', p, ' dd=', dd, ' lFdig=', lfdig, ' lldig=', lldig );
  1924. }
  1925. for i2 := lLdig DOWNTO lFDig do
  1926. begin
  1927. v3 := Singles[i2] - bh2.Singles[i2 - p] * dd - ue;
  1928. ue := 0;
  1929. while v3 < 0 do
  1930. begin
  1931. Inc ( ue );;
  1932. v3 := v3 + 10;
  1933. end;
  1934. {
  1935. if v3 <> 0
  1936. then begin
  1937. }
  1938. bh1[NOT FlipFlop].Singles[i2] := v3;
  1939. {
  1940. nFDig := i2;
  1941. if sf
  1942. then begin
  1943. nLDig := i2;
  1944. sf := False;
  1945. end;
  1946. end;
  1947. }
  1948. end;
  1949. sf := False;
  1950. nfdig := lfdig;
  1951. nldig := lldig;
  1952. Inc ( Add, dd );
  1953. if NOT fdset
  1954. then begin
  1955. bh.FDig := p;
  1956. fdset := True;
  1957. end;
  1958. if bh.LDig < p
  1959. then begin
  1960. bh.LDig := p;
  1961. if ( bh.LDig - bh.FDig ) > Succ ( MaxFmtBCDFractionSize )
  1962. then nz := False;
  1963. end;
  1964. if sf
  1965. then nz := False
  1966. else begin
  1967. FillChar ( bh1[FlipFlop], SizeOf ( bh1[FlipFlop] ), #0 );
  1968. FlipFlop := NOT FlipFlop;
  1969. WITH bh1[FlipFlop] do
  1970. begin
  1971. FDig := nFDig;
  1972. LDig := nLDig;
  1973. end;
  1974. end;
  1975. end;
  1976. end;
  1977. if Add <> 0
  1978. then begin
  1979. i4 := p;
  1980. while ( Add <> 0 ) AND ( i4 >= bh.FDig ) do
  1981. begin
  1982. {
  1983. writeln ( '> ', i4, ' ', bh.Singles[i4], ' ', Add );
  1984. }
  1985. v4 := bh.Singles[i4] + Add;
  1986. Add := v4 DIV 10;
  1987. bh.Singles[i4] := v4 MOD 10;
  1988. Dec ( i4 );
  1989. end;
  1990. if Add <> 0
  1991. then begin
  1992. Dec ( bh.FDig );
  1993. bh.Singles[bh.FDig] := Add;
  1994. Add := 0;
  1995. end;
  1996. end;
  1997. end;
  1998. end;
  1999. end;
  2000. WITH bh do
  2001. begin
  2002. if LDig < 0
  2003. then LDig := 0;
  2004. if LDig > 0
  2005. then Plac := LDig
  2006. else Plac := 0;
  2007. end;
  2008. if NOT pack_BCD ( bh, BCDout )
  2009. then begin
  2010. RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  2011. end;
  2012. _endSELECT
  2013. end;
  2014. procedure BCDDivide ( const Dividend,
  2015. Divisor : FmtBCDStringtype;
  2016. var BCDout : tBCD ); Inline;
  2017. begin
  2018. BCDDivide ( StrToBCD ( Dividend ), StrToBCD ( Divisor ), BCDout );
  2019. end;
  2020. procedure BCDDivide ( const Dividend : tBCD;
  2021. const Divisor : myRealtype;
  2022. var BCDout : tBCD ); Inline;
  2023. begin
  2024. BCDDivide ( Dividend, DoubleToBCD ( Divisor ), BCDout );
  2025. end;
  2026. procedure BCDDivide ( const Dividend : tBCD;
  2027. const Divisor : FmtBCDStringtype;
  2028. var BCDout : tBCD ); Inline;
  2029. begin
  2030. BCDDivide ( Dividend, StrToBCD ( Divisor ), BCDout );
  2031. end;
  2032. { TBCD variant creation utils }
  2033. procedure VarFmtBCDCreate ( var aDest : Variant;
  2034. const aBCD : tBCD );
  2035. begin
  2036. VarClear(aDest);
  2037. TVarData(aDest).Vtype:=FMTBcdFactory.Vartype;
  2038. TVarData(aDest).VPointer:=TFMTBcdVarData.create(aBCD);
  2039. end;
  2040. function VarFmtBCDCreate : Variant;
  2041. begin
  2042. VarFmtBCDCreate ( result, NullBCD );
  2043. end;
  2044. function VarFmtBCDCreate ( const aValue : FmtBCDStringtype;
  2045. Precision,
  2046. Scale : Word ) : Variant;
  2047. begin
  2048. VarFmtBCDCreate ( result, StrToBCD ( aValue ) );
  2049. end;
  2050. function VarFmtBCDCreate ( const aValue : myRealtype;
  2051. Precision : Word = 18;
  2052. Scale : Word = 4 ) : Variant;
  2053. begin
  2054. VarFmtBCDCreate ( result, DoubleToBCD ( aValue ) );
  2055. end;
  2056. function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant;
  2057. begin
  2058. VarFmtBCDCreate ( result, aBCD );
  2059. end;
  2060. function VarIsFmtBCD ( const aValue : Variant ) : Boolean;
  2061. begin
  2062. result:=false;
  2063. not_implemented;
  2064. end;
  2065. function VarFmtBCD : TVartype;
  2066. begin
  2067. result:=0;
  2068. not_implemented;
  2069. end;
  2070. { Formatting BCD as string }
  2071. function BCDToStrF ( const BCD : tBCD;
  2072. Format : TFloatFormat;
  2073. const Precision,
  2074. Digits : Integer ) : FmtBCDStringtype;
  2075. begin
  2076. not_implemented;
  2077. result:='';
  2078. end;
  2079. function FormatBCD ( const Format : string;
  2080. BCD : tBCD ) : FmtBCDStringtype;
  2081. begin
  2082. not_implemented;
  2083. result:='';
  2084. end;
  2085. {$ifdef additional_routines}
  2086. function CurrToBCD ( const Curr : currency ) : tBCD; Inline;
  2087. begin
  2088. CurrToBCD ( Curr, result );
  2089. end;
  2090. procedure BCDAdd ( const BCDIn : tBCD;
  2091. const IntIn : myInttype;
  2092. var BCDout : tBCD );
  2093. var
  2094. BCD : tBCD;
  2095. bhr : tBCD_helper;
  2096. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2097. ue : {$ifopt r+} 0..high ( IntIn ) - 9 {$else} Integer {$endif};
  2098. v : {$ifopt r+} 0..{high ( ue ) + 9} high ( IntIn ) {$else} Integer {$endif};
  2099. nz : Boolean;
  2100. begin
  2101. if IntIn = 0
  2102. then begin
  2103. BCDout := BCDIn;
  2104. EXIT;
  2105. end;
  2106. if IntIn = low ( myInttype )
  2107. then begin
  2108. {$if declared ( myMinIntBCD ) }
  2109. BCDAdd ( BCDIn, myMinIntBCD, BCDout );
  2110. EXIT;
  2111. {$else}
  2112. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2113. {$endif}
  2114. end;
  2115. if IsBCDNegative ( BCDIn )
  2116. then begin
  2117. BCD := BCDIn;
  2118. BCDNegate ( BCD );
  2119. if IntIn < 0
  2120. then BCDAdd ( BCD, -IntIn, BCDout )
  2121. else BCDSubtract ( BCD, IntIn, BCDout );
  2122. BCDNegate ( BCDout );
  2123. EXIT;
  2124. end;
  2125. if IntIn < 0
  2126. then begin
  2127. BCDSubtract ( BCDIn, -IntIn, BCDout );
  2128. EXIT;
  2129. end;
  2130. if IntIn > ( high ( IntIn ) - 9 )
  2131. then begin
  2132. BCDAdd ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2133. EXIT;
  2134. end;
  2135. unpack_BCD ( BCDIn, bhr );
  2136. p := 0;
  2137. nz := True;
  2138. ue := IntIn;
  2139. while nz do
  2140. begin
  2141. v := bhr.Singles[p] + ue;
  2142. bhr.Singles[p] := v MOD 10;
  2143. ue := v DIV 10;
  2144. if ue = 0
  2145. then nz := False
  2146. else Dec ( p );
  2147. end;
  2148. if p < bhr.FDig
  2149. then begin
  2150. bhr.FDig := p;
  2151. bhr.Prec := bhr.Prec + ( bhr.FDig - p );
  2152. end;
  2153. if NOT pack_BCD ( bhr, BCDout )
  2154. then begin
  2155. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2156. end;
  2157. end;
  2158. procedure BCDSubtract ( const BCDIn : tBCD;
  2159. const IntIn : myInttype;
  2160. var BCDout : tBCD );
  2161. {}
  2162. var
  2163. BCD : tBCD;
  2164. bhr : tBCD_helper;
  2165. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2166. ue : {$ifopt r+} 0..pred ( 100000000 ) {$else} Integer {$endif};
  2167. v : {$ifopt r+} -9..9 {$else} Integer {$endif};
  2168. direct : Boolean;
  2169. {}
  2170. begin
  2171. if IntIn = 0
  2172. then begin
  2173. BCDout := BCDIn;
  2174. EXIT;
  2175. end;
  2176. if IntIn = low ( myInttype )
  2177. then begin
  2178. {$if declared ( myMinIntBCD ) }
  2179. BCDSubtract ( BCDIn, myMinIntBCD, BCDout );
  2180. EXIT;
  2181. {$else}
  2182. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2183. {$endif}
  2184. end;
  2185. if IsBCDNegative ( BCDIn )
  2186. then begin
  2187. BCD := BCDIn;
  2188. BCDNegate ( BCD );
  2189. if IntIn < 0
  2190. then BCDSubtract ( BCD, -IntIn, BCDout )
  2191. else BCDAdd ( BCD, IntIn, BCDout );
  2192. BCDNegate ( BCDout );
  2193. EXIT;
  2194. end;
  2195. if IntIn < 0
  2196. then begin
  2197. BCDAdd ( BCDIn, -IntIn, BCDout );
  2198. EXIT;
  2199. end;
  2200. direct := False;
  2201. case BCDIn.Precision
  2202. -
  2203. {$ifndef bigger_BCD}
  2204. ( BCDIn.SignSpecialPlaces AND PlacesMask )
  2205. {$else}
  2206. BCDIn.Places
  2207. {$endif}
  2208. of
  2209. 2: direct := IntIn < 10;
  2210. 3: direct := IntIn < 100;
  2211. 4: direct := IntIn < 1000;
  2212. 5: direct := IntIn < 10000;
  2213. 6: direct := IntIn < 100000;
  2214. 7: direct := IntIn < 1000000;
  2215. 8: direct := IntIn < 10000000;
  2216. 9: direct := IntIn < 100000000;
  2217. end;
  2218. {
  2219. write(direct);dumpbcd(bcdin);write('[',intin,']');
  2220. }
  2221. if direct
  2222. then begin
  2223. unpack_BCD ( BCDIn, bhr );
  2224. WITH bhr do
  2225. begin
  2226. p := 0;
  2227. ue := IntIn;
  2228. while p >= FDig do
  2229. begin
  2230. v := Singles[p] - ue MOD 10;
  2231. ue := ue DIV 10;
  2232. if v < 0
  2233. then begin
  2234. v := v + 10;
  2235. ue := ue + 1;
  2236. end;
  2237. Singles[p] := v;
  2238. Dec ( p );
  2239. end;
  2240. end;
  2241. if NOT pack_BCD ( bhr, BCDout )
  2242. then begin
  2243. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2244. end;
  2245. end
  2246. else
  2247. {}
  2248. BCDSubtract ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2249. end;
  2250. procedure BCDAdd ( const IntIn : myInttype;
  2251. const BCDIn : tBCD;
  2252. var BCDout : tBCD ); Inline;
  2253. begin
  2254. BCDAdd ( BCDIn, IntIn, BCDout );
  2255. end;
  2256. procedure BCDAdd ( const BCDIn : tBCD;
  2257. const DoubleIn : myRealtype;
  2258. var BCDout : tBCD ); Inline;
  2259. begin
  2260. BCDAdd ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2261. end;
  2262. procedure BCDAdd ( const DoubleIn : myRealtype;
  2263. const BCDIn : tBCD;
  2264. var BCDout : tBCD ); Inline;
  2265. begin
  2266. BCDAdd ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2267. end;
  2268. procedure BCDAdd ( const BCDIn : tBCD;
  2269. const Currin : currency;
  2270. var BCDout : tBCD ); Inline;
  2271. begin
  2272. BCDAdd ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2273. end;
  2274. procedure BCDAdd ( const Currin : currency;
  2275. const BCDIn : tBCD;
  2276. var BCDout : tBCD ); Inline;
  2277. begin
  2278. BCDAdd ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2279. end;
  2280. {$ifdef comproutines}
  2281. procedure BCDAdd ( const BCDIn : tBCD;
  2282. const Compin : Comp;
  2283. var BCDout : tBCD ); Inline;
  2284. begin
  2285. BCDAdd ( BCDIn, CompToBCD ( Compin ), BCDout );
  2286. end;
  2287. procedure BCDAdd ( const Compin : Comp;
  2288. const BCDIn : tBCD;
  2289. var BCDout : tBCD ); Inline;
  2290. begin
  2291. BCDAdd ( CompToBCD ( Compin ), BCDIn, BCDout );
  2292. end;
  2293. {$endif}
  2294. procedure BCDAdd ( const BCDIn : tBCD;
  2295. const StringIn : FmtBCDStringtype;
  2296. var BCDout : tBCD ); Inline;
  2297. begin
  2298. BCDAdd ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2299. end;
  2300. procedure BCDAdd ( const StringIn : FmtBCDStringtype;
  2301. const BCDIn : tBCD;
  2302. var BCDout : tBCD ); Inline;
  2303. begin
  2304. BCDAdd ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2305. end;
  2306. procedure BCDAdd ( const StringIn1,
  2307. StringIn2 : FmtBCDStringtype;
  2308. var BCDout : tBCD ); Inline;
  2309. begin
  2310. BCDAdd ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2311. end;
  2312. procedure BCDSubtract ( const IntIn : myInttype;
  2313. const BCDIn : tBCD;
  2314. var BCDout : tBCD ); Inline;
  2315. begin
  2316. BCDSubtract ( BCDIn, IntIn, BCDout );
  2317. BCDNegate ( BCDout );
  2318. end;
  2319. procedure BCDSubtract ( const BCDIn : tBCD;
  2320. const DoubleIn : myRealtype;
  2321. var BCDout : tBCD ); Inline;
  2322. begin
  2323. BCDSubtract ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2324. end;
  2325. procedure BCDSubtract ( const DoubleIn : myRealtype;
  2326. const BCDIn : tBCD;
  2327. var BCDout : tBCD ); Inline;
  2328. begin
  2329. BCDSubtract ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2330. end;
  2331. procedure BCDSubtract ( const BCDIn : tBCD;
  2332. const Currin : currency;
  2333. var BCDout : tBCD ); Inline;
  2334. begin
  2335. BCDSubtract ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2336. end;
  2337. procedure BCDSubtract ( const Currin : currency;
  2338. const BCDIn : tBCD;
  2339. var BCDout : tBCD ); Inline;
  2340. begin
  2341. BCDSubtract ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2342. end;
  2343. {$ifdef comproutines}
  2344. procedure BCDSubtract ( const BCDIn : tBCD;
  2345. const Compin : Comp;
  2346. var BCDout : tBCD ); Inline;
  2347. begin
  2348. BCDSubtract ( BCDIn, CompToBCD ( Compin ), BCDout );
  2349. end;
  2350. procedure BCDSubtract ( const Compin : Comp;
  2351. const BCDIn : tBCD;
  2352. var BCDout : tBCD ); Inline;
  2353. begin
  2354. BCDSubtract ( CompToBCD ( Compin ), BCDIn, BCDout );
  2355. end;
  2356. {$endif}
  2357. procedure BCDSubtract ( const BCDIn : tBCD;
  2358. const StringIn : FmtBCDStringtype;
  2359. var BCDout : tBCD ); Inline;
  2360. begin
  2361. BCDSubtract ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2362. end;
  2363. procedure BCDSubtract ( const StringIn : FmtBCDStringtype;
  2364. const BCDIn : tBCD;
  2365. var BCDout : tBCD ); Inline;
  2366. begin
  2367. BCDSubtract ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2368. end;
  2369. procedure BCDSubtract ( const StringIn1,
  2370. StringIn2 : FmtBCDStringtype;
  2371. var BCDout : tBCD ); Inline;
  2372. begin
  2373. BCDSubtract ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2374. end;
  2375. procedure BCDMultiply ( const BCDIn : tBCD;
  2376. const IntIn : myInttype;
  2377. var BCDout : tBCD );
  2378. var
  2379. bh : tBCD_helper;
  2380. bhr : tBCD_helper;
  2381. bhrr : tBCD_helper_big;
  2382. int : {$ifopt r+} 0..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  2383. i1 : {$ifopt r+} low ( bh.Singles )..high ( bh.Singles ) {$else} Integer {$endif};
  2384. i3 : {$ifopt r+} low ( bhr.Singles )..high ( bhr.Singles ) {$else} Integer {$endif};
  2385. 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};
  2386. ue : {$ifopt r+} 1 * ( low ( bhrr.Singles[0] ) + low ( bhrr.Singles[0] ) DIV 10 ) DIV 10
  2387. ..( high ( bhrr.Singles[0] ) + high ( bhrr.Singles[0] ) DIV 10 ) DIV 10 {$else} Integer {$endif};
  2388. begin
  2389. if IntIn = 0
  2390. then begin
  2391. BCDout := NullBCD;
  2392. EXIT;
  2393. end;
  2394. if IntIn = 1
  2395. then begin
  2396. BCDout := BCDIn;
  2397. EXIT;
  2398. end;
  2399. if IntIn = -1
  2400. then begin
  2401. BCDout := BCDIn;
  2402. BCDNegate ( BCDout );
  2403. EXIT;
  2404. end;
  2405. if IntIn = low ( myInttype )
  2406. then begin
  2407. {$if declared ( myMinIntBCD ) }
  2408. BCDMultiply ( BCDIn, myMinIntBCD, BCDout );
  2409. EXIT;
  2410. {$else}
  2411. RAISE eBCDOverflowException.create ( 'in BCDmultiply' );
  2412. {$endif}
  2413. end;
  2414. if Abs ( IntIn ) > low ( bhrr.Singles[0] ) DIV 10
  2415. then begin
  2416. BCDMultiply ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2417. EXIT;
  2418. end;
  2419. unpack_BCD ( BCDIn, bh );
  2420. if bh.Prec = 0
  2421. then begin
  2422. BCDout := NullBCD;
  2423. EXIT;
  2424. end;
  2425. bhr := null_.bh;
  2426. bhrr := null_.bhb;
  2427. int := Abs ( IntIn );
  2428. WITH bhrr do
  2429. begin
  2430. Neg := bh.Neg XOR ( IntIn < 0 );
  2431. FDig := bh.FDig;
  2432. LDig := bh.LDig;
  2433. for i1 := bh.FDig TO bh.LDig do
  2434. Singles[i1] := bh.Singles[i1] * int;
  2435. {
  2436. for i3 := fdig to ldig do
  2437. write ( ' ', singles[i3] );
  2438. writeln;
  2439. }
  2440. ue := 0;
  2441. for i3 := LDig DOWNTO FDig do
  2442. begin
  2443. v := Singles[i3] + ue;
  2444. ue := v DIV 10;
  2445. v := v MOD 10;
  2446. bhr.Singles[i3] := v;
  2447. end;
  2448. while ue <> 0 do
  2449. begin
  2450. Dec ( FDig );
  2451. if FDig < low ( bhr.Singles )
  2452. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2453. bhr.Singles[FDig] := ue MOD 10;
  2454. ue := ue DIV 10;
  2455. end;
  2456. bhr.Plac := LDig;
  2457. bhr.FDig := FDig;
  2458. if LDig > high ( bhr.Singles )
  2459. then bhr.LDig := high ( bhr.Singles )
  2460. else bhr.LDig := LDig;
  2461. end;
  2462. if NOT pack_BCD ( bhr, BCDout )
  2463. then begin
  2464. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2465. end;
  2466. end;
  2467. procedure BCDMultiply ( const IntIn : myInttype;
  2468. const BCDIn : tBCD;
  2469. var BCDout : tBCD ); Inline;
  2470. begin
  2471. BCDMultiply ( BCDIn, IntIn, BCDout );
  2472. end;
  2473. procedure BCDMultiply ( const DoubleIn : myRealtype;
  2474. const BCDIn : tBCD;
  2475. var BCDout : tBCD ); Inline;
  2476. begin
  2477. BCDMultiply ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2478. end;
  2479. procedure BCDMultiply ( const BCDIn : tBCD;
  2480. const Currin : currency;
  2481. var BCDout : tBCD ); Inline;
  2482. begin
  2483. BCDMultiply ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2484. end;
  2485. procedure BCDMultiply ( const Currin : currency;
  2486. const BCDIn : tBCD;
  2487. var BCDout : tBCD ); Inline;
  2488. begin
  2489. BCDMultiply ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2490. end;
  2491. {$ifdef comproutines}
  2492. procedure BCDMultiply ( const BCDIn : tBCD;
  2493. const Compin : Comp;
  2494. var BCDout : tBCD ); Inline;
  2495. begin
  2496. BCDMultiply ( BCDIn, CompToBCD ( Compin ), BCDout );
  2497. end;
  2498. procedure BCDMultiply ( const Compin : Comp;
  2499. const BCDIn : tBCD;
  2500. var BCDout : tBCD ); Inline;
  2501. begin
  2502. BCDMultiply ( CompToBCD ( Compin ), BCDIn, BCDout );
  2503. end;
  2504. {$endif}
  2505. procedure BCDMultiply ( const StringIn : FmtBCDStringtype;
  2506. const BCDIn : tBCD;
  2507. var BCDout : tBCD ); Inline;
  2508. begin
  2509. BCDMultiply ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2510. end;
  2511. procedure BCDDivide ( const Dividend : tBCD;
  2512. const Divisor : myInttype;
  2513. var BCDout : tBCD ); Inline;
  2514. begin
  2515. BCDDivide ( Dividend, IntegerToBCD ( Divisor ), BCDout );
  2516. end;
  2517. procedure BCDDivide ( const Dividend : myInttype;
  2518. const Divisor : tBCD;
  2519. var BCDout : tBCD ); Inline;
  2520. begin
  2521. BCDDivide ( IntegerToBCD ( Dividend ), Divisor, BCDout );
  2522. end;
  2523. procedure BCDDivide ( const Dividend : myRealtype;
  2524. const Divisor : tBCD;
  2525. var BCDout : tBCD ); Inline;
  2526. begin
  2527. BCDDivide ( DoubleToBCD ( Dividend ), Divisor, BCDout );
  2528. end;
  2529. procedure BCDDivide ( const BCDIn : tBCD;
  2530. const Currin : currency;
  2531. var BCDout : tBCD ); Inline;
  2532. begin
  2533. BCDDivide ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2534. end;
  2535. procedure BCDDivide ( const Currin : currency;
  2536. const BCDIn : tBCD;
  2537. var BCDout : tBCD ); Inline;
  2538. begin
  2539. BCDDivide ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2540. end;
  2541. {$ifdef comproutines}
  2542. procedure BCDDivide ( const BCDIn : tBCD;
  2543. const Compin : Comp;
  2544. var BCDout : tBCD ); Inline;
  2545. begin
  2546. BCDDivide ( BCDIn, CompToBCD ( Compin ), BCDout );
  2547. end;
  2548. procedure BCDDivide ( const Compin : Comp;
  2549. const BCDIn : tBCD;
  2550. var BCDout : tBCD ); Inline;
  2551. begin
  2552. BCDDivide ( CompToBCD ( Compin ), BCDIn, BCDout );
  2553. end;
  2554. {$endif}
  2555. procedure BCDDivide ( const Dividend : FmtBCDStringtype;
  2556. const Divisor : tBCD;
  2557. var BCDout : tBCD ); Inline;
  2558. begin
  2559. BCDDivide ( StrToBCD ( Dividend ), Divisor, BCDout );
  2560. end;
  2561. operator = ( const BCD1,
  2562. BCD2 : tBCD ) z : Boolean; Inline;
  2563. begin
  2564. z := BCDCompare ( BCD1, BCD2 ) = 0;
  2565. end;
  2566. operator < ( const BCD1,
  2567. BCD2 : tBCD ) z : Boolean; Inline;
  2568. begin
  2569. z := BCDCompare ( BCD1, BCD2 ) < 0;
  2570. end;
  2571. operator > ( const BCD1,
  2572. BCD2 : tBCD ) z : Boolean; Inline;
  2573. begin
  2574. z := BCDCompare ( BCD1, BCD2 ) > 0;
  2575. end;
  2576. operator <= ( const BCD1,
  2577. BCD2 : tBCD ) z : Boolean; Inline;
  2578. begin
  2579. z := BCDCompare ( BCD1, BCD2 ) <= 0;
  2580. end;
  2581. operator >= ( const BCD1,
  2582. BCD2 : tBCD ) z : Boolean; Inline;
  2583. begin
  2584. z := BCDCompare ( BCD1, BCD2 ) >= 0;
  2585. end;
  2586. (* ######################## not allowed: why?
  2587. operator + ( const BCD : tBCD ) z : tBCD; Inline;
  2588. begin
  2589. z := bcd;
  2590. end;
  2591. ##################################################### *)
  2592. operator - ( const BCD : tBCD ) z : tBCD; Inline;
  2593. begin
  2594. z := BCD;
  2595. BCDNegate ( z );
  2596. end;
  2597. operator + ( const BCD1,
  2598. BCD2 : tBCD ) z : tBCD; Inline;
  2599. begin
  2600. BCDAdd ( BCD1, BCD2, z );
  2601. end;
  2602. operator + ( const BCD : tBCD;
  2603. const i : myInttype ) z : tBCD; Inline;
  2604. begin
  2605. BCDAdd ( BCD, i, z );
  2606. end;
  2607. operator + ( const i : myInttype;
  2608. const BCD : tBCD ) z : tBCD; Inline;
  2609. begin
  2610. BCDAdd ( i, BCD, z );
  2611. end;
  2612. operator + ( const BCD : tBCD;
  2613. const r : myRealtype ) z : tBCD; Inline;
  2614. begin
  2615. BCDAdd ( BCD, DoubleToBCD ( r ), z );
  2616. end;
  2617. operator + ( const r : myRealtype;
  2618. const BCD : tBCD ) z : tBCD; Inline;
  2619. begin
  2620. BCDAdd ( DoubleToBCD ( r ), BCD, z );
  2621. end;
  2622. operator + ( const BCD : tBCD;
  2623. const c : currency ) z : tBCD; Inline;
  2624. begin
  2625. BCDAdd ( BCD, CurrToBCD ( c ), z );
  2626. end;
  2627. operator + ( const c : currency;
  2628. const BCD : tBCD ) z : tBCD; Inline;
  2629. begin
  2630. BCDAdd ( CurrToBCD ( c ), BCD, z );
  2631. end;
  2632. {$ifdef comproutines}
  2633. operator + ( const BCD : tBCD;
  2634. const c : Comp ) z : tBCD; Inline;
  2635. begin
  2636. BCDAdd ( BCD, CompToBCD ( c ), z );
  2637. end;
  2638. operator + ( const c : Comp;
  2639. const BCD : tBCD ) z : tBCD; Inline;
  2640. begin
  2641. BCDAdd ( CompToBCD ( c ), BCD, z );
  2642. end;
  2643. {$endif}
  2644. operator + ( const BCD : tBCD;
  2645. const s : FmtBCDStringtype ) z : tBCD; Inline;
  2646. begin
  2647. BCDAdd ( BCD, StrToBCD ( s ), z );
  2648. end;
  2649. operator + ( const s : FmtBCDStringtype;
  2650. const BCD : tBCD ) z : tBCD; Inline;
  2651. begin
  2652. BCDAdd ( StrToBCD ( s ), BCD, z );
  2653. end;
  2654. operator - ( const BCD1,
  2655. BCD2 : tBCD ) z : tBCD; Inline;
  2656. begin
  2657. BCDSubtract ( BCD1, BCD2, z );
  2658. end;
  2659. operator - ( const BCD : tBCD;
  2660. const i : myInttype ) z : tBCD; Inline;
  2661. begin
  2662. BCDSubtract ( BCD, i, z );
  2663. end;
  2664. operator - ( const i : myInttype;
  2665. const BCD : tBCD ) z : tBCD; Inline;
  2666. begin
  2667. BCDSubtract ( BCD, i, z );
  2668. BCDNegate ( z );
  2669. end;
  2670. operator - ( const BCD : tBCD;
  2671. const r : myRealtype ) z : tBCD; Inline;
  2672. begin
  2673. BCDSubtract ( BCD, DoubleToBCD ( r ), z );
  2674. end;
  2675. operator - ( const r : myRealtype;
  2676. const BCD : tBCD ) z : tBCD; Inline;
  2677. begin
  2678. BCDSubtract ( DoubleToBCD ( r ), BCD, z );
  2679. end;
  2680. operator - ( const BCD : tBCD;
  2681. const c : currency ) z : tBCD; Inline;
  2682. begin
  2683. BCDSubtract ( BCD, CurrToBCD ( c ), z );
  2684. end;
  2685. operator - ( const c : currency;
  2686. const BCD : tBCD ) z : tBCD; Inline;
  2687. begin
  2688. BCDSubtract ( CurrToBCD ( c ), BCD, z );
  2689. end;
  2690. {$ifdef comproutines}
  2691. operator - ( const BCD : tBCD;
  2692. const c : Comp ) z : tBCD; Inline;
  2693. begin
  2694. BCDSubtract ( BCD, CompToBCD ( c ), z );
  2695. end;
  2696. operator - ( const c : Comp;
  2697. const BCD : tBCD ) z : tBCD; Inline;
  2698. begin
  2699. BCDSubtract ( CompToBCD ( c ), BCD, z );
  2700. end;
  2701. {$endif}
  2702. operator - ( const BCD : tBCD;
  2703. const s : FmtBCDStringtype ) z : tBCD; Inline;
  2704. begin
  2705. BCDSubtract ( BCD, StrToBCD ( s ), z );
  2706. end;
  2707. operator - ( const s : FmtBCDStringtype;
  2708. const BCD : tBCD ) z : tBCD; Inline;
  2709. begin
  2710. BCDSubtract ( StrToBCD ( s ), BCD, z );
  2711. end;
  2712. operator * ( const BCD1,
  2713. BCD2 : tBCD ) z : tBCD; Inline;
  2714. begin
  2715. BCDMultiply ( BCD1, BCD2, z );
  2716. end;
  2717. operator * ( const BCD : tBCD;
  2718. const i : myInttype ) z : tBCD; Inline;
  2719. begin
  2720. BCDMultiply ( BCD, i, z );
  2721. end;
  2722. operator * ( const i : myInttype;
  2723. const BCD : tBCD ) z : tBCD; Inline;
  2724. begin
  2725. BCDMultiply ( BCD, i, z );
  2726. end;
  2727. operator * ( const BCD : tBCD;
  2728. const r : myRealtype ) z : tBCD; Inline;
  2729. begin
  2730. BCDMultiply ( BCD, DoubleToBCD ( r ), z );
  2731. end;
  2732. operator * ( const r : myRealtype;
  2733. const BCD : tBCD ) z : tBCD; Inline;
  2734. begin
  2735. BCDMultiply ( DoubleToBCD ( r ), BCD, z );
  2736. end;
  2737. operator * ( const BCD : tBCD;
  2738. const c : currency ) z : tBCD; Inline;
  2739. begin
  2740. BCDMultiply ( BCD, CurrToBCD ( c ), z );
  2741. end;
  2742. operator * ( const c : currency;
  2743. const BCD : tBCD ) z : tBCD; Inline;
  2744. begin
  2745. BCDMultiply ( CurrToBCD ( c ), BCD, z );
  2746. end;
  2747. {$ifdef comproutines}
  2748. operator * ( const BCD : tBCD;
  2749. const c : Comp ) z : tBCD; Inline;
  2750. begin
  2751. BCDMultiply ( BCD, CompToBCD ( c ), z );
  2752. end;
  2753. operator * ( const c : Comp;
  2754. const BCD : tBCD ) z : tBCD; Inline;
  2755. begin
  2756. BCDMultiply ( CompToBCD ( c ), BCD, z );
  2757. end;
  2758. {$endif}
  2759. operator * ( const BCD : tBCD;
  2760. const s : FmtBCDStringtype ) z : tBCD; Inline;
  2761. begin
  2762. BCDMultiply ( BCD, StrToBCD ( s ), z );
  2763. end;
  2764. operator * ( const s : FmtBCDStringtype;
  2765. const BCD : tBCD ) z : tBCD; Inline;
  2766. begin
  2767. BCDMultiply ( StrToBCD ( s ), BCD, z );
  2768. end;
  2769. operator / ( const BCD1,
  2770. BCD2 : tBCD ) z : tBCD; Inline;
  2771. begin
  2772. BCDDivide ( BCD1, BCD2, z );
  2773. end;
  2774. operator / ( const BCD : tBCD;
  2775. const i : myInttype ) z : tBCD; Inline;
  2776. begin
  2777. BCDDivide ( BCD, i, z );
  2778. end;
  2779. operator / ( const i : myInttype;
  2780. const BCD : tBCD ) z : tBCD; Inline;
  2781. begin
  2782. BCDDivide ( IntegerToBCD ( i ), BCD, z );
  2783. end;
  2784. operator / ( const BCD : tBCD;
  2785. const r : myRealtype ) z : tBCD; Inline;
  2786. begin
  2787. BCDDivide ( BCD, DoubleToBCD ( r ), z );
  2788. end;
  2789. operator / ( const r : myRealtype;
  2790. const BCD : tBCD ) z : tBCD; Inline;
  2791. begin
  2792. BCDDivide ( DoubleToBCD ( r ), BCD, z );
  2793. end;
  2794. operator / ( const BCD : tBCD;
  2795. const c : currency ) z : tBCD; Inline;
  2796. begin
  2797. BCDDivide ( BCD, CurrToBCD ( c ), z );
  2798. end;
  2799. operator / ( const c : currency;
  2800. const BCD : tBCD ) z : tBCD; Inline;
  2801. begin
  2802. BCDDivide ( CurrToBCD ( c ), BCD, z );
  2803. end;
  2804. {$ifdef comproutines}
  2805. operator / ( const BCD : tBCD;
  2806. const c : Comp ) z : tBCD; Inline;
  2807. begin
  2808. BCDDivide ( BCD, CompToBCD ( c ), z );
  2809. end;
  2810. operator / ( const c : Comp;
  2811. const BCD : tBCD ) z : tBCD; Inline;
  2812. begin
  2813. BCDDivide ( CompToBCD ( c ), BCD, z );
  2814. end;
  2815. {$endif}
  2816. operator / ( const BCD : tBCD;
  2817. const s : FmtBCDStringtype ) z : tBCD; Inline;
  2818. begin
  2819. BCDDivide ( BCD, StrToBCD ( s ), z );
  2820. end;
  2821. operator / ( const s : FmtBCDStringtype;
  2822. const BCD : tBCD ) z : tBCD; Inline;
  2823. begin
  2824. BCDDivide ( StrToBCD ( s ), BCD, z );
  2825. end;
  2826. operator := ( const i : Byte ) z : tBCD; Inline;
  2827. begin
  2828. z := IntegerToBCD ( myInttype ( i ) );
  2829. end;
  2830. operator := ( const BCD : tBCD ) z : Byte; Inline;
  2831. begin
  2832. z := BCDToInteger ( BCD );
  2833. end;
  2834. operator := ( const i : Word ) z : tBCD; Inline;
  2835. begin
  2836. z := IntegerToBCD ( myInttype ( i ) );
  2837. end;
  2838. operator := ( const BCD : tBCD ) z : Word; Inline;
  2839. begin
  2840. z := BCDToInteger ( BCD );
  2841. end;
  2842. operator := ( const i : longword ) z : tBCD; Inline;
  2843. begin
  2844. z := IntegerToBCD ( myInttype ( i ) );
  2845. end;
  2846. operator := ( const BCD : tBCD ) z : longword; Inline;
  2847. begin
  2848. z := BCDToInteger ( BCD );
  2849. end;
  2850. {$if declared ( qword ) }
  2851. operator := ( const i : qword ) z : tBCD; Inline;
  2852. begin
  2853. z := IntegerToBCD ( myInttype ( i ) );
  2854. end;
  2855. operator := ( const BCD : tBCD ) z : qword; Inline;
  2856. begin
  2857. z := BCDToInteger ( BCD );
  2858. end;
  2859. {$endif}
  2860. operator := ( const i : ShortInt ) z : tBCD; Inline;
  2861. begin
  2862. z := IntegerToBCD ( myInttype ( i ) );
  2863. end;
  2864. operator := ( const BCD : tBCD ) z : ShortInt; Inline;
  2865. begin
  2866. z := BCDToInteger ( BCD );
  2867. end;
  2868. operator := ( const i : smallint ) z : tBCD; Inline;
  2869. begin
  2870. z := IntegerToBCD ( myInttype ( i ) );
  2871. end;
  2872. operator := ( const BCD : tBCD ) z : smallint; Inline;
  2873. begin
  2874. z := BCDToInteger ( BCD );
  2875. end;
  2876. operator := ( const i : LongInt ) z : tBCD; Inline;
  2877. begin
  2878. z := IntegerToBCD ( myInttype ( i ) );
  2879. end;
  2880. operator := ( const BCD : tBCD ) z : LongInt; Inline;
  2881. begin
  2882. z := BCDToInteger ( BCD );
  2883. end;
  2884. {$if declared ( int64 ) }
  2885. operator := ( const i : int64 ) z : tBCD; Inline;
  2886. begin
  2887. z := IntegerToBCD ( myInttype ( i ) );
  2888. end;
  2889. operator := ( const BCD : tBCD ) z : int64; Inline;
  2890. begin
  2891. z := BCDToInteger ( BCD );
  2892. end;
  2893. {$endif}
  2894. operator := ( const r : Single ) z : tBCD; Inline;
  2895. begin
  2896. z := DoubleToBCD ( myRealtype ( r ) );
  2897. end;
  2898. operator := ( const BCD : tBCD ) z : Single; Inline;
  2899. begin
  2900. z := BCDToDouble ( BCD );
  2901. end;
  2902. operator := ( const r : Double ) z : tBCD; Inline;
  2903. begin
  2904. z := DoubleToBCD ( myRealtype ( r ) );
  2905. end;
  2906. operator := ( const BCD : tBCD ) z : Double; Inline;
  2907. begin
  2908. z := BCDToDouble ( BCD );
  2909. end;
  2910. {$if sizeof ( extended ) <> sizeof ( double )}
  2911. operator := ( const r : Extended ) z : tBCD; Inline;
  2912. begin
  2913. z := DoubleToBCD ( {myRealtype (} r {)} );
  2914. end;
  2915. operator := ( const BCD : tBCD ) z : Extended; Inline;
  2916. begin
  2917. z := BCDToDouble ( BCD );
  2918. end;
  2919. {$endif}
  2920. operator := ( const c : currency ) z : tBCD; Inline;
  2921. begin
  2922. CurrToBCD ( c, z );
  2923. end;
  2924. operator := ( const BCD : tBCD ) z : currency; Inline;
  2925. begin
  2926. BCDToCurr ( BCD, z );
  2927. end;
  2928. {$ifdef comproutines}
  2929. {$undef makedirect}
  2930. {$ifdef makedirect}
  2931. operator := ( const c : Comp ) z : tBCD; Inline;
  2932. var
  2933. cc : int64 absolute c;
  2934. begin
  2935. z := IntegerToBCD ( cc );
  2936. end;
  2937. { $define version1} { only one of these may be defined! }
  2938. { $define version2} { version 1 produces a compiler error (with INLINE only!)}
  2939. {$define version3} { I wasn't able to reduce the problem, sorry }
  2940. {$ifdef version1}
  2941. operator := ( const BCD : tBCD ) z : Comp; Inline;
  2942. var
  2943. zz : Comp absolute z;
  2944. begin
  2945. zz := BCDToInteger ( BCD );
  2946. end;
  2947. {$endif}
  2948. {$ifdef version2}
  2949. operator := ( const BCD : tBCD ) z : Comp; Inline;
  2950. var
  2951. zz : int64;
  2952. zzz : Comp absolute zz;
  2953. begin
  2954. zz := BCDToInteger ( BCD );
  2955. z := zzz;
  2956. end;
  2957. {$endif}
  2958. {$ifdef version3}
  2959. operator := ( const BCD : tBCD ) z : Comp; Inline;
  2960. var
  2961. zz : record
  2962. case Boolean of
  2963. False: ( i : int64 );
  2964. True: ( c : Comp );
  2965. end;
  2966. begin
  2967. zz.i := BCDToInteger ( BCD );
  2968. z := zz.c;
  2969. end;
  2970. {$endif}
  2971. {$else}
  2972. operator := ( const c : Comp ) z : tBCD; Inline;
  2973. begin
  2974. z := CompToBCD ( c );
  2975. end;
  2976. operator := ( const BCD : tBCD ) z : Comp; Inline;
  2977. begin
  2978. z := BCDToComp ( BCD );
  2979. end;
  2980. {$endif}
  2981. {$endif}
  2982. operator := ( const s : string ) z : tBCD; Inline;
  2983. begin
  2984. z := StrToBCD ( s );
  2985. end;
  2986. operator := ( const BCD : tBCD ) z : string; Inline;
  2987. begin
  2988. z := BCDToStr ( BCD );
  2989. end;
  2990. operator := ( const s : AnsiString ) z : tBCD; Inline;
  2991. begin
  2992. z := StrToBCD ( s );
  2993. end;
  2994. operator := ( const BCD : tBCD ) z : AnsiString; Inline;
  2995. begin
  2996. z := BCDToStr ( BCD );
  2997. end;
  2998. {$endif}
  2999. constructor TFMTBcdVarData.create;
  3000. begin
  3001. inherited create;
  3002. FBcd:=NullBCD;
  3003. end;
  3004. constructor TFMTBcdVarData.create(const BCD : tBCD);
  3005. begin
  3006. inherited create;
  3007. FBcd:=BCD;
  3008. end;
  3009. function TFMTBcdFactory.GetInstance(const v : TVarData): tObject;
  3010. begin
  3011. result:=tObject(v.VPointer);
  3012. end;
  3013. procedure TFMTBcdFactory.BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp);
  3014. begin
  3015. case Operation of
  3016. opAdd:
  3017. TFMTBcdVarData(Left.VPointer).BCD:=TFMTBcdVarData(Left.VPointer).BCD+TFMTBcdVarData(Right.VPointer).BCD;
  3018. opSubtract:
  3019. TFMTBcdVarData(Left.VPointer).BCD:=TFMTBcdVarData(Left.VPointer).BCD-TFMTBcdVarData(Right.VPointer).BCD;
  3020. opMultiply:
  3021. TFMTBcdVarData(Left.VPointer).BCD:=TFMTBcdVarData(Left.VPointer).BCD*TFMTBcdVarData(Right.VPointer).BCD;
  3022. opDivide:
  3023. TFMTBcdVarData(Left.VPointer).BCD:=TFMTBcdVarData(Left.VPointer).BCD/TFMTBcdVarData(Right.VPointer).BCD;
  3024. else
  3025. RaiseInvalidOp;
  3026. end;
  3027. end;
  3028. {$if declared ( myMinIntBCD ) }
  3029. (*
  3030. {$if sizeof ( integer ) = 2 }
  3031. {$ifdef BCDgr4 }
  3032. const
  3033. myMinIntBCDValue : packed array [ 1..3 ] of Char = #$32#$76#$80;
  3034. {$endif}
  3035. {$else}
  3036. {$if sizeof ( integer ) = 4 }
  3037. *)
  3038. {$ifdef BCDgr9 }
  3039. const
  3040. myMinIntBCDValue : packed array [ 1..10 ] of Char = #$21#$47#$48#$36#$48;
  3041. {$endif}
  3042. (*
  3043. {$else}
  3044. {$if sizeof ( integer ) = 8 }
  3045. {$ifdef BCDgr18 }
  3046. const
  3047. myMinIntBCDValue : packed array [ 1..19 ] of Char = #$92#$23#$37#$20#$36#$85#$47#$75#$80#$80;
  3048. {$endif}
  3049. {$else}
  3050. {$fatal You have an interesting integer type! Sorry, not supported}
  3051. {$endif}
  3052. {$endif}
  3053. {$endif}
  3054. *)
  3055. {$endif}
  3056. initialization
  3057. FillChar ( null_, SizeOf ( null_ ), #0 );
  3058. FillChar ( NullBCD_, SizeOf ( NullBCD_ ), #0 );
  3059. FillChar ( OneBCD_, SizeOf ( OneBCD_ ), #0 );
  3060. OneBCD_.Precision := 1;
  3061. OneBCD_.Fraction[low ( OneBCD_.Fraction )] := $10;
  3062. {$if declared ( myMinIntBCD ) }
  3063. FillChar ( myMinIntBCD, SizeOf ( myMinIntBCD ), #0 );
  3064. {$ifndef bigger_BCD}
  3065. myMinIntBCD.SignSpecialPlaces := NegBit;
  3066. {$else}
  3067. myMinIntBCD.Negativ := True;
  3068. {$endif}
  3069. {$if sizeof ( integer ) = 2 }
  3070. {$ifdef BCDgr4 }
  3071. myMinIntBCD.Precision := 5;
  3072. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3073. {$endif}
  3074. {$else}
  3075. {$if sizeof ( integer ) = 4 }
  3076. {$ifdef BCDgr9 }
  3077. myMinIntBCD.Precision := 10;
  3078. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3079. {$endif}
  3080. {$else}
  3081. {$if sizeof ( integer ) = 8 }
  3082. {$ifdef BCDgr18 }
  3083. myMinIntBCD.Precision := 19;
  3084. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3085. {$endif}
  3086. {$else}
  3087. {$fatal You have an interesting integer type! Sorry, not supported}
  3088. {$endif}
  3089. {$endif}
  3090. {$endif}
  3091. {$endif}
  3092. FMTBcdFactory:=TFMTBcdFactory.create;
  3093. finalization
  3094. FreeAndNil(FMTBcdFactory)
  3095. end.