fmtbcd.pp 115 KB

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