fmtbcd.pp 107 KB

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