fmtbcd.pp 123 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2005-2006 by the Free Pascal development team
  4. and Gehard Scholz
  5. It contains the Free Pascal BCD implementation
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS for A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. { "Programming is the time between two bugs" }
  13. { (last words of the unknown programmer) }
  14. (* this program was a good test for the compiler: some bugs have been found.
  15. 1. WITH in inline funcs produces a compiler error AFTER producing an .exe file
  16. (was already known; I didn't see it in the bug list)
  17. 2. macro names were checked for being a keyword, even when starting with
  18. an '_' (produces range check when compiler is compiled with { $r+ }-mode
  19. fixed.
  20. 3. { $define program } was not possible in { $macro on } mode
  21. (keywords not allowed: doesn't make sense here)
  22. fixed.
  23. 4. the Inc/Dec ( unsigned, signed ) problem (has been similar in the
  24. bug list already)
  25. 5. when the result of an overloaded (inline) operator is ABSOLUTEd:
  26. compiler error 200110205
  27. happens only when operator is defined in a unit.
  28. 6. two range check errors in scanner.pas
  29. a) array subscripting
  30. b) value out ouf range
  31. *)
  32. { $define debug_version}
  33. // Dont use s+ (Stack checking on) because it crashes libraries, see bug 21208
  34. {$r+,q+,s-}
  35. {$mode objfpc}
  36. {$h-}
  37. {$inline on}
  38. {$macro on}
  39. {$define BCDMaxDigits := 64 } { should be even }
  40. { the next defines must be defined by hand,
  41. unless someone shows me a way how to to it with macros }
  42. {$define BCDgr4} { define this if MCDMaxDigits is greater 4, else undefine! }
  43. {$define BCDgr9} { define this if MCDMaxDigits is greater 9, else undefine! }
  44. {$define BCDgr18} { define this if MCDMaxDigits is greater 18, else undefine! }
  45. { $define BCDgr64} { define this if MCDMaxDigits is greater 64, else undefine! }
  46. { $define BCDgr180} { define this if MCDMaxDigits is greater 180, else undefine! }
  47. {$ifdef BCDgr4}
  48. {$hint BCD Digits > 4}
  49. {$endif}
  50. {$ifdef BCDgr9}
  51. {$hint BCD Digits > 9}
  52. {$endif}
  53. {$ifdef BCDgr18}
  54. {$hint BCD Digits > 18}
  55. {$endif}
  56. {$ifdef BCDgr64}
  57. {$hint BCD Digits > 64}
  58. {$endif}
  59. {$ifdef BCDgr180}
  60. {$hint BCD Digits > 180}
  61. {$endif}
  62. {$ifndef NO_SMART_LINK}
  63. { $smartlink on}
  64. {$endif}
  65. {$define some_packed} { enable this to keep some local structures PACKED }
  66. { $define as_object} { to define the tBCD record as object instead;
  67. fields then are private }
  68. { not done yet! }
  69. {$define additional_routines} { to create additional routines and operators }
  70. (* only define one of them! *)
  71. { $define integ32}
  72. {$define integ64}
  73. (* only define one of them! *)
  74. { $define real8}
  75. {$define real10}
  76. {check}
  77. {$ifndef integ32}
  78. {$ifndef integ64}
  79. {$define integ64}
  80. {$endif}
  81. {$endif}
  82. {$ifdef integ32}
  83. {$ifdef integ64}
  84. {$undef integ32}
  85. {$endif}
  86. {$endif}
  87. {check}
  88. {$ifndef real8}
  89. {$ifndef real10}
  90. {$define real8}
  91. {$endif}
  92. {$endif}
  93. {$ifdef real8}
  94. {$ifdef real10}
  95. {$undef real10}
  96. {$endif}
  97. {$endif}
  98. {$ifdef some_packed}
  99. {$define maybe_packed := packed}
  100. {$else}
  101. {$define maybe_packed := (**)}
  102. {$endif}
  103. UNIT FmtBCD;
  104. INTERFACE
  105. USES
  106. SysUtils,
  107. Variants;
  108. const
  109. MaxStringDigits = 100; { not used ! }
  110. _NoDecimal = -255; { not used ! }
  111. _DefaultDecimals = 10; { not used ! }
  112. { From DB.pas }
  113. { Max supported by Midas } { must be EVEN }
  114. MaxFmtBCDFractionSize = BCDMaxDigits + Ord ( Odd ( BCDMaxDigits ) );
  115. { Max supported by Midas }
  116. MaxFmtBCDDigits = 32; { not used ! }
  117. DefaultFmtBCDScale = 6; { not used ! }
  118. MaxBCDPrecision = 18; { not used ! }
  119. MaxBCDScale = 4; { not used ! }
  120. {$ifdef BCDgr64}
  121. { $fatal big 1}
  122. {$define bigger_BCD} { must be defined
  123. if MaxFmtBCDFractionSize > 64 }
  124. { not usable in the moment }
  125. {$endif}
  126. {$ifdef BCDgr180}
  127. { $fatal big 2}
  128. type
  129. FmtBCDStringtype = AnsiString;
  130. {$define use_Ansistring}
  131. {$else}
  132. type
  133. FmtBCDStringtype = string [ 255 ];
  134. {$undef use_Ansistring}
  135. {$endif}
  136. {$ifdef use_ansistring}
  137. {$hint ansi}
  138. {$else}
  139. {$hint -ansi}
  140. {$endif}
  141. {$ifdef integ32}
  142. {$define myInttype := LongInt}
  143. {$endif}
  144. {$ifdef integ64}
  145. {$define myInttype := int64}
  146. {$endif}
  147. {$ifndef FPUNONE}
  148. {$ifdef real8}
  149. {$define myRealtype := double}
  150. {$endif}
  151. {$ifdef real10}
  152. {$define myRealtype := extended}
  153. {$endif}
  154. {$endif}
  155. {$ifdef SUPPORT_COMP}
  156. {$define comproutines}
  157. {$endif SUPPORT_COMP}
  158. {$define __low_Fraction := 0 }
  159. {$define __high_Fraction := ( ( MaxFmtBCDFractionSize DIV 2 ) - 1 ) }
  160. type
  161. pBCD = ^ tBCD;
  162. tBCD = packed {$ifdef as_object} OBJECT {$else} record {$endif}
  163. {$ifdef as_object} PRIVATE {$endif}
  164. Precision : 0..maxfmtbcdfractionsize; { 1 (joke?)..64 }
  165. {$ifndef bigger_BCD}
  166. SignSpecialPlaces : Byte; { Sign:1, Special:1, Places:6 }
  167. {$else}
  168. Negativ : Boolean;
  169. {
  170. Special : Boolean;
  171. }
  172. Places : 0..maxfmtbcdfractionsize - 1;
  173. {$endif}
  174. Fraction : packed array [ __low_Fraction..__high_Fraction ] of Byte;
  175. { BCD Nibbles, 00..99 per Byte, high Nibble 1st }
  176. end;
  177. { Exception classes }
  178. type
  179. eBCDException = CLASS ( Exception );
  180. eBCDOverflowException = CLASS ( eBCDException );
  181. eBCDNotImplementedException = CLASS ( eBCDException );
  182. { Utility functions for TBCD access }
  183. function BCDPrecision ( const BCD : tBCD ) : Word; Inline;
  184. function BCDScale ( const BCD : tBCD ) : Word; Inline;
  185. function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline;
  186. { BCD Arithmetic}
  187. procedure BCDNegate ( var BCD : tBCD ); Inline;
  188. { !!!!!!!!!! most routines are intentionally NOT inline !!!!!!!!!! }
  189. { Returns True if successful, False if Int Digits needed to be truncated }
  190. function NormalizeBCD ( const InBCD : tBCD;
  191. var OutBCD : tBCD;
  192. const 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. _SELECT
  1041. _WHEN BCD1.Fraction[i] < BCD2.Fraction[i]
  1042. _THEN res := -1
  1043. _WHEN BCD1.Fraction[i] > BCD2.Fraction[i]
  1044. _THEN res := +1;
  1045. _WHENOTHER
  1046. _endSELECT;
  1047. Inc ( i );
  1048. end;
  1049. if res = 0
  1050. then begin
  1051. if Odd ( pr )
  1052. then begin
  1053. f1 := BCD1.Fraction[i] AND $f0;
  1054. f2 := BCD2.Fraction[i] AND $f0;
  1055. _SELECT
  1056. _WHEN f1 < f2
  1057. _THEN res := -1
  1058. _WHEN f1 > f2
  1059. _THEN res := +1;
  1060. _endSELECT;
  1061. end;
  1062. if res = 0 then
  1063. if pr1 > pr2 then
  1064. res := +1
  1065. else if pr1 < pr2 then
  1066. res := -1;
  1067. end;
  1068. if neg1
  1069. then result := 0 - res
  1070. else result := res;
  1071. end;
  1072. _endSELECT
  1073. end;
  1074. { Convert string/Double/Integer to BCD struct }
  1075. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  1076. var BCD : tBCD ) : Boolean;
  1077. begin
  1078. Result := TryStrToBCD(aValue, BCD, DefaultFormatSettings);
  1079. end;
  1080. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  1081. var BCD : tBCD;
  1082. Const Format : TFormatSettings) : Boolean;
  1083. var
  1084. {$ifndef use_ansistring}
  1085. lav : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1086. i : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1087. {$else}
  1088. lav : {$ifopt r+} longword {$else} longword {$endif};
  1089. i : {$ifopt r+} longword {$else} longword {$endif};
  1090. {$endif}
  1091. ch : Char;
  1092. type
  1093. ife = ( inint, infrac, inexp );
  1094. {$define max_exp_scanned := 9999 }
  1095. var
  1096. inife : ife;
  1097. lvars : record
  1098. fp,
  1099. lp : ARRAY [ ife ]
  1100. {$ifndef use_ansistring}
  1101. of {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1102. pfnb : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1103. ps : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1104. pse : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1105. errp : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1106. {$else}
  1107. of {$ifopt r+} longword {$else} longword {$endif};
  1108. pfnb : {$ifopt r+} longword {$else} longword {$endif};
  1109. ps : {$ifopt r+} longword {$else} longword {$endif};
  1110. pse : {$ifopt r+} longword {$else} longword {$endif};
  1111. errp : {$ifopt r+} longword {$else} longword {$endif};
  1112. {$endif}
  1113. exp : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1114. p : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1115. bh : tBCD_helper;
  1116. nbf : Boolean;
  1117. end;
  1118. begin
  1119. result := True;
  1120. FillChar ( lvars, SizeOf ( lvars ), #0 );
  1121. BCD := NullBCD;
  1122. lav := Length ( aValue );
  1123. if lav <> 0
  1124. then
  1125. WITH lvars,
  1126. bh do
  1127. begin
  1128. while ( pfnb < lav ) AND ( NOT nbf ) do // skip leading spaces
  1129. begin
  1130. Inc ( pfnb );
  1131. nbf := aValue[pfnb] <> ' ';
  1132. end;
  1133. if nbf
  1134. then begin
  1135. if aValue[pfnb] IN [ '+', '-' ]
  1136. then begin
  1137. ps := pfnb; // position of sign
  1138. Inc ( pfnb );
  1139. end;
  1140. inife := low ( inife );
  1141. for i := pfnb TO lav do
  1142. begin
  1143. ch := aValue[i];
  1144. case ch of
  1145. '0'..'9': begin
  1146. case inife of
  1147. inint,
  1148. inexp: if fp[inife] = 0
  1149. then begin
  1150. if ch <> '0'
  1151. then begin
  1152. fp[inife] := i;
  1153. lp[inife] := i;
  1154. end;
  1155. end
  1156. else lp[inife] := i;
  1157. infrac: begin
  1158. if fp[infrac] = 0
  1159. then fp[infrac] := i;
  1160. if ch <> '0'
  1161. then lp[infrac] := i;
  1162. end;
  1163. end;
  1164. end;
  1165. ',',
  1166. '.': if ch = Format.DecimalSeparator then
  1167. begin
  1168. if inife <> inint then result := False
  1169. else inife := infrac;
  1170. end;
  1171. 'e',
  1172. 'E': if inife = inexp
  1173. then result := False
  1174. else inife := inexp;
  1175. '+',
  1176. '-': if ( inife = inexp ) AND ( fp[inexp] = 0 )
  1177. then pse := i // position of exponent sign
  1178. else result := False;
  1179. else begin
  1180. result := False;
  1181. errp := i;
  1182. end;
  1183. end;
  1184. end;
  1185. if not result
  1186. then begin
  1187. result := True;
  1188. for i := errp TO lav do // skip trailing spaces
  1189. if aValue[i] <> ' '
  1190. then result := False;
  1191. end;
  1192. if not result
  1193. then EXIT;
  1194. if ps <> 0
  1195. then Neg := aValue[ps] = '-';
  1196. if lp[infrac] = 0
  1197. then fp[infrac] := 0;
  1198. if fp[inexp] <> 0
  1199. then begin
  1200. exp := 0;
  1201. for i := fp[inexp] TO lp[inexp] do
  1202. if result
  1203. then
  1204. if aValue[i] <> Format.ThousandSeparator
  1205. then begin
  1206. exp := exp * 10 + ( Ord ( aValue[i] ) - Ord ( '0' ) );
  1207. if exp > 999
  1208. then result := False;
  1209. end;
  1210. if not result
  1211. then EXIT;
  1212. if pse <> 0
  1213. then
  1214. if aValue[pse] = '-'
  1215. then exp := -exp;
  1216. end;
  1217. p := -exp;
  1218. if fp[infrac] <> 0
  1219. then begin
  1220. for i := fp[infrac] TO lp[infrac] do
  1221. if aValue[i] <> Format.ThousandSeparator
  1222. then begin
  1223. if p < ( MaxFmtBCDFractionSize + 2 )
  1224. then begin
  1225. Inc ( p );
  1226. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1227. end;
  1228. end;
  1229. end;
  1230. LDig := p;
  1231. p := 1 - exp;
  1232. if fp[inint] <> 0
  1233. then
  1234. for i := lp[inint] DOWNTO fp[inint] do
  1235. if aValue[i] <> Format.ThousandSeparator
  1236. then begin
  1237. if p > - ( MaxFmtBCDFractionSize + 2 )
  1238. then begin
  1239. Dec ( p );
  1240. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1241. end
  1242. else result := False;
  1243. end;
  1244. if not result
  1245. then EXIT;
  1246. FDig := p;
  1247. if LDig < 0
  1248. then LDig := 0;
  1249. Plac := LDig;
  1250. result := pack_BCD ( bh, BCD );
  1251. end;
  1252. end;
  1253. end;
  1254. function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD;
  1255. begin
  1256. Result := StrToBCD(aValue, DefaultFormatSettings);
  1257. end;
  1258. function StrToBCD ( const aValue : FmtBCDStringtype;
  1259. Const Format : TFormatSettings ) : tBCD;
  1260. begin
  1261. if not TryStrToBCD ( aValue, Result, Format ) then
  1262. raise eBCDOverflowException.create ( 'in StrToBCD' );
  1263. end;
  1264. {$ifndef FPUNONE}
  1265. procedure DoubleToBCD ( const aValue : myRealtype;
  1266. var BCD : tBCD );
  1267. var
  1268. s : string [ 30 ];
  1269. f : TFormatSettings;
  1270. begin
  1271. Str ( aValue : 25, s );
  1272. f.DecimalSeparator := '.';
  1273. f.ThousandSeparator := #0;
  1274. BCD := StrToBCD ( s, f );
  1275. end;
  1276. function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline;
  1277. begin
  1278. DoubleToBCD ( aValue, result );
  1279. end;
  1280. {$endif}
  1281. function IntegerToBCD ( const aValue : myInttype ) : tBCD;
  1282. var
  1283. bh : tBCD_helper;
  1284. v : {$ifopt r+} 0..high ( myInttype ) {$else} Integer {$endif};
  1285. p : {$ifopt r+} low ( bh.Singles ) - 1..0 {$else} Integer {$endif};
  1286. exitloop : Boolean;
  1287. begin
  1288. _SELECT
  1289. _WHEN aValue = 0
  1290. _THEN result := NullBCD;
  1291. _WHEN aValue = 1
  1292. _THEN result := OneBCD;
  1293. _WHEN aValue = low ( myInttype )
  1294. _THEN
  1295. {$if declared ( myMinIntBCD ) }
  1296. result := myMinIntBCD;
  1297. {$else}
  1298. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1299. {$endif}
  1300. _WHENOTHER
  1301. bh := null_.bh;
  1302. WITH bh do
  1303. begin
  1304. Neg := aValue < 0;
  1305. if Neg
  1306. then v := -aValue
  1307. else v := +aValue;
  1308. LDig := 0;
  1309. p := 0;
  1310. REPEAT
  1311. Singles[p] := v MOD 10;
  1312. v := v DIV 10;
  1313. exitloop := v = 0;
  1314. Dec ( p );
  1315. if p < low ( Singles )
  1316. then begin
  1317. exitloop := True;
  1318. (* what to do if error occured? *)
  1319. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1320. end;
  1321. UNTIL exitloop;
  1322. FDig := p + 1;
  1323. end;
  1324. pack_BCD ( bh, result );
  1325. _endSELECT;
  1326. end;
  1327. function CurrToBCD ( const Curr : currency;
  1328. var BCD : tBCD;
  1329. Precision : Integer = 32;
  1330. Decimals : Integer = 4 ) : Boolean;
  1331. {
  1332. this works under the assumption that a currency is an int64,
  1333. except for scale of 10000
  1334. }
  1335. var
  1336. i : int64 absolute Curr;
  1337. begin
  1338. BCD := IntegerToBCD ( i );
  1339. {$ifndef bigger_BCD}
  1340. BCD.SignSpecialPlaces := 4 OR ( BCD.SignSpecialPlaces AND NegBit );
  1341. {$else}
  1342. BCD.Places := 4;
  1343. {$endif}
  1344. if Decimals <> 4 then
  1345. Result := NormalizeBCD ( BCD, BCD, Precision, Decimals )
  1346. else
  1347. CurrToBCD := True;
  1348. end;
  1349. {$ifdef comproutines}
  1350. function CompToBCD ( const Curr : Comp ) : tBCD; Inline;
  1351. var
  1352. cc : int64 absolute Curr;
  1353. begin
  1354. result := IntegerToBCD ( cc );
  1355. end;
  1356. function BCDToComp ( const BCD : tBCD ) : Comp; Inline;
  1357. var
  1358. zz : record
  1359. case Boolean of
  1360. False: ( i : int64 );
  1361. True: ( c : Comp );
  1362. end;
  1363. begin
  1364. zz.i := BCDToInteger ( BCD );
  1365. BCDToComp := zz.c;
  1366. end;
  1367. {$endif}
  1368. { Convert BCD struct to string/Double/Integer }
  1369. function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype;
  1370. begin
  1371. Result := BCDToStr(BCD, DefaultFormatSettings);
  1372. end;
  1373. function BCDToStr ( const BCD : tBCD;
  1374. Const Format : TFormatSettings ) : FmtBCDStringtype;
  1375. var
  1376. bh : tBCD_helper;
  1377. l : {$ifopt r+} 0..maxfmtbcdfractionsize + 1 + 1 {$else} Integer {$endif};
  1378. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1379. pp : {$ifopt r+} low ( bh.FDig ) - 1..1 {$else} Integer {$endif};
  1380. begin
  1381. {$ifdef use_ansistring}
  1382. result := '';
  1383. {$endif}
  1384. unpack_BCD ( BCD, bh );
  1385. WITH bh do
  1386. begin
  1387. l := 0;
  1388. if Neg
  1389. then begin
  1390. {$ifndef use_ansistring}
  1391. Inc ( l );
  1392. result[l] := '-';
  1393. {$else}
  1394. result := result + '-';
  1395. {$endif}
  1396. end;
  1397. if Prec = Plac
  1398. then begin
  1399. {$ifndef use_ansistring}
  1400. Inc ( l );
  1401. result[l] := '0';
  1402. {$else}
  1403. result := result + '0';
  1404. {$endif}
  1405. end;
  1406. if Prec > 0
  1407. then begin
  1408. pp := low ( bh.FDig ) - 1;
  1409. if Plac > 0
  1410. then pp := 1;
  1411. for i := FDig TO LDig do
  1412. begin
  1413. if i = pp
  1414. then begin
  1415. {$ifndef use_ansistring}
  1416. Inc ( l );
  1417. result[l] := Format.DecimalSeparator;
  1418. {$else}
  1419. result := result + Format.DecimalSeparator;
  1420. {$endif}
  1421. end;
  1422. {$ifndef use_ansistring}
  1423. Inc ( l );
  1424. result[l] := Chr ( Singles[i] + Ord ( '0' ) );
  1425. {$else}
  1426. result := result + Chr ( Singles[i] + Ord ( '0' ) );
  1427. {$endif}
  1428. end;
  1429. end;
  1430. end;
  1431. {$ifndef use_ansistring}
  1432. result[0] := Chr ( l );
  1433. {$endif}
  1434. end;
  1435. {$ifndef FPUNONE}
  1436. function BCDToDouble ( const BCD : tBCD ) : myRealtype;
  1437. var
  1438. bh : tBCD_helper;
  1439. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1440. r,
  1441. e : myRealtype;
  1442. begin
  1443. unpack_BCD ( BCD, bh );
  1444. WITH bh do
  1445. begin
  1446. r := 0;
  1447. e := 1;
  1448. for i := 0 DOWNTO FDig do
  1449. begin
  1450. r := r + Singles[i] * e;
  1451. e := e * 10;
  1452. end;
  1453. e := 1;
  1454. for i := 1 TO LDig do
  1455. begin
  1456. e := e / 10;
  1457. r := r + Singles[i] * e;
  1458. end;
  1459. if Neg
  1460. then BCDToDouble := -r
  1461. else BCDToDouble := +r;
  1462. end;
  1463. end;
  1464. {$endif}
  1465. function BCDToInteger ( const BCD : tBCD;
  1466. Truncate : Boolean = False ) : myInttype;
  1467. var
  1468. bh : tBCD_helper;
  1469. res : myInttype;
  1470. i : {$ifopt r+} low ( bh.FDig )..0 {$else} Integer {$endif};
  1471. {
  1472. unclear: behaviour if overflow: abort? return 0? return something?
  1473. so: checks are missing yet
  1474. }
  1475. begin
  1476. unpack_BCD ( BCD, bh );
  1477. res := 0;
  1478. WITH bh do
  1479. begin
  1480. for i := FDig TO 0 do
  1481. res := res * 10 - Singles[i];
  1482. if NOT Truncate
  1483. then
  1484. if Plac > 0
  1485. then
  1486. if Singles[1] > 4
  1487. then Dec ( res );
  1488. if Neg
  1489. then BCDToInteger := +res
  1490. else BCDToInteger := -res;
  1491. end;
  1492. end;
  1493. { From DB.pas }
  1494. function BCDToCurr ( const BCD : tBCD;
  1495. var Curr : currency ) : Boolean;
  1496. const
  1497. MaxCurr: array[boolean] of QWord = (QWord($7FFFFFFFFFFFFFFF), QWord($8000000000000000));
  1498. var
  1499. bh : tBCD_helper;
  1500. res : QWord;
  1501. c : currency absolute res;
  1502. i : {$ifopt r+} low ( bh.FDig )..4 {$else} Integer {$endif};
  1503. {
  1504. unclear: behaviour if overflow: abort? return 0? return something?
  1505. }
  1506. begin
  1507. BCDToCurr := False;
  1508. if BCDPrecision(BCD) - BCDScale(BCD) > 15 then
  1509. Exit;
  1510. unpack_BCD ( BCD, bh );
  1511. res := 0;
  1512. WITH bh do
  1513. begin
  1514. for i := FDig TO 4 do
  1515. res := res * 10 + Singles[i];
  1516. if Plac > 4
  1517. then
  1518. if Singles[5] > 4
  1519. then Inc ( res );
  1520. if res > MaxCurr[Neg] then
  1521. Exit;
  1522. if Neg then
  1523. begin
  1524. res := not res;
  1525. inc(res);
  1526. end;
  1527. Curr := c;
  1528. BCDToCurr := True;
  1529. end;
  1530. end;
  1531. procedure BCDAdd ( const BCDin1,
  1532. BCDin2 : tBCD;
  1533. var BCDout : tBCD );
  1534. var
  1535. bhr,
  1536. bh1,
  1537. bh2 : tBCD_helper;
  1538. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1539. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1540. v : {$ifopt r+} 0..9 + 9 + 1 {$else} Integer {$endif};
  1541. BCD : tBCD;
  1542. negate : Boolean;
  1543. begin
  1544. negate := IsBCDNegative ( BCDin1 );
  1545. if negate <> IsBCDNegative ( BCDin2 )
  1546. then begin
  1547. if negate
  1548. then begin
  1549. BCD := BCDin1;
  1550. BCDNegate ( BCD );
  1551. BCDSubtract ( BCDin2, BCD, BCDout );
  1552. EXIT;
  1553. end;
  1554. BCD := BCDin2;
  1555. BCDNegate ( BCD );
  1556. BCDSubtract ( BCDin1, BCD, BCDout );
  1557. EXIT;
  1558. end;
  1559. bhr := null_.bh;
  1560. WITH bhr do
  1561. begin
  1562. unpack_BCD ( BCDin1, bh1 );
  1563. unpack_BCD ( BCDin2, bh2 );
  1564. if bh1.FDig < bh2.FDig
  1565. then FDig := bh1.FDig
  1566. else FDig := bh2.FDig;
  1567. if bh1.LDig > bh2.LDig
  1568. then LDig := bh1.LDig
  1569. else LDig := bh2.LDig;
  1570. Plac := LDig;
  1571. ue := 0;
  1572. for i := LDig DOWNTO FDig do
  1573. begin
  1574. v := bh1.Singles[i] + bh2.Singles[i] + ue;
  1575. ue := v DIV 10;
  1576. Singles[i] := v MOD 10;
  1577. end;
  1578. if ue <> 0
  1579. then begin
  1580. Dec ( FDig );
  1581. Singles[FDig] := ue;
  1582. end;
  1583. Neg := negate;
  1584. end;
  1585. if NOT pack_BCD ( bhr, BCDout )
  1586. then begin
  1587. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  1588. end;
  1589. end;
  1590. procedure BCDSubtract ( const BCDin1,
  1591. BCDin2 : tBCD;
  1592. var BCDout : tBCD );
  1593. var
  1594. bhr,
  1595. bh1,
  1596. bh2 : tBCD_helper;
  1597. cmp : {$ifopt r+} -1..1 {$else} Integer {$endif};
  1598. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1599. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1600. v : {$ifopt r+} 0 - 9 - 1..9 - 0 - 0 {$else} Integer {$endif};
  1601. negate : Boolean;
  1602. BCD : tBCD;
  1603. begin
  1604. negate := IsBCDNegative ( BCDin1 );
  1605. if negate <> IsBCDNegative ( BCDin2 )
  1606. then begin
  1607. if negate
  1608. then begin
  1609. BCD := BCDin1;
  1610. BCDNegate ( BCD );
  1611. BCDAdd ( BCDin2, BCD, BCDout );
  1612. BCDNegate ( BCDout );
  1613. EXIT;
  1614. end;
  1615. BCD := BCDin2;
  1616. BCDNegate ( BCD );
  1617. BCDAdd ( BCDin1, BCD, BCDout );
  1618. EXIT;
  1619. end;
  1620. cmp := BCDCompare ( BCDin1, BCDin2 );
  1621. if cmp = 0
  1622. then begin
  1623. BCDout := NullBCD;
  1624. EXIT;
  1625. end;
  1626. bhr := null_.bh; { n n }
  1627. WITH bhr do { > < > < }
  1628. begin { }
  1629. if ( cmp > 0 ) = negate { +123 +12 -12 -123 }
  1630. then begin { - +12 - +123 - -123 - -12 }
  1631. unpack_BCD ( BCDin1, bh2 ); { x x }
  1632. unpack_BCD ( BCDin2, bh1 ); { s s s s }
  1633. negate := NOT negate; { nn n nn n }
  1634. end
  1635. else begin
  1636. unpack_BCD ( BCDin1, bh1 );
  1637. unpack_BCD ( BCDin2, bh2 );
  1638. end;
  1639. if bh1.FDig < bh2.FDig
  1640. then FDig := bh1.FDig
  1641. else FDig := bh2.FDig;
  1642. if bh1.LDig > bh2.LDig
  1643. then LDig := bh1.LDig
  1644. else LDig := bh2.LDig;
  1645. Plac := LDig;
  1646. ue := 0;
  1647. for i := LDig DOWNTO FDig do
  1648. begin
  1649. v := Integer ( bh1.Singles[i] ) - bh2.Singles[i] - ue;
  1650. ue := 0;
  1651. if v < 0
  1652. then begin
  1653. ue := 1;
  1654. Inc ( v, 10 );
  1655. end;
  1656. Singles[i] := v;
  1657. end;
  1658. Neg := negate;
  1659. if NOT pack_BCD ( bhr, BCDout )
  1660. then begin
  1661. {should never occur!}
  1662. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  1663. end;
  1664. end;
  1665. end;
  1666. { Returns True if successful, False if Int Digits needed to be truncated }
  1667. function NormalizeBCD ( const InBCD : tBCD;
  1668. var OutBCD : tBCD;
  1669. const Prec,
  1670. Scale : Word ) : Boolean;
  1671. var
  1672. bh : tBCD_helper;
  1673. tm : {$ifopt r+} 1..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  1674. begin
  1675. NormalizeBCD := True;
  1676. {$ifopt r+}
  1677. if ( Prec < 0 ) OR ( Prec > MaxFmtBCDFractionSize ) then RangeError;
  1678. if ( Scale < 0 ) OR ( Prec >= MaxFmtBCDFractionSize ) then RangeError;
  1679. {$endif}
  1680. if BCDScale ( InBCD ) > Scale
  1681. then begin
  1682. unpack_BCD ( InBCD, bh );
  1683. WITH bh do
  1684. begin
  1685. tm := Plac - Scale;
  1686. Plac := Scale;
  1687. { dec ( prec, tm ); Dec/Inc error? }
  1688. Prec := Prec - tm;
  1689. { dec ( ldig, tm ); Dec/Inc error? }
  1690. LDig := LDig - tm;
  1691. NormalizeBCD := False;
  1692. end;
  1693. if NOT pack_BCD ( bh, OutBCD )
  1694. then begin
  1695. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  1696. end;
  1697. end;
  1698. end;
  1699. procedure BCDMultiply ( const BCDin1,
  1700. BCDin2 : tBCD;
  1701. var BCDout : tBCD );
  1702. var
  1703. bh1,
  1704. bh2,
  1705. bhr : tBCD_helper;
  1706. bhrr : tBCD_helper_big;
  1707. i1 : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1708. i2 : {$ifopt r+} low ( bh2.FDig )..high ( bh2.LDig ) {$else} Integer {$endif};
  1709. i3 : {$ifopt r+} low ( bhrr.FDig )..high ( bhrr.LDig ) {$else} Integer {$endif};
  1710. v : {$ifopt r+} low ( bhrr.Singles[0] )..high ( bhrr.Singles[0] ) {$else} Integer {$endif};
  1711. ue : {$ifopt r+} low ( bhrr.Singles[0] ) DIV 10..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  1712. begin
  1713. unpack_BCD ( BCDin1, bh1 );
  1714. unpack_BCD ( BCDin2, bh2 );
  1715. if ( bh1.Prec = 0 ) OR ( bh2.Prec = 0 )
  1716. then begin
  1717. BCDout := NullBCD;
  1718. EXIT;
  1719. end;
  1720. bhr := null_.bh;
  1721. bhrr := null_.bhb;
  1722. WITH bhrr do
  1723. begin
  1724. Neg := bh1.Neg XOR bh2.Neg;
  1725. {
  1726. writeln ( __lo_bhb, ' ', __hi_bhb, ' ', bh1.fdig, ' ', bh2.fdig, ' ', low ( fdig ), ' ', low ( ldig ) );
  1727. }
  1728. FDig := bh1.FDig + bh2.FDig;
  1729. LDig := bh1.LDig + bh2.LDig;
  1730. for i1 := bh1.FDig TO bh1.LDig do
  1731. for i2 := bh2.FDig TO bh2.LDig do
  1732. begin
  1733. Inc ( Singles[i1 + i2],
  1734. bh1.Singles[i1]
  1735. * bh2.Singles[i2] );
  1736. {
  1737. write ( Singles[i1 + i2], ' ', bh1.Singles[i1], ' ', bh2.Singles[i2], ' : ' );
  1738. writeln ( Singles[i1 + i2] + bh1.Singles[i1] + bh2.Singles[i2] );
  1739. }
  1740. {
  1741. Singles[i1 + i2] := Singles[i1 + i2]
  1742. + bh1.Singles[i1]
  1743. * bh2.Singles[i2];
  1744. }
  1745. end;
  1746. {
  1747. for i3 := fdig to ldig do
  1748. write ( ' ', singles[i3] );
  1749. writeln;
  1750. }
  1751. if FDig < low ( bhr.Singles )
  1752. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1753. ue := 0;
  1754. for i3 := LDig DOWNTO FDig do
  1755. begin
  1756. v := Singles[i3] + ue;
  1757. ue := v DIV 10;
  1758. v := v MOD 10;
  1759. bhr.Singles[i3] := v;
  1760. end;
  1761. while ue <> 0 do
  1762. begin
  1763. Dec ( FDig );
  1764. if FDig < low ( bhr.Singles )
  1765. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1766. bhr.Singles[FDig] := ue MOD 10;
  1767. ue := ue DIV 10;
  1768. end;
  1769. bhr.neg := bh1.Neg XOR bh2.Neg;
  1770. bhr.Plac := LDig;
  1771. bhr.FDig := FDig;
  1772. if LDig > high ( bhr.Singles )
  1773. then bhr.LDig := high ( bhr.Singles )
  1774. else bhr.LDig := LDig;
  1775. end;
  1776. if NOT pack_BCD ( bhr, BCDout )
  1777. then begin
  1778. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1779. end;
  1780. end;
  1781. {$ifndef FPUNONE}
  1782. procedure BCDMultiply ( const BCDIn : tBCD;
  1783. const DoubleIn : myRealtype;
  1784. var BCDout : tBCD ); Inline;
  1785. begin
  1786. BCDMultiply ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  1787. end;
  1788. {$endif}
  1789. procedure BCDMultiply ( const BCDIn : tBCD;
  1790. const StringIn : FmtBCDStringtype;
  1791. var BCDout : tBCD ); Inline;
  1792. begin
  1793. BCDMultiply ( BCDIn, StrToBCD ( StringIn ), BCDout );
  1794. end;
  1795. procedure BCDMultiply ( const StringIn1,
  1796. StringIn2 : FmtBCDStringtype;
  1797. var BCDout : tBCD ); Inline;
  1798. begin
  1799. BCDMultiply ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  1800. end;
  1801. procedure BCDDivide ( const Dividend,
  1802. Divisor : tBCD;
  1803. var BCDout : tBCD );
  1804. var
  1805. bh1 : ARRAY [ Boolean ] of tBCD_helper;
  1806. bh2,
  1807. bh : tBCD_helper;
  1808. p : {$ifopt r+} low ( bh.FDig ) - high ( bh.FDig )..high ( bh.FDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1809. v1 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1810. v2 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1811. lFDig : {$ifopt r+} low ( bh.FDig )..high ( bh.FDig ) {$else} Integer {$endif};
  1812. d1 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1813. d2 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1814. d : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1815. lLdig : {$ifopt r+} low ( lFDig ) + low ( d )..high ( lFDig ) + high ( d ) {$else} Integer {$endif};
  1816. tm : {$ifopt r+} low ( lLdig ) - high ( bh2.Singles )..high ( lLdig ) - high ( bh2.Singles ) {$else} Integer {$endif};
  1817. i2 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1818. i3 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1819. ie : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1820. i4 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1821. nFDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1822. nLDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1823. dd : {$ifopt r+} 0..9 {$else} Integer {$endif};
  1824. Add : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1825. ue : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1826. 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};
  1827. v4 : {$ifopt r+} low ( bh.Singles[0] ) + low ( add )..high ( bh.Singles[0] ) + high ( add ) {$else} Integer {$endif};
  1828. FlipFlop,
  1829. nz,
  1830. sf,
  1831. sh,
  1832. fdset : Boolean;
  1833. {
  1834. bh1p : ARRAY [ Boolean ] of ^ tBCD_helper;
  1835. }
  1836. begin
  1837. { test:
  1838. bh1p[false] := @ bh1[false];
  1839. bh1p[true] := @ bh1[true];
  1840. v := bh1[false].singles[0];
  1841. v := bh1[true].singles[0];
  1842. v := bh1p[false]^.singles[0];
  1843. v := bh1p[true]^.singles[0];
  1844. v := bh1[nz].singles[0];
  1845. v := bh1p[nz]^.singles[0];
  1846. }
  1847. unpack_BCD ( Divisor, bh2 );
  1848. unpack_BCD ( Dividend, bh1[False] );
  1849. p := bh1[False].FDig - bh2.FDig;
  1850. _SELECT
  1851. _WHEN bh2.Prec = 0
  1852. _THEN RAISE eBCDException.create ( 'Division by zero' );
  1853. _WHEN bh1[False].Prec = 0
  1854. _THEN BCDout := NullBCD;
  1855. _WHEN p < low ( bh2.Singles )
  1856. _THEN RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  1857. _WHENOTHER
  1858. bh := null_.bh;
  1859. bh.Neg := bh1[False].Neg XOR bh2.Neg;
  1860. if p <= high ( bh.Singles )
  1861. then begin
  1862. bh1[True] := null_.bh;
  1863. FlipFlop := False;
  1864. fdset := p > 0;
  1865. Add := 0;
  1866. nz := True;
  1867. while nz do
  1868. WITH bh1[FlipFlop] do
  1869. begin
  1870. {
  1871. WriteLn('#####');
  1872. dumpbh ( bh1[flipflop] );
  1873. dumpbh ( bh2 );
  1874. dumpbh ( bh );
  1875. }
  1876. if ( Singles[FDig] + bh2.Singles[bh2.FDig] ) = 0
  1877. then begin
  1878. if ( FDig >= LDig )
  1879. OR ( bh2.FDig >= bh2.LDig )
  1880. then nz := False
  1881. else begin
  1882. Inc ( FDig );
  1883. Inc ( bh2.FDig );
  1884. end;
  1885. end
  1886. else begin
  1887. v1 := Singles[FDig];
  1888. v2 := bh2.Singles[bh2.FDig];
  1889. sh := v1 < v2;
  1890. if ( v1 = v2 )
  1891. then begin
  1892. nz := False;
  1893. i3 := Succ ( FDig );
  1894. ie := LDig;
  1895. while ( i3 <= ie ) AND ( NOT nz ) AND ( NOT sh ) do
  1896. begin
  1897. v1 := Singles[i3];
  1898. v2 := bh2.Singles[i3 - p];
  1899. if v1 <> v2
  1900. then begin
  1901. nz := True;
  1902. if v1 < v2
  1903. then sh := True;
  1904. end;
  1905. Inc ( i3 );
  1906. end;
  1907. end;
  1908. if NOT nz
  1909. then Add := 1
  1910. else begin
  1911. if sh
  1912. then begin
  1913. Inc ( p );
  1914. {
  1915. if p > 3 then halt;
  1916. }
  1917. if p > high ( bh.Singles )
  1918. then nz := False
  1919. else Dec ( bh2.FDig );
  1920. end
  1921. else begin
  1922. lFDig := FDig;
  1923. d1 := LDig - FDig;
  1924. d2 := bh2.LDig - bh2.FDig;
  1925. if d1 > d2
  1926. then d := d1
  1927. else d := d2;
  1928. lLdig := lFDig + d;
  1929. if lLdig > high ( bh2.Singles )
  1930. then begin
  1931. tm := ( lLdig ) - high ( bh2.Singles );
  1932. d := d - tm;
  1933. lLdig := lLdig - tm;
  1934. {runden?}
  1935. end;
  1936. sf := True;
  1937. Add := 0;
  1938. nFDig := 0;
  1939. nLDig := 0;
  1940. ue := 0;
  1941. dd := Singles[lFDig] DIV ( bh2.Singles[lFDig - p] + 1 );
  1942. if dd < 1
  1943. then dd := 1;
  1944. {
  1945. writeln ( 'p=', p, ' dd=', dd, ' lFdig=', lfdig, ' lldig=', lldig );
  1946. }
  1947. for i2 := lLdig DOWNTO lFDig do
  1948. begin
  1949. v3 := Singles[i2] - bh2.Singles[i2 - p] * dd - ue;
  1950. ue := 0;
  1951. while v3 < 0 do
  1952. begin
  1953. Inc ( ue );;
  1954. v3 := v3 + 10;
  1955. end;
  1956. {
  1957. if v3 <> 0
  1958. then begin
  1959. }
  1960. bh1[NOT FlipFlop].Singles[i2] := v3;
  1961. {
  1962. nFDig := i2;
  1963. if sf
  1964. then begin
  1965. nLDig := i2;
  1966. sf := False;
  1967. end;
  1968. end;
  1969. }
  1970. end;
  1971. sf := False;
  1972. nFDig := lFDig;
  1973. nLDig := lLDig;
  1974. Inc ( Add, dd );
  1975. if sf
  1976. then nz := False
  1977. else begin
  1978. FillChar ( bh1[FlipFlop], SizeOf ( bh1[FlipFlop] ), #0 );
  1979. FlipFlop := NOT FlipFlop;
  1980. WITH bh1[FlipFlop] do
  1981. begin
  1982. FDig := nFDig;
  1983. LDig := nLDig;
  1984. end;
  1985. end;
  1986. end;
  1987. end;
  1988. if Add <> 0
  1989. then begin
  1990. if NOT fdset
  1991. then begin
  1992. bh.FDig := p;
  1993. fdset := True;
  1994. end;
  1995. if bh.LDig < p
  1996. then begin
  1997. bh.LDig := p;
  1998. if ( bh.LDig - bh.FDig ) > Succ ( MaxFmtBCDFractionSize )
  1999. then nz := False;
  2000. end;
  2001. i4 := p;
  2002. while ( Add <> 0 ) AND ( i4 >= bh.FDig ) do
  2003. begin
  2004. {
  2005. writeln ( '> ', i4, ' ', bh.Singles[i4], ' ', Add );
  2006. }
  2007. v4 := bh.Singles[i4] + Add;
  2008. Add := v4 DIV 10;
  2009. bh.Singles[i4] := v4 MOD 10;
  2010. Dec ( i4 );
  2011. end;
  2012. if Add <> 0
  2013. then begin
  2014. Dec ( bh.FDig );
  2015. bh.Singles[bh.FDig] := Add;
  2016. Add := 0;
  2017. end;
  2018. end;
  2019. end;
  2020. end;
  2021. end;
  2022. WITH bh do
  2023. begin
  2024. if LDig < 0
  2025. then LDig := 0;
  2026. if LDig > 0
  2027. then Plac := LDig
  2028. else Plac := 0;
  2029. end;
  2030. if NOT pack_BCD ( bh, BCDout )
  2031. then begin
  2032. RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  2033. end;
  2034. _endSELECT
  2035. end;
  2036. procedure BCDDivide ( const Dividend,
  2037. Divisor : FmtBCDStringtype;
  2038. var BCDout : tBCD ); Inline;
  2039. begin
  2040. BCDDivide ( StrToBCD ( Dividend ), StrToBCD ( Divisor ), BCDout );
  2041. end;
  2042. {$ifndef FPUNONE}
  2043. procedure BCDDivide ( const Dividend : tBCD;
  2044. const Divisor : myRealtype;
  2045. var BCDout : tBCD ); Inline;
  2046. begin
  2047. BCDDivide ( Dividend, DoubleToBCD ( Divisor ), BCDout );
  2048. end;
  2049. {$endif}
  2050. procedure BCDDivide ( const Dividend : tBCD;
  2051. const Divisor : FmtBCDStringtype;
  2052. var BCDout : tBCD ); Inline;
  2053. begin
  2054. BCDDivide ( Dividend, StrToBCD ( Divisor ), BCDout );
  2055. end;
  2056. { TBCD variant creation utils }
  2057. procedure VarFmtBCDCreate ( var aDest : Variant;
  2058. const aBCD : tBCD );
  2059. begin
  2060. VarClear(aDest);
  2061. TVarData(aDest).Vtype:=FMTBcdFactory.Vartype;
  2062. TVarData(aDest).VPointer:=TFMTBcdVarData.create(aBCD);
  2063. end;
  2064. function VarFmtBCDCreate : Variant;
  2065. begin
  2066. VarFmtBCDCreate ( result, NullBCD );
  2067. end;
  2068. function VarFmtBCDCreate ( const aValue : FmtBCDStringtype;
  2069. Precision,
  2070. Scale : Word ) : Variant;
  2071. begin
  2072. VarFmtBCDCreate ( result, StrToBCD ( aValue ) );
  2073. end;
  2074. {$ifndef FPUNONE}
  2075. function VarFmtBCDCreate ( const aValue : myRealtype;
  2076. Precision : Word = 18;
  2077. Scale : Word = 4 ) : Variant;
  2078. begin
  2079. VarFmtBCDCreate ( result, DoubleToBCD ( aValue ) );
  2080. end;
  2081. {$endif}
  2082. function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant;
  2083. begin
  2084. VarFmtBCDCreate ( result, aBCD );
  2085. end;
  2086. function VarIsFmtBCD ( const aValue : Variant ) : Boolean;
  2087. begin
  2088. Result:=TVarData(aValue).VType=FMTBcdFactory.VarType;
  2089. end;
  2090. function VarFmtBCD : TVartype;
  2091. begin
  2092. Result:=FMTBcdFactory.VarType;
  2093. end;
  2094. { Formatting BCD as string }
  2095. function BCDToStrF ( const BCD : tBCD;
  2096. Format : TFloatFormat;
  2097. const Precision,
  2098. Digits : Integer ) : FmtBCDStringtype;
  2099. var P, E: integer;
  2100. Negative: boolean;
  2101. DS, TS: char;
  2102. procedure RoundDecimalDigits(const d: integer);
  2103. var i,j: integer;
  2104. begin
  2105. j:=P+d;
  2106. if (Length(Result) > j) and (Result[j+1] >= '5') then
  2107. for i:=j downto 1+ord(Negative) do
  2108. begin
  2109. if Result[i] = '9' then
  2110. begin
  2111. Result[i] := '0';
  2112. if i = 1+ord(Negative) then
  2113. begin
  2114. Insert('1', Result, i);
  2115. inc(P);
  2116. inc(j);
  2117. end;
  2118. end
  2119. else if Result[i] <> DS then
  2120. begin
  2121. inc(Result[i]);
  2122. break;
  2123. end;
  2124. end;
  2125. if d = 0 then dec(j); // if decimal separator is last char then do not copy them
  2126. Result := copy(Result, 1, j);
  2127. end;
  2128. procedure AddDecimalDigits(d: integer);
  2129. var n: integer;
  2130. begin
  2131. if P > Length(Result) then // there isn't decimal separator
  2132. if d = 0 then
  2133. Exit
  2134. else
  2135. Result := Result + DS;
  2136. n := d + P - Length(Result);
  2137. if n > 0 then
  2138. Result := Result + StringOfChar('0', n)
  2139. else if n < 0 then
  2140. RoundDecimalDigits(d);
  2141. end;
  2142. procedure AddThousandSeparators;
  2143. begin
  2144. Dec(P, 3);
  2145. While (P > 1) Do
  2146. Begin
  2147. If (Result[P - 1] <> '-') And (TS <> #0) Then
  2148. Insert(TS, Result, P);
  2149. Dec(P, 3);
  2150. End;
  2151. end;
  2152. begin
  2153. Result := BCDToStr(BCD);
  2154. if Format = ffGeneral then Exit;
  2155. DS:=DefaultFormatSettings.DecimalSeparator;
  2156. TS:=DefaultFormatSettings.ThousandSeparator;
  2157. Negative := Result[1] = '-';
  2158. P := Pos(DS, Result);
  2159. if P = 0 then
  2160. P := Length(Result) + 1;
  2161. Case Format Of
  2162. ffExponent:
  2163. Begin
  2164. E := P - 2 - ord(Negative);
  2165. if (E = 0) and (Result[P-1] = '0') then // 0.###
  2166. repeat
  2167. dec(E);
  2168. until (Length(Result) <= P-E) or (Result[P-E] <> '0');
  2169. if E <> 0 then
  2170. begin
  2171. System.Delete(Result, P, 1);
  2172. dec(P, E);
  2173. Insert(DS, Result, P);
  2174. end;
  2175. AddDecimalDigits(Precision-1);
  2176. if E < 0 then
  2177. begin
  2178. System.Delete(Result, P+E-1, -E);
  2179. Result := Result + SysUtils.Format('E%.*d' , [Digits,E])
  2180. end
  2181. else
  2182. Result := Result + SysUtils.Format('E+%.*d', [Digits,E]);
  2183. End;
  2184. ffFixed:
  2185. Begin
  2186. AddDecimalDigits(Digits);
  2187. End;
  2188. ffNumber:
  2189. Begin
  2190. AddDecimalDigits(Digits);
  2191. AddThousandSeparators;
  2192. End;
  2193. ffCurrency:
  2194. Begin
  2195. //implementation based on FloatToStrFIntl()
  2196. if Negative then System.Delete(Result, 1, 1);
  2197. AddDecimalDigits(Digits);
  2198. AddThousandSeparators;
  2199. If Not Negative Then
  2200. Begin
  2201. Case FormatSettings.CurrencyFormat Of
  2202. 0: Result := FormatSettings.CurrencyString + Result;
  2203. 1: Result := Result + FormatSettings.CurrencyString;
  2204. 2: Result := FormatSettings.CurrencyString + ' ' + Result;
  2205. 3: Result := Result + ' ' + FormatSettings.CurrencyString;
  2206. End
  2207. End
  2208. Else
  2209. Begin
  2210. Case FormatSettings.NegCurrFormat Of
  2211. 0: Result := '(' + FormatSettings.CurrencyString + Result + ')';
  2212. 1: Result := '-' + FormatSettings.CurrencyString + Result;
  2213. 2: Result := FormatSettings.CurrencyString + '-' + Result;
  2214. 3: Result := FormatSettings.CurrencyString + Result + '-';
  2215. 4: Result := '(' + Result + FormatSettings.CurrencyString + ')';
  2216. 5: Result := '-' + Result + FormatSettings.CurrencyString;
  2217. 6: Result := Result + '-' + FormatSettings.CurrencyString;
  2218. 7: Result := Result + FormatSettings.CurrencyString + '-';
  2219. 8: Result := '-' + Result + ' ' + FormatSettings.CurrencyString;
  2220. 9: Result := '-' + FormatSettings.CurrencyString + ' ' + Result;
  2221. 10: Result := FormatSettings.CurrencyString + ' ' + Result + '-';
  2222. End;
  2223. End;
  2224. End;
  2225. End;
  2226. end;
  2227. function FormatBCD ( const Format : string;
  2228. BCD : tBCD ) : FmtBCDStringtype;
  2229. // Tests: tests/test/units/fmtbcd/
  2230. type
  2231. TSection=record
  2232. FmtStart, FmtEnd, // positions in Format string,
  2233. Fmt1Dig, // position of 1st digit placeholder,
  2234. FmtDS: PChar; // position of decimal point
  2235. Digits: integer; // number of all digit placeholders
  2236. DigDS: integer; // number of digit placeholders after decimal separator
  2237. HasTS, HasDS: boolean; // has thousand or decimal separator?
  2238. end;
  2239. var
  2240. PFmt: PChar;
  2241. i, j, j1, je, ReqSec, Sec, Scale: integer;
  2242. Section: TSection;
  2243. FF: TFloatFormat;
  2244. BCDStr: string; // BCDToStrF of given BCD parameter
  2245. Buf: array [0..85] of char; // output buffer
  2246. // Parses Format parameter, their sections (positive;negative;zero) and
  2247. // builds Section information for requested section
  2248. procedure ParseFormat;
  2249. var C,Q: Char;
  2250. PFmtEnd: PChar;
  2251. Section1: TSection;
  2252. begin
  2253. PFmt:=@Format[1];
  2254. PFmtEnd:=PFmt+length(Format);
  2255. Section.FmtStart:=PFmt;
  2256. Section.Fmt1Dig:=nil;
  2257. Section.Digits:=0;
  2258. Section.HasTS:=false; // has thousand separator?
  2259. Section.HasDS:=false; // has decimal separator?
  2260. Sec:=1;
  2261. while true do begin
  2262. if PFmt>=PFmtEnd then
  2263. C:=#0 // hack if short strings used
  2264. else
  2265. C:=PFmt^;
  2266. case C of
  2267. '''', '"':
  2268. begin
  2269. Q:=PFmt^;
  2270. inc(PFmt);
  2271. while (PFmt<PFmtEnd-1) and (PFmt^<>Q) do
  2272. inc(PFmt);
  2273. end;
  2274. #0, ';': // end of Format string or end of section
  2275. begin
  2276. if Sec > 1 then
  2277. Section.FmtStart:=Section.FmtEnd+1;
  2278. Section.FmtEnd:=PFmt;
  2279. if not assigned(Section.Fmt1Dig) then
  2280. Section.Fmt1Dig:=Section.FmtEnd;
  2281. if not Section.HasDS then
  2282. begin
  2283. Section.FmtDS := Section.FmtEnd;
  2284. Section.DigDS := 0;
  2285. end;
  2286. if Sec = 1 then
  2287. Section1 := Section;
  2288. if (C = #0) or (Sec=ReqSec) then
  2289. break;
  2290. Section.Fmt1Dig:=nil;
  2291. Section.Digits:=0;
  2292. Section.HasTS:=false;
  2293. Section.HasDS:=false;
  2294. inc(Sec);
  2295. end;
  2296. '.': // decimal point
  2297. begin
  2298. Section.HasDS:=true;
  2299. Section.FmtDS:=PFmt;
  2300. Section.DigDS:=0;
  2301. end;
  2302. ',': // thousand separator
  2303. Section.HasTS:=true;
  2304. '0','#': // digits placeholders
  2305. begin
  2306. if not assigned(Section.Fmt1Dig) then Section.Fmt1Dig:=PFmt;
  2307. inc(Section.Digits);
  2308. inc(Section.DigDS);
  2309. end;
  2310. end;
  2311. inc(PFmt);
  2312. end;
  2313. // if requested section does not exists or is empty use first section
  2314. if (ReqSec > Sec) or (Section.FmtStart=Section.FmtEnd) then
  2315. begin
  2316. Section := Section1;
  2317. Sec := 1;
  2318. end;
  2319. end;
  2320. procedure PutFmtDigit(var AFmt: PChar; var iBCDStr, iBuf: integer; MoveBy: integer);
  2321. var ADig, Q: Char;
  2322. begin
  2323. if (iBuf < low(Buf)) or (iBuf > high(Buf)) then
  2324. raise eBCDOverflowException.Create ( 'in FormatBCD' );
  2325. if (iBCDStr < 1) or (iBCDStr > length(BCDStr)) then
  2326. ADig:=#0
  2327. else
  2328. ADig:=BCDStr[iBCDStr];
  2329. // write remaining leading part of BCDStr if there are no more digit placeholders in Format string
  2330. if ((AFmt < Section.Fmt1Dig) and (AFmt < Section.FmtDS) and (ADig <> #0)) or
  2331. (ADig = DefaultFormatSettings.ThousandSeparator) then
  2332. begin
  2333. Buf[iBuf] := BCDStr[iBCDStr];
  2334. inc(iBCDStr, MoveBy);
  2335. inc(iBuf, MoveBy);
  2336. Exit;
  2337. end;
  2338. case AFmt^ of
  2339. '''','"':
  2340. begin
  2341. Q:=AFmt^;
  2342. inc(AFmt, MoveBy);
  2343. // write all characters between quotes
  2344. while (AFmt>Section.FmtStart) and (AFmt<Section.FmtEnd) and (AFmt^ <> Q) do
  2345. begin
  2346. Buf[iBuf] := AFmt^;
  2347. inc(AFmt, MoveBy);
  2348. inc(iBuf, MoveBy);
  2349. end;
  2350. end;
  2351. '0','.':
  2352. begin
  2353. if AFmt^ = '.' then
  2354. Buf[iBuf] := DefaultFormatSettings.DecimalSeparator
  2355. else if ADig = #0 then
  2356. Buf[iBuf] := '0'
  2357. else
  2358. Buf[iBuf] := ADig;
  2359. inc(AFmt, MoveBy);
  2360. inc(iBCDStr, MoveBy);
  2361. inc(iBuf, MoveBy);
  2362. end;
  2363. '#':
  2364. begin
  2365. if ADig = #0 then
  2366. inc(AFmt, MoveBy)
  2367. else if (ADig = '0') and (iBCDStr = 1) then // skip leading zero
  2368. begin
  2369. inc(AFmt, MoveBy);
  2370. inc(iBCDStr, MoveBy);
  2371. end
  2372. else
  2373. begin
  2374. Buf[iBuf] := ADig;
  2375. inc(AFmt, MoveBy);
  2376. inc(iBCDStr, MoveBy);
  2377. inc(iBuf, MoveBy);
  2378. end;
  2379. end;
  2380. ',':
  2381. begin
  2382. inc(AFmt, MoveBy); // thousand separators are already in BCDStr
  2383. end;
  2384. else // write character what is in Format as is
  2385. begin
  2386. Buf[iBuf] := AFmt^;
  2387. inc(AFmt, MoveBy);
  2388. inc(iBuf, MoveBy);
  2389. end;
  2390. end;
  2391. end;
  2392. begin
  2393. case BCDCompare(BCD, NullBCD) of
  2394. 1: ReqSec := 1;
  2395. 0: ReqSec := 3;
  2396. -1: ReqSec := 2;
  2397. end;
  2398. // remove sign for negative value
  2399. if ReqSec = 2 then
  2400. BCDNegate(BCD);
  2401. // parse Format into Section
  2402. ParseFormat;
  2403. if Section.FmtStart=Section.FmtEnd then // empty section
  2404. FF := ffGeneral
  2405. else if Section.HasTS then
  2406. FF := ffNumber
  2407. else
  2408. FF := ffFixed;
  2409. Scale := BCDScale(BCD);
  2410. if (FF <> ffGeneral) and (Scale > Section.DigDS) then // we need rounding
  2411. Scale := Section.DigDS;
  2412. BCDStr := BCDToStrF(BCD, FF, 64, Scale);
  2413. if (FF = ffGeneral) then
  2414. begin
  2415. Result:=BCDStr;
  2416. Exit;
  2417. end;
  2418. // write to output buffer
  2419. j1 := high(Buf); // position of 1st number before decimal point in output buffer
  2420. je := length(Buf); // position after last digit in output buffer
  2421. // output decimal part of BCDStr
  2422. if Section.HasDS and (Section.FmtEnd-Section.FmtDS>1) then // is there something after decimal point?
  2423. begin
  2424. PFmt := Section.FmtDS; // start from decimal point until end
  2425. i := length(BCDStr) - Scale + ord(Scale=0);
  2426. dec(j1, Section.FmtEnd-Section.FmtDS);
  2427. j := j1 + 1;
  2428. while PFmt < Section.FmtEnd do
  2429. PutFmtDigit(PFmt, i, j, 1);
  2430. je := j; // store position after last decimal digit
  2431. end;
  2432. // output whole number part of BCDStr
  2433. PFmt := Section.FmtDS - 1;
  2434. i := length(BCDStr) - Scale - ord(Scale<>0);
  2435. j := j1;
  2436. while (i>0) and (j>0) do
  2437. PutFmtDigit(PFmt, i, j, -1);
  2438. // output leading '0' (f.e. '001.23')
  2439. while (PFmt >= Section.FmtStart) and (PFmt^ = '0') do
  2440. PutFmtDigit(PFmt, i, j, -1);
  2441. // output sign (-), if value is negative, and does not exists 2nd section
  2442. if (ReqSec = 2) and (Sec = 1) then
  2443. begin
  2444. Buf[j]:='-';
  2445. dec(j);
  2446. end;
  2447. // output remaining chars from begining of Format (f.e. 'abc' if given Format is 'abc0.00')
  2448. while PFmt >= Section.FmtStart do
  2449. PutFmtDigit(PFmt, i, j, -1);
  2450. inc(j);
  2451. if j > high(Buf) then
  2452. Result := ''
  2453. else
  2454. SetString(Result, @Buf[j], je-j);
  2455. end;
  2456. {$ifdef additional_routines}
  2457. function CurrToBCD ( const Curr : currency ) : tBCD; Inline;
  2458. begin
  2459. CurrToBCD ( Curr, result );
  2460. end;
  2461. procedure BCDAdd ( const BCDIn : tBCD;
  2462. const IntIn : myInttype;
  2463. var BCDout : tBCD );
  2464. var
  2465. BCD : tBCD;
  2466. bhr : tBCD_helper;
  2467. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2468. ue : {$ifopt r+} 0..high ( IntIn ) - 9 {$else} Integer {$endif};
  2469. v : {$ifopt r+} 0..{high ( ue ) + 9} high ( IntIn ) {$else} Integer {$endif};
  2470. nz : Boolean;
  2471. begin
  2472. if IntIn = 0
  2473. then begin
  2474. BCDout := BCDIn;
  2475. EXIT;
  2476. end;
  2477. if IntIn = low ( myInttype )
  2478. then begin
  2479. {$if declared ( myMinIntBCD ) }
  2480. BCDAdd ( BCDIn, myMinIntBCD, BCDout );
  2481. EXIT;
  2482. {$else}
  2483. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2484. {$endif}
  2485. end;
  2486. if IsBCDNegative ( BCDIn )
  2487. then begin
  2488. BCD := BCDIn;
  2489. BCDNegate ( BCD );
  2490. if IntIn < 0
  2491. then BCDAdd ( BCD, -IntIn, BCDout )
  2492. else BCDSubtract ( BCD, IntIn, BCDout );
  2493. BCDNegate ( BCDout );
  2494. EXIT;
  2495. end;
  2496. if IntIn < 0
  2497. then begin
  2498. BCDSubtract ( BCDIn, -IntIn, BCDout );
  2499. EXIT;
  2500. end;
  2501. if IntIn > ( high ( IntIn ) - 9 )
  2502. then begin
  2503. BCDAdd ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2504. EXIT;
  2505. end;
  2506. unpack_BCD ( BCDIn, bhr );
  2507. p := 0;
  2508. nz := True;
  2509. ue := IntIn;
  2510. while nz do
  2511. begin
  2512. v := bhr.Singles[p] + ue;
  2513. bhr.Singles[p] := v MOD 10;
  2514. ue := v DIV 10;
  2515. if ue = 0
  2516. then nz := False
  2517. else Dec ( p );
  2518. end;
  2519. if p < bhr.FDig
  2520. then begin
  2521. bhr.FDig := p;
  2522. bhr.Prec := bhr.Prec + ( bhr.FDig - p );
  2523. end;
  2524. if NOT pack_BCD ( bhr, BCDout )
  2525. then begin
  2526. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2527. end;
  2528. end;
  2529. procedure BCDSubtract ( const BCDIn : tBCD;
  2530. const IntIn : myInttype;
  2531. var BCDout : tBCD );
  2532. {}
  2533. var
  2534. BCD : tBCD;
  2535. bhr : tBCD_helper;
  2536. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2537. ue : {$ifopt r+} 0..pred ( 100000000 ) {$else} Integer {$endif};
  2538. v : {$ifopt r+} -9..9 {$else} Integer {$endif};
  2539. direct : Boolean;
  2540. {}
  2541. begin
  2542. if IntIn = 0
  2543. then begin
  2544. BCDout := BCDIn;
  2545. EXIT;
  2546. end;
  2547. if IntIn = low ( myInttype )
  2548. then begin
  2549. {$if declared ( myMinIntBCD ) }
  2550. BCDSubtract ( BCDIn, myMinIntBCD, BCDout );
  2551. EXIT;
  2552. {$else}
  2553. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2554. {$endif}
  2555. end;
  2556. if IsBCDNegative ( BCDIn )
  2557. then begin
  2558. BCD := BCDIn;
  2559. BCDNegate ( BCD );
  2560. if IntIn < 0
  2561. then BCDSubtract ( BCD, -IntIn, BCDout )
  2562. else BCDAdd ( BCD, IntIn, BCDout );
  2563. BCDNegate ( BCDout );
  2564. EXIT;
  2565. end;
  2566. if IntIn < 0
  2567. then begin
  2568. BCDAdd ( BCDIn, -IntIn, BCDout );
  2569. EXIT;
  2570. end;
  2571. direct := False;
  2572. case BCDIn.Precision
  2573. -
  2574. {$ifndef bigger_BCD}
  2575. ( BCDIn.SignSpecialPlaces AND PlacesMask )
  2576. {$else}
  2577. BCDIn.Places
  2578. {$endif}
  2579. of
  2580. 2: direct := IntIn < 10;
  2581. 3: direct := IntIn < 100;
  2582. 4: direct := IntIn < 1000;
  2583. 5: direct := IntIn < 10000;
  2584. 6: direct := IntIn < 100000;
  2585. 7: direct := IntIn < 1000000;
  2586. 8: direct := IntIn < 10000000;
  2587. 9: direct := IntIn < 100000000;
  2588. end;
  2589. {
  2590. write(direct);dumpbcd(bcdin);write('[',intin,']');
  2591. }
  2592. if direct
  2593. then begin
  2594. unpack_BCD ( BCDIn, bhr );
  2595. WITH bhr do
  2596. begin
  2597. p := 0;
  2598. ue := IntIn;
  2599. while p >= FDig do
  2600. begin
  2601. v := Singles[p] - ue MOD 10;
  2602. ue := ue DIV 10;
  2603. if v < 0
  2604. then begin
  2605. v := v + 10;
  2606. ue := ue + 1;
  2607. end;
  2608. Singles[p] := v;
  2609. Dec ( p );
  2610. end;
  2611. end;
  2612. if NOT pack_BCD ( bhr, BCDout )
  2613. then begin
  2614. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2615. end;
  2616. end
  2617. else
  2618. {}
  2619. BCDSubtract ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2620. end;
  2621. procedure BCDAdd ( const IntIn : myInttype;
  2622. const BCDIn : tBCD;
  2623. var BCDout : tBCD ); Inline;
  2624. begin
  2625. BCDAdd ( BCDIn, IntIn, BCDout );
  2626. end;
  2627. {$ifndef FPUNONE}
  2628. procedure BCDAdd ( const BCDIn : tBCD;
  2629. const DoubleIn : myRealtype;
  2630. var BCDout : tBCD ); Inline;
  2631. begin
  2632. BCDAdd ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2633. end;
  2634. procedure BCDAdd ( const DoubleIn : myRealtype;
  2635. const BCDIn : tBCD;
  2636. var BCDout : tBCD ); Inline;
  2637. begin
  2638. BCDAdd ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2639. end;
  2640. {$endif}
  2641. procedure BCDAdd ( const BCDIn : tBCD;
  2642. const Currin : currency;
  2643. var BCDout : tBCD ); Inline;
  2644. begin
  2645. BCDAdd ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2646. end;
  2647. procedure BCDAdd ( const Currin : currency;
  2648. const BCDIn : tBCD;
  2649. var BCDout : tBCD ); Inline;
  2650. begin
  2651. BCDAdd ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2652. end;
  2653. {$ifdef comproutines}
  2654. procedure BCDAdd ( const BCDIn : tBCD;
  2655. const Compin : Comp;
  2656. var BCDout : tBCD ); Inline;
  2657. begin
  2658. BCDAdd ( BCDIn, CompToBCD ( Compin ), BCDout );
  2659. end;
  2660. procedure BCDAdd ( const Compin : Comp;
  2661. const BCDIn : tBCD;
  2662. var BCDout : tBCD ); Inline;
  2663. begin
  2664. BCDAdd ( CompToBCD ( Compin ), BCDIn, BCDout );
  2665. end;
  2666. {$endif}
  2667. procedure BCDAdd ( const BCDIn : tBCD;
  2668. const StringIn : FmtBCDStringtype;
  2669. var BCDout : tBCD ); Inline;
  2670. begin
  2671. BCDAdd ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2672. end;
  2673. procedure BCDAdd ( const StringIn : FmtBCDStringtype;
  2674. const BCDIn : tBCD;
  2675. var BCDout : tBCD ); Inline;
  2676. begin
  2677. BCDAdd ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2678. end;
  2679. procedure BCDAdd ( const StringIn1,
  2680. StringIn2 : FmtBCDStringtype;
  2681. var BCDout : tBCD ); Inline;
  2682. begin
  2683. BCDAdd ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2684. end;
  2685. procedure BCDSubtract ( const IntIn : myInttype;
  2686. const BCDIn : tBCD;
  2687. var BCDout : tBCD ); Inline;
  2688. begin
  2689. BCDSubtract ( BCDIn, IntIn, BCDout );
  2690. BCDNegate ( BCDout );
  2691. end;
  2692. {$ifndef FPUNONE}
  2693. procedure BCDSubtract ( const BCDIn : tBCD;
  2694. const DoubleIn : myRealtype;
  2695. var BCDout : tBCD ); Inline;
  2696. begin
  2697. BCDSubtract ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2698. end;
  2699. procedure BCDSubtract ( const DoubleIn : myRealtype;
  2700. const BCDIn : tBCD;
  2701. var BCDout : tBCD ); Inline;
  2702. begin
  2703. BCDSubtract ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2704. end;
  2705. {$endif}
  2706. procedure BCDSubtract ( const BCDIn : tBCD;
  2707. const Currin : currency;
  2708. var BCDout : tBCD ); Inline;
  2709. begin
  2710. BCDSubtract ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2711. end;
  2712. procedure BCDSubtract ( const Currin : currency;
  2713. const BCDIn : tBCD;
  2714. var BCDout : tBCD ); Inline;
  2715. begin
  2716. BCDSubtract ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2717. end;
  2718. {$ifdef comproutines}
  2719. procedure BCDSubtract ( const BCDIn : tBCD;
  2720. const Compin : Comp;
  2721. var BCDout : tBCD ); Inline;
  2722. begin
  2723. BCDSubtract ( BCDIn, CompToBCD ( Compin ), BCDout );
  2724. end;
  2725. procedure BCDSubtract ( const Compin : Comp;
  2726. const BCDIn : tBCD;
  2727. var BCDout : tBCD ); Inline;
  2728. begin
  2729. BCDSubtract ( CompToBCD ( Compin ), BCDIn, BCDout );
  2730. end;
  2731. {$endif}
  2732. procedure BCDSubtract ( const BCDIn : tBCD;
  2733. const StringIn : FmtBCDStringtype;
  2734. var BCDout : tBCD ); Inline;
  2735. begin
  2736. BCDSubtract ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2737. end;
  2738. procedure BCDSubtract ( const StringIn : FmtBCDStringtype;
  2739. const BCDIn : tBCD;
  2740. var BCDout : tBCD ); Inline;
  2741. begin
  2742. BCDSubtract ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2743. end;
  2744. procedure BCDSubtract ( const StringIn1,
  2745. StringIn2 : FmtBCDStringtype;
  2746. var BCDout : tBCD ); Inline;
  2747. begin
  2748. BCDSubtract ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2749. end;
  2750. procedure BCDMultiply ( const BCDIn : tBCD;
  2751. const IntIn : myInttype;
  2752. var BCDout : tBCD );
  2753. var
  2754. bh : tBCD_helper;
  2755. bhr : tBCD_helper;
  2756. bhrr : tBCD_helper_big;
  2757. int : {$ifopt r+} 0..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  2758. i1 : {$ifopt r+} low ( bh.Singles )..high ( bh.Singles ) {$else} Integer {$endif};
  2759. i3 : {$ifopt r+} low ( bhr.Singles )..high ( bhr.Singles ) {$else} Integer {$endif};
  2760. 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};
  2761. ue : {$ifopt r+} 1 * ( low ( bhrr.Singles[0] ) + low ( bhrr.Singles[0] ) DIV 10 ) DIV 10
  2762. ..( high ( bhrr.Singles[0] ) + high ( bhrr.Singles[0] ) DIV 10 ) DIV 10 {$else} Integer {$endif};
  2763. begin
  2764. if IntIn = 0
  2765. then begin
  2766. BCDout := NullBCD;
  2767. EXIT;
  2768. end;
  2769. if IntIn = 1
  2770. then begin
  2771. BCDout := BCDIn;
  2772. EXIT;
  2773. end;
  2774. if IntIn = -1
  2775. then begin
  2776. BCDout := BCDIn;
  2777. BCDNegate ( BCDout );
  2778. EXIT;
  2779. end;
  2780. if IntIn = low ( myInttype )
  2781. then begin
  2782. {$if declared ( myMinIntBCD ) }
  2783. BCDMultiply ( BCDIn, myMinIntBCD, BCDout );
  2784. EXIT;
  2785. {$else}
  2786. RAISE eBCDOverflowException.create ( 'in BCDmultiply' );
  2787. {$endif}
  2788. end;
  2789. if Abs ( IntIn ) > low ( bhrr.Singles[0] ) DIV 10
  2790. then begin
  2791. BCDMultiply ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2792. EXIT;
  2793. end;
  2794. unpack_BCD ( BCDIn, bh );
  2795. if bh.Prec = 0
  2796. then begin
  2797. BCDout := NullBCD;
  2798. EXIT;
  2799. end;
  2800. bhr := null_.bh;
  2801. bhrr := null_.bhb;
  2802. int := Abs ( IntIn );
  2803. WITH bhrr do
  2804. begin
  2805. Neg := bh.Neg XOR ( IntIn < 0 );
  2806. FDig := bh.FDig;
  2807. LDig := bh.LDig;
  2808. for i1 := bh.FDig TO bh.LDig do
  2809. Singles[i1] := bh.Singles[i1] * int;
  2810. {
  2811. for i3 := fdig to ldig do
  2812. write ( ' ', singles[i3] );
  2813. writeln;
  2814. }
  2815. ue := 0;
  2816. for i3 := LDig DOWNTO FDig do
  2817. begin
  2818. v := Singles[i3] + ue;
  2819. ue := v DIV 10;
  2820. v := v MOD 10;
  2821. bhr.Singles[i3] := v;
  2822. end;
  2823. while ue <> 0 do
  2824. begin
  2825. Dec ( FDig );
  2826. if FDig < low ( bhr.Singles )
  2827. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2828. bhr.Singles[FDig] := ue MOD 10;
  2829. ue := ue DIV 10;
  2830. end;
  2831. bhr.Plac := LDig;
  2832. bhr.FDig := FDig;
  2833. if LDig > high ( bhr.Singles )
  2834. then bhr.LDig := high ( bhr.Singles )
  2835. else bhr.LDig := LDig;
  2836. end;
  2837. if NOT pack_BCD ( bhr, BCDout )
  2838. then begin
  2839. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2840. end;
  2841. end;
  2842. procedure BCDMultiply ( const IntIn : myInttype;
  2843. const BCDIn : tBCD;
  2844. var BCDout : tBCD ); Inline;
  2845. begin
  2846. BCDMultiply ( BCDIn, IntIn, BCDout );
  2847. end;
  2848. {$ifndef FPUNONE}
  2849. procedure BCDMultiply ( const DoubleIn : myRealtype;
  2850. const BCDIn : tBCD;
  2851. var BCDout : tBCD ); Inline;
  2852. begin
  2853. BCDMultiply ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2854. end;
  2855. {$endif}
  2856. procedure BCDMultiply ( const BCDIn : tBCD;
  2857. const Currin : currency;
  2858. var BCDout : tBCD ); Inline;
  2859. begin
  2860. BCDMultiply ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2861. end;
  2862. procedure BCDMultiply ( const Currin : currency;
  2863. const BCDIn : tBCD;
  2864. var BCDout : tBCD ); Inline;
  2865. begin
  2866. BCDMultiply ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2867. end;
  2868. {$ifdef comproutines}
  2869. procedure BCDMultiply ( const BCDIn : tBCD;
  2870. const Compin : Comp;
  2871. var BCDout : tBCD ); Inline;
  2872. begin
  2873. BCDMultiply ( BCDIn, CompToBCD ( Compin ), BCDout );
  2874. end;
  2875. procedure BCDMultiply ( const Compin : Comp;
  2876. const BCDIn : tBCD;
  2877. var BCDout : tBCD ); Inline;
  2878. begin
  2879. BCDMultiply ( CompToBCD ( Compin ), BCDIn, BCDout );
  2880. end;
  2881. {$endif}
  2882. procedure BCDMultiply ( const StringIn : FmtBCDStringtype;
  2883. const BCDIn : tBCD;
  2884. var BCDout : tBCD ); Inline;
  2885. begin
  2886. BCDMultiply ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2887. end;
  2888. procedure BCDDivide ( const Dividend : tBCD;
  2889. const Divisor : myInttype;
  2890. var BCDout : tBCD ); Inline;
  2891. begin
  2892. BCDDivide ( Dividend, IntegerToBCD ( Divisor ), BCDout );
  2893. end;
  2894. procedure BCDDivide ( const Dividend : myInttype;
  2895. const Divisor : tBCD;
  2896. var BCDout : tBCD ); Inline;
  2897. begin
  2898. BCDDivide ( IntegerToBCD ( Dividend ), Divisor, BCDout );
  2899. end;
  2900. {$ifndef FPUNONE}
  2901. procedure BCDDivide ( const Dividend : myRealtype;
  2902. const Divisor : tBCD;
  2903. var BCDout : tBCD ); Inline;
  2904. begin
  2905. BCDDivide ( DoubleToBCD ( Dividend ), Divisor, BCDout );
  2906. end;
  2907. {$endif}
  2908. procedure BCDDivide ( const BCDIn : tBCD;
  2909. const Currin : currency;
  2910. var BCDout : tBCD ); Inline;
  2911. begin
  2912. BCDDivide ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2913. end;
  2914. procedure BCDDivide ( const Currin : currency;
  2915. const BCDIn : tBCD;
  2916. var BCDout : tBCD ); Inline;
  2917. begin
  2918. BCDDivide ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2919. end;
  2920. {$ifdef comproutines}
  2921. procedure BCDDivide ( const BCDIn : tBCD;
  2922. const Compin : Comp;
  2923. var BCDout : tBCD ); Inline;
  2924. begin
  2925. BCDDivide ( BCDIn, CompToBCD ( Compin ), BCDout );
  2926. end;
  2927. procedure BCDDivide ( const Compin : Comp;
  2928. const BCDIn : tBCD;
  2929. var BCDout : tBCD ); Inline;
  2930. begin
  2931. BCDDivide ( CompToBCD ( Compin ), BCDIn, BCDout );
  2932. end;
  2933. {$endif}
  2934. procedure BCDDivide ( const Dividend : FmtBCDStringtype;
  2935. const Divisor : tBCD;
  2936. var BCDout : tBCD ); Inline;
  2937. begin
  2938. BCDDivide ( StrToBCD ( Dividend ), Divisor, BCDout );
  2939. end;
  2940. operator = ( const BCD1,
  2941. BCD2 : tBCD ) z : Boolean; Inline;
  2942. begin
  2943. z := BCDCompare ( BCD1, BCD2 ) = 0;
  2944. end;
  2945. operator < ( const BCD1,
  2946. BCD2 : tBCD ) z : Boolean; Inline;
  2947. begin
  2948. z := BCDCompare ( BCD1, BCD2 ) < 0;
  2949. end;
  2950. operator > ( const BCD1,
  2951. BCD2 : tBCD ) z : Boolean; Inline;
  2952. begin
  2953. z := BCDCompare ( BCD1, BCD2 ) > 0;
  2954. end;
  2955. operator <= ( const BCD1,
  2956. BCD2 : tBCD ) z : Boolean; Inline;
  2957. begin
  2958. z := BCDCompare ( BCD1, BCD2 ) <= 0;
  2959. end;
  2960. operator >= ( const BCD1,
  2961. BCD2 : tBCD ) z : Boolean; Inline;
  2962. begin
  2963. z := BCDCompare ( BCD1, BCD2 ) >= 0;
  2964. end;
  2965. (* ######################## not allowed: why?
  2966. operator + ( const BCD : tBCD ) z : tBCD; Inline;
  2967. begin
  2968. z := bcd;
  2969. end;
  2970. ##################################################### *)
  2971. operator - ( const BCD : tBCD ) z : tBCD; Inline;
  2972. begin
  2973. z := BCD;
  2974. BCDNegate ( z );
  2975. end;
  2976. operator + ( const BCD1,
  2977. BCD2 : tBCD ) z : tBCD; Inline;
  2978. begin
  2979. BCDAdd ( BCD1, BCD2, z );
  2980. end;
  2981. operator + ( const BCD : tBCD;
  2982. const i : myInttype ) z : tBCD; Inline;
  2983. begin
  2984. BCDAdd ( BCD, i, z );
  2985. end;
  2986. operator + ( const i : myInttype;
  2987. const BCD : tBCD ) z : tBCD; Inline;
  2988. begin
  2989. BCDAdd ( i, BCD, z );
  2990. end;
  2991. {$ifndef FPUNONE}
  2992. operator + ( const BCD : tBCD;
  2993. const r : myRealtype ) z : tBCD; Inline;
  2994. begin
  2995. BCDAdd ( BCD, DoubleToBCD ( r ), z );
  2996. end;
  2997. operator + ( const r : myRealtype;
  2998. const BCD : tBCD ) z : tBCD; Inline;
  2999. begin
  3000. BCDAdd ( DoubleToBCD ( r ), BCD, z );
  3001. end;
  3002. {$endif}
  3003. operator + ( const BCD : tBCD;
  3004. const c : currency ) z : tBCD; Inline;
  3005. begin
  3006. BCDAdd ( BCD, CurrToBCD ( c ), z );
  3007. end;
  3008. operator + ( const c : currency;
  3009. const BCD : tBCD ) z : tBCD; Inline;
  3010. begin
  3011. BCDAdd ( CurrToBCD ( c ), BCD, z );
  3012. end;
  3013. {$ifdef comproutines}
  3014. operator + ( const BCD : tBCD;
  3015. const c : Comp ) z : tBCD; Inline;
  3016. begin
  3017. BCDAdd ( BCD, CompToBCD ( c ), z );
  3018. end;
  3019. operator + ( const c : Comp;
  3020. const BCD : tBCD ) z : tBCD; Inline;
  3021. begin
  3022. BCDAdd ( CompToBCD ( c ), BCD, z );
  3023. end;
  3024. {$endif}
  3025. operator + ( const BCD : tBCD;
  3026. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3027. begin
  3028. BCDAdd ( BCD, StrToBCD ( s ), z );
  3029. end;
  3030. operator + ( const s : FmtBCDStringtype;
  3031. const BCD : tBCD ) z : tBCD; Inline;
  3032. begin
  3033. BCDAdd ( StrToBCD ( s ), BCD, z );
  3034. end;
  3035. operator - ( const BCD1,
  3036. BCD2 : tBCD ) z : tBCD; Inline;
  3037. begin
  3038. BCDSubtract ( BCD1, BCD2, z );
  3039. end;
  3040. operator - ( const BCD : tBCD;
  3041. const i : myInttype ) z : tBCD; Inline;
  3042. begin
  3043. BCDSubtract ( BCD, i, z );
  3044. end;
  3045. operator - ( const i : myInttype;
  3046. const BCD : tBCD ) z : tBCD; Inline;
  3047. begin
  3048. BCDSubtract ( BCD, i, z );
  3049. BCDNegate ( z );
  3050. end;
  3051. {$ifndef FPUNONE}
  3052. operator - ( const BCD : tBCD;
  3053. const r : myRealtype ) z : tBCD; Inline;
  3054. begin
  3055. BCDSubtract ( BCD, DoubleToBCD ( r ), z );
  3056. end;
  3057. operator - ( const r : myRealtype;
  3058. const BCD : tBCD ) z : tBCD; Inline;
  3059. begin
  3060. BCDSubtract ( DoubleToBCD ( r ), BCD, z );
  3061. end;
  3062. {$endif}
  3063. operator - ( const BCD : tBCD;
  3064. const c : currency ) z : tBCD; Inline;
  3065. begin
  3066. BCDSubtract ( BCD, CurrToBCD ( c ), z );
  3067. end;
  3068. operator - ( const c : currency;
  3069. const BCD : tBCD ) z : tBCD; Inline;
  3070. begin
  3071. BCDSubtract ( CurrToBCD ( c ), BCD, z );
  3072. end;
  3073. {$ifdef comproutines}
  3074. operator - ( const BCD : tBCD;
  3075. const c : Comp ) z : tBCD; Inline;
  3076. begin
  3077. BCDSubtract ( BCD, CompToBCD ( c ), z );
  3078. end;
  3079. operator - ( const c : Comp;
  3080. const BCD : tBCD ) z : tBCD; Inline;
  3081. begin
  3082. BCDSubtract ( CompToBCD ( c ), BCD, z );
  3083. end;
  3084. {$endif}
  3085. operator - ( const BCD : tBCD;
  3086. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3087. begin
  3088. BCDSubtract ( BCD, StrToBCD ( s ), z );
  3089. end;
  3090. operator - ( const s : FmtBCDStringtype;
  3091. const BCD : tBCD ) z : tBCD; Inline;
  3092. begin
  3093. BCDSubtract ( StrToBCD ( s ), BCD, z );
  3094. end;
  3095. operator * ( const BCD1,
  3096. BCD2 : tBCD ) z : tBCD; Inline;
  3097. begin
  3098. BCDMultiply ( BCD1, BCD2, z );
  3099. end;
  3100. operator * ( const BCD : tBCD;
  3101. const i : myInttype ) z : tBCD; Inline;
  3102. begin
  3103. BCDMultiply ( BCD, i, z );
  3104. end;
  3105. operator * ( const i : myInttype;
  3106. const BCD : tBCD ) z : tBCD; Inline;
  3107. begin
  3108. BCDMultiply ( BCD, i, z );
  3109. end;
  3110. {$ifndef FPUNONE}
  3111. operator * ( const BCD : tBCD;
  3112. const r : myRealtype ) z : tBCD; Inline;
  3113. begin
  3114. BCDMultiply ( BCD, DoubleToBCD ( r ), z );
  3115. end;
  3116. operator * ( const r : myRealtype;
  3117. const BCD : tBCD ) z : tBCD; Inline;
  3118. begin
  3119. BCDMultiply ( DoubleToBCD ( r ), BCD, z );
  3120. end;
  3121. {$endif}
  3122. operator * ( const BCD : tBCD;
  3123. const c : currency ) z : tBCD; Inline;
  3124. begin
  3125. BCDMultiply ( BCD, CurrToBCD ( c ), z );
  3126. end;
  3127. operator * ( const c : currency;
  3128. const BCD : tBCD ) z : tBCD; Inline;
  3129. begin
  3130. BCDMultiply ( CurrToBCD ( c ), BCD, z );
  3131. end;
  3132. {$ifdef comproutines}
  3133. operator * ( const BCD : tBCD;
  3134. const c : Comp ) z : tBCD; Inline;
  3135. begin
  3136. BCDMultiply ( BCD, CompToBCD ( c ), z );
  3137. end;
  3138. operator * ( const c : Comp;
  3139. const BCD : tBCD ) z : tBCD; Inline;
  3140. begin
  3141. BCDMultiply ( CompToBCD ( c ), BCD, z );
  3142. end;
  3143. {$endif}
  3144. operator * ( const BCD : tBCD;
  3145. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3146. begin
  3147. BCDMultiply ( BCD, StrToBCD ( s ), z );
  3148. end;
  3149. operator * ( const s : FmtBCDStringtype;
  3150. const BCD : tBCD ) z : tBCD; Inline;
  3151. begin
  3152. BCDMultiply ( StrToBCD ( s ), BCD, z );
  3153. end;
  3154. operator / ( const BCD1,
  3155. BCD2 : tBCD ) z : tBCD; Inline;
  3156. begin
  3157. BCDDivide ( BCD1, BCD2, z );
  3158. end;
  3159. operator / ( const BCD : tBCD;
  3160. const i : myInttype ) z : tBCD; Inline;
  3161. begin
  3162. BCDDivide ( BCD, i, z );
  3163. end;
  3164. operator / ( const i : myInttype;
  3165. const BCD : tBCD ) z : tBCD; Inline;
  3166. begin
  3167. BCDDivide ( IntegerToBCD ( i ), BCD, z );
  3168. end;
  3169. {$ifndef FPUNONE}
  3170. operator / ( const BCD : tBCD;
  3171. const r : myRealtype ) z : tBCD; Inline;
  3172. begin
  3173. BCDDivide ( BCD, DoubleToBCD ( r ), z );
  3174. end;
  3175. operator / ( const r : myRealtype;
  3176. const BCD : tBCD ) z : tBCD; Inline;
  3177. begin
  3178. BCDDivide ( DoubleToBCD ( r ), BCD, z );
  3179. end;
  3180. {$endif}
  3181. operator / ( const BCD : tBCD;
  3182. const c : currency ) z : tBCD; Inline;
  3183. begin
  3184. BCDDivide ( BCD, CurrToBCD ( c ), z );
  3185. end;
  3186. operator / ( const c : currency;
  3187. const BCD : tBCD ) z : tBCD; Inline;
  3188. begin
  3189. BCDDivide ( CurrToBCD ( c ), BCD, z );
  3190. end;
  3191. {$ifdef comproutines}
  3192. operator / ( const BCD : tBCD;
  3193. const c : Comp ) z : tBCD; Inline;
  3194. begin
  3195. BCDDivide ( BCD, CompToBCD ( c ), z );
  3196. end;
  3197. operator / ( const c : Comp;
  3198. const BCD : tBCD ) z : tBCD; Inline;
  3199. begin
  3200. BCDDivide ( CompToBCD ( c ), BCD, z );
  3201. end;
  3202. {$endif}
  3203. operator / ( const BCD : tBCD;
  3204. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3205. begin
  3206. BCDDivide ( BCD, StrToBCD ( s ), z );
  3207. end;
  3208. operator / ( const s : FmtBCDStringtype;
  3209. const BCD : tBCD ) z : tBCD; Inline;
  3210. begin
  3211. BCDDivide ( StrToBCD ( s ), BCD, z );
  3212. end;
  3213. operator := ( const i : Byte ) z : tBCD; Inline;
  3214. begin
  3215. z := IntegerToBCD ( myInttype ( i ) );
  3216. end;
  3217. operator := ( const BCD : tBCD ) z : Byte; Inline;
  3218. begin
  3219. z := BCDToInteger ( BCD );
  3220. end;
  3221. operator := ( const i : Word ) z : tBCD; Inline;
  3222. begin
  3223. z := IntegerToBCD ( myInttype ( i ) );
  3224. end;
  3225. operator := ( const BCD : tBCD ) z : Word; Inline;
  3226. begin
  3227. z := BCDToInteger ( BCD );
  3228. end;
  3229. operator := ( const i : longword ) z : tBCD; Inline;
  3230. begin
  3231. z := IntegerToBCD ( myInttype ( i ) );
  3232. end;
  3233. operator := ( const BCD : tBCD ) z : longword; Inline;
  3234. begin
  3235. z := BCDToInteger ( BCD );
  3236. end;
  3237. {$if declared ( qword ) }
  3238. operator := ( const i : qword ) z : tBCD; Inline;
  3239. begin
  3240. z := IntegerToBCD ( myInttype ( i ) );
  3241. end;
  3242. operator := ( const BCD : tBCD ) z : qword; Inline;
  3243. begin
  3244. z := BCDToInteger ( BCD );
  3245. end;
  3246. {$endif}
  3247. operator := ( const i : ShortInt ) z : tBCD; Inline;
  3248. begin
  3249. z := IntegerToBCD ( myInttype ( i ) );
  3250. end;
  3251. operator := ( const BCD : tBCD ) z : ShortInt; Inline;
  3252. begin
  3253. z := BCDToInteger ( BCD );
  3254. end;
  3255. operator := ( const i : smallint ) z : tBCD; Inline;
  3256. begin
  3257. z := IntegerToBCD ( myInttype ( i ) );
  3258. end;
  3259. operator := ( const BCD : tBCD ) z : smallint; Inline;
  3260. begin
  3261. z := BCDToInteger ( BCD );
  3262. end;
  3263. operator := ( const i : LongInt ) z : tBCD; Inline;
  3264. begin
  3265. z := IntegerToBCD ( myInttype ( i ) );
  3266. end;
  3267. operator := ( const BCD : tBCD ) z : LongInt; Inline;
  3268. begin
  3269. z := BCDToInteger ( BCD );
  3270. end;
  3271. {$if declared ( int64 ) }
  3272. operator := ( const i : int64 ) z : tBCD; Inline;
  3273. begin
  3274. z := IntegerToBCD ( myInttype ( i ) );
  3275. end;
  3276. operator := ( const BCD : tBCD ) z : int64; Inline;
  3277. begin
  3278. z := BCDToInteger ( BCD );
  3279. end;
  3280. {$endif}
  3281. {$ifndef FPUNONE}
  3282. operator := ( const r : Single ) z : tBCD; Inline;
  3283. begin
  3284. z := DoubleToBCD ( myRealtype ( r ) );
  3285. end;
  3286. operator := ( const BCD : tBCD ) z : Single; Inline;
  3287. begin
  3288. z := BCDToDouble ( BCD );
  3289. end;
  3290. operator := ( const r : Double ) z : tBCD; Inline;
  3291. begin
  3292. z := DoubleToBCD ( myRealtype ( r ) );
  3293. end;
  3294. operator := ( const BCD : tBCD ) z : Double; Inline;
  3295. begin
  3296. z := BCDToDouble ( BCD );
  3297. end;
  3298. {$if sizeof ( extended ) <> sizeof ( double )}
  3299. operator := ( const r : Extended ) z : tBCD; Inline;
  3300. begin
  3301. z := DoubleToBCD ( {myRealtype (} r {)} );
  3302. end;
  3303. operator := ( const BCD : tBCD ) z : Extended; Inline;
  3304. begin
  3305. z := BCDToDouble ( BCD );
  3306. end;
  3307. {$endif}
  3308. {$endif}
  3309. operator := ( const c : currency ) z : tBCD; Inline;
  3310. begin
  3311. CurrToBCD ( c, z );
  3312. end;
  3313. operator := ( const BCD : tBCD ) z : currency; Inline;
  3314. begin
  3315. BCDToCurr ( BCD, z );
  3316. end;
  3317. {$ifdef comproutines}
  3318. {$undef makedirect}
  3319. {$ifdef makedirect}
  3320. operator := ( const c : Comp ) z : tBCD; Inline;
  3321. var
  3322. cc : int64 absolute c;
  3323. begin
  3324. z := IntegerToBCD ( cc );
  3325. end;
  3326. { $define version1} { only one of these may be defined! }
  3327. { $define version2} { version 1 produces a compiler error (with INLINE only!)}
  3328. {$define version3} { I wasn't able to reduce the problem, sorry }
  3329. {$ifdef version1}
  3330. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3331. var
  3332. zz : Comp absolute z;
  3333. begin
  3334. zz := BCDToInteger ( BCD );
  3335. end;
  3336. {$endif}
  3337. {$ifdef version2}
  3338. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3339. var
  3340. zz : int64;
  3341. zzz : Comp absolute zz;
  3342. begin
  3343. zz := BCDToInteger ( BCD );
  3344. z := zzz;
  3345. end;
  3346. {$endif}
  3347. {$ifdef version3}
  3348. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3349. var
  3350. zz : record
  3351. case Boolean of
  3352. False: ( i : int64 );
  3353. True: ( c : Comp );
  3354. end;
  3355. begin
  3356. zz.i := BCDToInteger ( BCD );
  3357. z := zz.c;
  3358. end;
  3359. {$endif}
  3360. {$else}
  3361. operator := ( const c : Comp ) z : tBCD; Inline;
  3362. begin
  3363. z := CompToBCD ( c );
  3364. end;
  3365. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3366. begin
  3367. z := BCDToComp ( BCD );
  3368. end;
  3369. {$endif}
  3370. {$endif}
  3371. operator := ( const s : string ) z : tBCD; Inline;
  3372. begin
  3373. z := StrToBCD ( s );
  3374. end;
  3375. operator := ( const BCD : tBCD ) z : string; Inline;
  3376. begin
  3377. z := BCDToStr ( BCD );
  3378. end;
  3379. operator := ( const s : AnsiString ) z : tBCD; Inline;
  3380. begin
  3381. z := StrToBCD ( s );
  3382. end;
  3383. operator := ( const BCD : tBCD ) z : AnsiString; Inline;
  3384. begin
  3385. z := BCDToStr ( BCD );
  3386. end;
  3387. {$endif}
  3388. Function VariantToBCD(const VargSrc : TVarData) : TBCD;
  3389. begin
  3390. with VargSrc do
  3391. case vType and not varTypeMask of
  3392. 0: case vType of
  3393. varEmpty : Result := 0;
  3394. varSmallInt : Result := vSmallInt;
  3395. varShortInt : Result := vShortInt;
  3396. varInteger : Result := vInteger;
  3397. varSingle : Result := vSingle;
  3398. varDouble : Result := vDouble;
  3399. varCurrency : Result := vCurrency;
  3400. varDate : Result := vDate;
  3401. varBoolean : Result := Integer(vBoolean);
  3402. varVariant : Result := VariantToBCD(PVarData(vPointer)^);
  3403. varByte : Result := vByte;
  3404. varWord : Result := vWord;
  3405. varLongWord : Result := vLongWord;
  3406. varInt64 : Result := vInt64;
  3407. varQword : Result := vQWord;
  3408. varString : Result := AnsiString(vString);
  3409. varOleStr : Result := WideString(vOleStr);
  3410. varUString : Result := UnicodeString(vString);
  3411. else
  3412. if vType=VarFmtBCD then
  3413. Result := TFMTBcdVarData(vPointer).BCD
  3414. else
  3415. not_implemented;
  3416. end;
  3417. varByRef: if Assigned(vPointer) then case vType and varTypeMask of
  3418. varSmallInt : Result := PSmallInt(vPointer)^;
  3419. varShortInt : Result := PShortInt(vPointer)^;
  3420. varInteger : Result := PInteger(vPointer)^;
  3421. varSingle : Result := PSingle(vPointer)^;
  3422. varDouble : Result := PDouble(vPointer)^;
  3423. varCurrency : Result := PCurrency(vPointer)^;
  3424. varDate : Result := PDate(vPointer)^;
  3425. varBoolean : Result := SmallInt(PWordBool(vPointer)^);
  3426. varVariant : Result := VariantToBCD(PVarData(vPointer)^);
  3427. varByte : Result := PByte(vPointer)^;
  3428. varWord : Result := PWord(vPointer)^;
  3429. varLongWord : Result := PLongWord(vPointer)^;
  3430. varInt64 : Result := PInt64(vPointer)^;
  3431. varQword : Result := PQWord(vPointer)^;
  3432. else { other vtype }
  3433. not_implemented;
  3434. end else { pointer is nil }
  3435. not_implemented;
  3436. else { array or something like that }
  3437. not_implemented;
  3438. end;
  3439. end;
  3440. function VarToBCD ( const aValue : Variant ) : tBCD;
  3441. begin
  3442. Result:=VariantToBCD(TVarData(aValue));
  3443. end;
  3444. constructor TFMTBcdVarData.create;
  3445. begin
  3446. inherited create;
  3447. FBcd:=NullBCD;
  3448. end;
  3449. constructor TFMTBcdVarData.create(const BCD : tBCD);
  3450. begin
  3451. inherited create;
  3452. FBcd:=BCD;
  3453. end;
  3454. function TFMTBcdFactory.GetInstance(const v : TVarData): tObject;
  3455. begin
  3456. result:=tObject(v.VPointer);
  3457. end;
  3458. procedure TFMTBcdFactory.BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp);
  3459. var l, r: TBCD;
  3460. begin
  3461. l:=VariantToBCD(Left);
  3462. r:=VariantToBCD(Right);
  3463. case Operation of
  3464. opAdd:
  3465. l:=l+r;
  3466. opSubtract:
  3467. l:=l-r;
  3468. opMultiply:
  3469. l:=l*r;
  3470. opDivide:
  3471. l:=l/r;
  3472. else
  3473. RaiseInvalidOp;
  3474. end;
  3475. if Left.vType = VarType then
  3476. TFMTBcdVarData(Left.VPointer).BCD := l
  3477. else if Left.vType = varDouble then
  3478. Left.vDouble := l
  3479. else
  3480. RaiseInvalidOp;
  3481. end;
  3482. procedure TFMTBcdFactory.Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult);
  3483. var l, r: TBCD;
  3484. CmpRes: integer;
  3485. begin
  3486. l:=VariantToBCD(Left);
  3487. r:=VariantToBCD(Right);
  3488. CmpRes := BCDCompare(l,r);
  3489. if CmpRes=0 then
  3490. Relationship := crEqual
  3491. else if CmpRes<0 then
  3492. Relationship := crLessThan
  3493. else
  3494. Relationship := crGreaterThan;
  3495. end;
  3496. function TFMTBcdFactory.CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean;
  3497. var l, r: TBCD;
  3498. begin
  3499. l:=VariantToBCD(Left);
  3500. r:=VariantToBCD(Right);
  3501. case Operation of
  3502. opCmpEq:
  3503. Result := l=r;
  3504. opCmpNe:
  3505. Result := l<>r;
  3506. opCmpLt:
  3507. Result := l<r;
  3508. opCmpLe:
  3509. Result := l<=r;
  3510. opCmpGt:
  3511. Result := l>r;
  3512. opCmpGe:
  3513. Result := l>=r;
  3514. else
  3515. RaiseInvalidOp;
  3516. end;
  3517. end;
  3518. procedure TFMTBcdFactory.Clear(var V: TVarData);
  3519. begin
  3520. FreeAndNil(tObject(V.VPointer));
  3521. V.VType:=varEmpty;
  3522. end;
  3523. procedure TFMTBcdFactory.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
  3524. begin
  3525. if Indirect then
  3526. Dest.VPointer:=Source.VPointer
  3527. else
  3528. Dest.VPointer:=TFMTBcdVarData.Create(TFMTBcdVarData(Source.VPointer).BCD);
  3529. Dest.VType:=VarType;
  3530. end;
  3531. procedure TFMTBcdFactory.Cast(var Dest: TVarData; const Source: TVarData);
  3532. begin
  3533. not_implemented;
  3534. end;
  3535. procedure TFMTBcdFactory.CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType);
  3536. var v: TVarData;
  3537. begin
  3538. if Source.vType=VarType then
  3539. if aVarType = varString then
  3540. VarDataFromStr(Dest, BCDToStr(TFMTBcdVarData(Source.vPointer).BCD))
  3541. else
  3542. begin
  3543. VarDataInit(v);
  3544. v.vType:=varDouble;
  3545. v.vDouble:=BCDToDouble(TFMTBcdVarData(Source.vPointer).BCD);
  3546. VarDataCastTo(Dest, v, aVarType); //now cast Double to any requested type
  3547. { finalizing v is not necessary here (Double is a simple type) }
  3548. end
  3549. else
  3550. inherited;
  3551. end;
  3552. {$if declared ( myMinIntBCD ) }
  3553. (*
  3554. {$if sizeof ( integer ) = 2 }
  3555. {$ifdef BCDgr4 }
  3556. const
  3557. myMinIntBCDValue : packed array [ 1..3 ] of Char = #$32#$76#$80;
  3558. {$endif}
  3559. {$else}
  3560. {$if sizeof ( integer ) = 4 }
  3561. *)
  3562. {$ifdef BCDgr9 }
  3563. const
  3564. myMinIntBCDValue : packed array [ 1..10 ] of Char = #$21#$47#$48#$36#$48;
  3565. {$endif}
  3566. (*
  3567. {$else}
  3568. {$if sizeof ( integer ) = 8 }
  3569. {$ifdef BCDgr18 }
  3570. const
  3571. myMinIntBCDValue : packed array [ 1..19 ] of Char = #$92#$23#$37#$20#$36#$85#$47#$75#$80#$80;
  3572. {$endif}
  3573. {$else}
  3574. {$fatal You have an interesting integer type! Sorry, not supported}
  3575. {$endif}
  3576. {$endif}
  3577. {$endif}
  3578. *)
  3579. {$endif}
  3580. initialization
  3581. FillChar ( null_, SizeOf ( null_ ), #0 );
  3582. FillChar ( NullBCD_, SizeOf ( NullBCD_ ), #0 );
  3583. FillChar ( OneBCD_, SizeOf ( OneBCD_ ), #0 );
  3584. OneBCD_.Precision := 1;
  3585. OneBCD_.Fraction[low ( OneBCD_.Fraction )] := $10;
  3586. {$if declared ( myMinIntBCD ) }
  3587. FillChar ( myMinIntBCD, SizeOf ( myMinIntBCD ), #0 );
  3588. {$ifndef bigger_BCD}
  3589. myMinIntBCD.SignSpecialPlaces := NegBit;
  3590. {$else}
  3591. myMinIntBCD.Negativ := True;
  3592. {$endif}
  3593. {$if sizeof ( integer ) = 2 }
  3594. {$ifdef BCDgr4 }
  3595. myMinIntBCD.Precision := 5;
  3596. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3597. {$endif}
  3598. {$else}
  3599. {$if sizeof ( integer ) = 4 }
  3600. {$ifdef BCDgr9 }
  3601. myMinIntBCD.Precision := 10;
  3602. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3603. {$endif}
  3604. {$else}
  3605. {$if sizeof ( integer ) = 8 }
  3606. {$ifdef BCDgr18 }
  3607. myMinIntBCD.Precision := 19;
  3608. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3609. {$endif}
  3610. {$else}
  3611. {$fatal You have an interesting integer type! Sorry, not supported}
  3612. {$endif}
  3613. {$endif}
  3614. {$endif}
  3615. {$endif}
  3616. FMTBcdFactory:=TFMTBcdFactory.create;
  3617. finalization
  3618. FreeAndNil(FMTBcdFactory)
  3619. end.