fmtbcd.pp 106 KB

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