fmtbcd.pp 123 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354
  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 Precision,
  193. Places : Integer ) : 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_zero : tBCD; Inline;
  585. function __get_one : tBCD; Inline;
  586. PROPERTY
  587. NullBCD : tBCD Read __get_null;
  588. ZeroBCD : tBCD Read __get_zero;
  589. OneBCD : tBCD Read __get_one;
  590. //{$define __lo_bh := 1 * ( -( MaxFmtBCDFractionSize * 1 + 2 ) ) }
  591. //{$define __hi_bh := 1 * ( MaxFmtBCDFractionSize * 1 + 1 ) }
  592. {$define helper_declarations :=
  593. const
  594. __lo_bh = -( MaxFmtBCDFractionSize + 2 );
  595. __hi_bh = ( MaxFmtBCDFractionSize + 1 );
  596. type
  597. tBCD_helper = Maybe_Packed record
  598. Prec : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif};
  599. Plac : {$ifopt r+} 0..( __hi_bh - __lo_bh + 1 ) {$else} Integer {$endif};
  600. FDig,
  601. LDig : {$ifopt r+} __lo_bh..__hi_bh {$else} Integer {$endif};
  602. Singles : Maybe_packed array [ __lo_bh..__hi_bh ]
  603. of {$ifopt r+} 0..9 {$else} Byte {$endif};
  604. Neg : Boolean;
  605. end;
  606. { in the tBCD_helper the bcd is stored for computations,
  607. shifted to the right position }
  608. // {$define __lo_bhb := 1 * ( __lo_bh + __lo_bh ) }
  609. // {$define __hi_bhb := 1 * ( __hi_bh + __hi_bh + 1 ) }
  610. const
  611. __lo_bhb = __lo_bh + __lo_bh - 1;
  612. __hi_bhb = __hi_bh + __hi_bh;
  613. type
  614. tBCD_helper_big = Maybe_Packed record
  615. Prec : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif};
  616. Plac : {$ifopt r+} 0.. ( __hi_bhb - __lo_bhb + 1 ) {$else} Integer {$endif};
  617. FDig,
  618. LDig : {$ifopt r+} __lo_bhb..__hi_bhb {$else} Integer {$endif};
  619. Singles : Maybe_packed array [ __lo_bhb..__hi_bhb ]
  620. of {$ifopt r+} 0 * 0..9 * 9 * Pred ( MaxFmtBCDDigits ) {$else} Integer {$endif};
  621. Neg : Boolean;
  622. end;
  623. }
  624. {$ifdef debug_version}
  625. helper_declarations
  626. procedure unpack_BCD ( const BCD : tBCD;
  627. var bh : tBCD_helper );
  628. function pack_BCD ( var bh : tBCD_helper;
  629. var BCD : tBCD ) : Boolean;
  630. procedure dumpBCD ( const v : tBCD );
  631. {$endif}
  632. IMPLEMENTATION
  633. USES
  634. classes {$ifopt r+}, sysconst {$endif};
  635. type
  636. TFMTBcdFactory = CLASS(TPublishableVarianttype)
  637. PROTECTED
  638. function GetInstance(const v : TVarData): tObject; OVERRIDE;
  639. PUBLIC
  640. procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp); override;
  641. procedure Clear(var V: TVarData); override;
  642. procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
  643. function CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean; override;
  644. procedure Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); override;
  645. procedure Cast(var Dest: TVarData; const Source: TVarData); override;
  646. procedure CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); override;
  647. end;
  648. TFMTBcdVarData = CLASS(TPersistent)
  649. PRIVATE
  650. FBcd : tBCD;
  651. PUBLIC
  652. constructor create;
  653. constructor create(const BCD : tBCD);
  654. PROPERTY BCD : tBCD Read FBcd Write FBcd;
  655. end;
  656. var
  657. NullBCD_ : tBCD;
  658. OneBCD_ : tBCD;
  659. function __get_null : tBCD; Inline;
  660. begin
  661. __get_null := NullBCD_;
  662. end;
  663. function __get_zero : tBCD; Inline;
  664. begin
  665. __get_zero := NullBCD_;
  666. __get_zero.Precision := 1;
  667. end;
  668. function __get_one : tBCD; Inline;
  669. begin
  670. __get_one := OneBCD_;
  671. end;
  672. type
  673. range_digits = 1..maxfmtbcdfractionsize;
  674. range_digits0 = 0..maxfmtbcdfractionsize;
  675. range_fracdigits = 0..pred ( MaxFmtBCDFractionSize );
  676. {$ifopt r+}
  677. procedure RangeError;
  678. begin
  679. raise ERangeError.Create(SRangeError);
  680. end;
  681. {$endif}
  682. {$ifndef debug_version}
  683. helper_declarations
  684. {$endif}
  685. var
  686. null_ : record
  687. case Boolean of
  688. False: ( bh : tBCD_helper );
  689. True: ( bhb : tBCD_helper_big );
  690. end;
  691. FMTBcdFactory : TFMTBcdFactory = NIL;
  692. {$ifndef bigger_BCD}
  693. const
  694. NegBit = 1 SHL 7;
  695. SpecialBit = 1 SHL 6;
  696. PlacesMask = $ff XOR ( NegBit OR SpecialBit );
  697. {$endif}
  698. {$define _select := {$define _when := if {$define _when := end else if } }
  699. {$define _then := then begin }
  700. {$define _whenother := end else begin }
  701. {$define _endselect := end } }
  702. {$ifdef debug_version}
  703. procedure dumpBCD ( const v : tBCD );
  704. var
  705. i,
  706. j : Integer;
  707. const
  708. ft : ARRAY [ Boolean ] of Char = ( 'f', 't' );
  709. begin
  710. {$ifndef bigger_BCD}
  711. Write ( 'Prec:', v.Precision, ' ',
  712. 'Neg:', ft[( v.SignSpecialPlaces AND NegBit ) <> 0], ' ',
  713. 'Special:', ft[( v.SignSpecialPlaces AND SpecialBit ) <> 0], ' ',
  714. 'Places:', v.SignSpecialPlaces AND PlacesMask, ' ' );
  715. {$else}
  716. Write ( 'Prec:', v.Precision, ' ',
  717. 'Neg:', ft[v.Negativ], ' ',
  718. 'Places:', v.Places, ' ' );
  719. {$endif}
  720. j := 0;
  721. for i := 1 TO v.Precision do
  722. if Odd ( i )
  723. then Write ( ( v.Fraction[j] AND $f0 ) SHR 4 )
  724. else begin
  725. Write ( v.Fraction[j] AND $0f );
  726. Inc ( j );
  727. end;
  728. WriteLn;
  729. end;
  730. procedure dumpbh ( const v : tBCD_helper );
  731. var
  732. i : Integer;
  733. const
  734. ft : ARRAY [ Boolean ] of Char = ( 'f', 't' );
  735. begin
  736. Write ( 'Prec:', v.Prec, ' ',
  737. 'Neg:', ft[v.Neg], ' ',
  738. 'Places:', v.Plac, ' ',
  739. 'FDig:', v.FDig, ' ',
  740. 'LDig:', v.LDig, ' ',
  741. 'Digits:', v.LDig - v.FDig + 1, ' ' );
  742. for i := v.FDig TO v.LDig do
  743. Write ( v.Singles[i] );
  744. WriteLn;
  745. end;
  746. {$endif}
  747. {$if sizeof ( integer ) = 2 }
  748. {$ifdef BCDgr4 }
  749. var
  750. myMinIntBCD : tBCD;
  751. {$endif}
  752. {$else}
  753. {$if sizeof ( integer ) = 4 }
  754. {$ifdef BCDgr9 }
  755. var
  756. myMinIntBCD : tBCD;
  757. {$endif}
  758. {$else}
  759. {$if sizeof ( integer ) = 8 }
  760. {$ifdef BCDgr18 }
  761. var
  762. myMinIntBCD : tBCD;
  763. {$endif}
  764. {$else}
  765. {$fatal You have an interesting integer type! Sorry, not supported}
  766. {$endif}
  767. {$endif}
  768. {$endif}
  769. procedure not_implemented;
  770. begin
  771. RAISE eBCDNotImplementedException.create ( 'not implemented' );
  772. end;
  773. procedure unpack_BCD ( const BCD : tBCD;
  774. var bh : tBCD_helper );
  775. var
  776. i : {$ifopt r+} __lo_bh + 1 ..__hi_bh {$else} Integer {$endif};
  777. j : {$ifopt r+} __low_fraction..__high_fraction+1 {$else} Integer {$endif};
  778. vv : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  779. begin
  780. bh := null_.bh;
  781. WITH bh,
  782. BCD do
  783. begin
  784. Prec := Precision;
  785. if Prec > 0
  786. then begin
  787. {$ifndef bigger_BCD}
  788. Plac := SignSpecialPlaces AND PlacesMask;
  789. Neg := ( SignSpecialPlaces AND NegBit ) <> 0;
  790. {$else}
  791. Plac := Places;
  792. Neg := Negativ;
  793. {$endif}
  794. LDig := Plac;
  795. FDig := LDig - Prec + 1;
  796. j := 0;
  797. i := FDig;
  798. while i <= LDig do
  799. begin
  800. vv := Fraction[j];
  801. Singles[i] := ( vv {AND $f0} ) SHR 4;
  802. if i < LDig
  803. then Singles[i+1] := vv AND $0f;
  804. Inc ( j );
  805. Inc ( i, 2 );
  806. end;
  807. end;
  808. end;
  809. end;
  810. function pack_BCD ( var bh : tBCD_helper;
  811. var BCD : tBCD ) : Boolean;
  812. { return TRUE if successful (BCD valid) }
  813. var
  814. pre : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 {$else} Integer {$endif};
  815. fra : {$ifopt r+} -1 * ( __hi_bh - __lo_bh + 1 )..__hi_bh - __lo_bh + 1 {$else} Integer {$endif};
  816. tm : {$ifopt r+} 0..__hi_bh - __lo_bh + 1 - Pred ( MaxFmtBCDFractionSize ) {$else} Integer {$endif};
  817. i : {$ifopt r+} low ( bh.FDig ) - 1..high ( bh.LDig ) {$else} Integer {$endif};
  818. rp : {$ifopt r+} low ( BCD.Fraction )..high ( BCD.Fraction ) + 1 {$else} Integer {$endif};
  819. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  820. v : {$ifopt r+} 0..10 {$else} Integer {$endif};
  821. lnz : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  822. doround,
  823. lnzf : Boolean;
  824. begin
  825. pack_BCD := False;
  826. BCD := NullBCD;
  827. WITH BCD,
  828. bh do
  829. begin
  830. lnzf := FDig <= 0;
  831. while lnzf do // skip leading 0
  832. if Singles[FDig] = 0
  833. then begin
  834. Inc ( FDig );
  835. if FDig > 0
  836. then lnzf := False;
  837. end
  838. else lnzf := False;
  839. if FDig > 1 then FDig := 1;
  840. pre := LDig - FDig + 1;
  841. fra := Plac;
  842. doround := False;
  843. if fra >= MaxFmtBCDFractionSize
  844. then begin
  845. doround := True;
  846. tm := fra - Pred ( MaxFmtBCDFractionSize );
  847. { dec ( pre, tm ); Dec/Inc error? }
  848. pre := pre - tm;
  849. { Dec ( fra, tm ); Dec/Inc error? }
  850. fra := fra - tm;
  851. { Dec ( LDig, tm ); Dec/Inc error? }
  852. LDig := LDig - tm;
  853. end;
  854. if pre > MaxFmtBCDFractionSize
  855. then begin
  856. doround := True;
  857. tm := pre - MaxFmtBCDFractionSize;
  858. { Dec ( pre, tm ); Dec/Inc error? }
  859. pre := pre - tm;
  860. { Dec ( fra, tm ); Dec/Inc error? }
  861. fra := fra - tm;
  862. { Dec ( LDig, tm ); Dec/Inc error? }
  863. LDig := LDig - tm;
  864. end;
  865. if fra < 0
  866. then EXIT;
  867. if doround
  868. then begin
  869. v := Singles[fra + 1];
  870. if v > 4
  871. then begin
  872. ue := 1;
  873. i := LDig;
  874. while ( i >= FDig ) AND ( ue <> 0 ) do
  875. begin
  876. v := Singles[i] + ue;
  877. ue := v DIV 10;
  878. Singles[i] := v MOD 10;
  879. Dec ( i );
  880. end;
  881. if ue <> 0
  882. then begin
  883. Dec ( FDig );
  884. Singles[FDig] := ue;
  885. Dec ( LDig );
  886. Dec ( fra );
  887. if fra < 0
  888. then EXIT;
  889. end;
  890. end;
  891. end;
  892. lnzf := False;
  893. i := LDig;
  894. while ( i >= FDig ) AND ( NOT lnzf ) do // skip trailing 0
  895. begin
  896. if Singles[i] <> 0
  897. then begin
  898. lnz := i;
  899. lnzf := True;
  900. end;
  901. Dec ( i );
  902. end;
  903. if lnzf
  904. then begin
  905. tm := LDig - lnz;
  906. if tm <> 0
  907. then begin
  908. { Dec ( pre, tm ); Dec/Inc error? }
  909. pre := pre - tm;
  910. { Dec ( fra, tm ); Dec/Inc error? }
  911. fra := fra - tm;
  912. { Dec ( LDig, tm ); Dec/Inc error? }
  913. LDig := LDig - tm;
  914. if fra < 0
  915. then begin
  916. { Dec ( pre, fra ); Dec/Inc error? }
  917. pre := pre - fra;
  918. { Dec ( LDig, fra ); Dec/Inc error? }
  919. LDig := LDig - fra;
  920. fra := 0;
  921. end;
  922. end;
  923. end
  924. else begin
  925. LDig := FDig;
  926. fra := 0;
  927. pre := 0;
  928. Neg := False;
  929. end;
  930. if pre <> 0
  931. then begin
  932. Precision := pre;
  933. rp := 0;
  934. i := FDig;
  935. while i <= LDig do
  936. begin
  937. if i < LDig
  938. then Fraction[rp] := ( Singles[i] SHL 4 ) OR Singles[i + 1]
  939. else Fraction[rp] := Singles[i] SHL 4;
  940. Inc ( rp );
  941. Inc ( i, 2 );
  942. end;
  943. {$ifndef bigger_BCD}
  944. if Neg
  945. then SignSpecialPlaces := NegBit;
  946. SignSpecialPlaces := SignSpecialPlaces OR fra;
  947. {$else}
  948. Negativ := Neg;
  949. Places := fra;
  950. {$endif}
  951. end;
  952. end;
  953. pack_BCD := True;
  954. end;
  955. function BCDPrecision ( const BCD : tBCD ) : Word; Inline;
  956. begin
  957. BCDPrecision := BCD.Precision;
  958. end;
  959. function BCDScale ( const BCD : tBCD ) : Word; Inline;
  960. begin
  961. {$ifndef bigger_BCD}
  962. BCDScale := BCD.SignSpecialPlaces AND PlacesMask;
  963. {$else}
  964. BCDScale := BCD.Places;
  965. {$endif}
  966. end;
  967. function IsBCDNegative ( const BCD : tBCD ) : Boolean; Inline;
  968. begin
  969. {$ifndef bigger_BCD}
  970. IsBCDNegative := ( BCD.SignSpecialPlaces AND NegBit ) <> 0;
  971. {$else}
  972. IsBCDNegative := BCD.Negativ;
  973. {$endif}
  974. end;
  975. { BCD Arithmetic}
  976. procedure BCDNegate ( var BCD : tBCD ); Inline;
  977. begin
  978. { with-statement geht nicht !!
  979. with bcd do
  980. if precision <> 0
  981. then signspecialplaces := signspecialplaces xor negbit;
  982. }
  983. if BCD.Precision <> 0
  984. then
  985. {$ifndef bigger_BCD}
  986. BCD.SignSpecialPlaces := BCD.SignSpecialPlaces XOR NegBit;
  987. {$else}
  988. BCD.Negativ := NOT BCD.Negativ;
  989. {$endif}
  990. end;
  991. { returns -1 if BCD1 < BCD2, 0 if BCD1 = BCD2, 1 if BCD1 > BCD2 }
  992. function BCDCompare ( const BCD1,
  993. BCD2 : tBCD ) : Integer;
  994. var
  995. pl1 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  996. pl2 : {$ifopt r+} 0..maxfmtbcdfractionsize - 1 {$else} Integer {$endif};
  997. pr1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  998. pr2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  999. pr : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1000. idig1 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1001. idig2 : {$ifopt r+} 0..maxfmtbcdfractionsize {$else} Integer {$endif};
  1002. i : {$ifopt r+} __low_Fraction..__high_Fraction + 1 {$else} Integer {$endif};
  1003. f1 : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  1004. f2 : {$ifopt r+} $00..$99 {$else} Integer {$endif};
  1005. res : {$ifopt r+} -1..1 {$else} Integer {$endif};
  1006. neg1,
  1007. neg2 : Boolean;
  1008. begin
  1009. {$ifndef bigger_BCD}
  1010. neg1 := ( BCD1.SignSpecialPlaces AND NegBit ) <> 0;
  1011. neg2 := ( BCD2.SignSpecialPlaces AND NegBit ) <> 0;
  1012. {$else}
  1013. neg1 := BCD1.Negativ;
  1014. neg2 := BCD2.Negativ;
  1015. {$endif}
  1016. _SELECT
  1017. _WHEN neg1 AND ( NOT neg2 )
  1018. _THEN result := -1;
  1019. _WHEN ( NOT neg1 ) AND neg2
  1020. _THEN result := +1;
  1021. _WHENOTHER
  1022. pr1 := BCD1.Precision;
  1023. pr2 := BCD2.Precision;
  1024. {$ifndef bigger_BCD}
  1025. pl1 := BCD1.SignSpecialPlaces AND PlacesMask;
  1026. pl2 := BCD2.SignSpecialPlaces AND PlacesMask;
  1027. {$else}
  1028. pl1 := BCD1.Places;
  1029. pl2 := BCD2.Places;
  1030. {$endif}
  1031. idig1 := pr1 - pl1;
  1032. idig2 := pr2 - pl2;
  1033. if idig1 <> idig2
  1034. then begin
  1035. if ( idig1 > idig2 ) = neg1
  1036. then result := -1
  1037. else result := +1;
  1038. end
  1039. else begin
  1040. if pr1 < pr2
  1041. then pr := pr1
  1042. else pr := pr2;
  1043. res := 0;
  1044. i := __low_Fraction;
  1045. while ( res = 0 ) AND ( i < ( __low_Fraction + ( pr DIV 2 ) ) ) do
  1046. begin
  1047. _SELECT
  1048. _WHEN BCD1.Fraction[i] < BCD2.Fraction[i]
  1049. _THEN res := -1
  1050. _WHEN BCD1.Fraction[i] > BCD2.Fraction[i]
  1051. _THEN res := +1;
  1052. _WHENOTHER
  1053. _endSELECT;
  1054. Inc ( i );
  1055. end;
  1056. if res = 0
  1057. then begin
  1058. if Odd ( pr )
  1059. then begin
  1060. f1 := BCD1.Fraction[i] AND $f0;
  1061. f2 := BCD2.Fraction[i] AND $f0;
  1062. _SELECT
  1063. _WHEN f1 < f2
  1064. _THEN res := -1
  1065. _WHEN f1 > f2
  1066. _THEN res := +1;
  1067. _endSELECT;
  1068. end;
  1069. if res = 0 then
  1070. if pr1 > pr2 then
  1071. res := +1
  1072. else if pr1 < pr2 then
  1073. res := -1;
  1074. end;
  1075. if neg1
  1076. then result := 0 - res
  1077. else result := res;
  1078. end;
  1079. _endSELECT
  1080. end;
  1081. { Convert string/Double/Integer to BCD struct }
  1082. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  1083. var BCD : tBCD ) : Boolean;
  1084. begin
  1085. Result := TryStrToBCD(aValue, BCD, DefaultFormatSettings);
  1086. end;
  1087. function TryStrToBCD ( const aValue : FmtBCDStringtype;
  1088. var BCD : tBCD;
  1089. Const Format : TFormatSettings) : Boolean;
  1090. var
  1091. {$ifndef use_ansistring}
  1092. lav : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1093. i : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1094. {$else}
  1095. lav : {$ifopt r+} longword {$else} longword {$endif};
  1096. i : {$ifopt r+} longword {$else} longword {$endif};
  1097. {$endif}
  1098. ch : Char;
  1099. type
  1100. ife = ( inint, infrac, inexp );
  1101. {$define max_exp_scanned := 9999 }
  1102. var
  1103. inife : ife;
  1104. lvars : record
  1105. fp,
  1106. lp : ARRAY [ ife ]
  1107. {$ifndef use_ansistring}
  1108. of {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1109. pfnb : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1110. ps : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1111. pse : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1112. errp : {$ifopt r+} 0..high ( aValue ) {$else} Integer {$endif};
  1113. {$else}
  1114. of {$ifopt r+} longword {$else} longword {$endif};
  1115. pfnb : {$ifopt r+} longword {$else} longword {$endif};
  1116. ps : {$ifopt r+} longword {$else} longword {$endif};
  1117. pse : {$ifopt r+} longword {$else} longword {$endif};
  1118. errp : {$ifopt r+} longword {$else} longword {$endif};
  1119. {$endif}
  1120. exp : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1121. p : {$ifopt r+} -max_exp_scanned..max_exp_scanned {$else} Integer {$endif};
  1122. bh : tBCD_helper;
  1123. nbf : Boolean;
  1124. end;
  1125. begin
  1126. result := True;
  1127. FillChar ( lvars, SizeOf ( lvars ), #0 );
  1128. BCD := NullBCD;
  1129. lav := Length ( aValue );
  1130. if lav <> 0
  1131. then
  1132. WITH lvars,
  1133. bh do
  1134. begin
  1135. while ( pfnb < lav ) AND ( NOT nbf ) do // skip leading spaces
  1136. begin
  1137. Inc ( pfnb );
  1138. nbf := aValue[pfnb] <> ' ';
  1139. end;
  1140. if nbf
  1141. then begin
  1142. if aValue[pfnb] IN [ '+', '-' ]
  1143. then begin
  1144. ps := pfnb; // position of sign
  1145. Inc ( pfnb );
  1146. end;
  1147. inife := low ( inife );
  1148. for i := pfnb TO lav do
  1149. begin
  1150. ch := aValue[i];
  1151. case ch of
  1152. '0'..'9': begin
  1153. case inife of
  1154. inint,
  1155. inexp: if fp[inife] = 0
  1156. then begin
  1157. if ch <> '0'
  1158. then begin
  1159. fp[inife] := i;
  1160. lp[inife] := i;
  1161. end;
  1162. end
  1163. else lp[inife] := i;
  1164. infrac: begin
  1165. if fp[infrac] = 0
  1166. then fp[infrac] := i;
  1167. if ch <> '0'
  1168. then lp[infrac] := i;
  1169. end;
  1170. end;
  1171. end;
  1172. ',',
  1173. '.': if ch = Format.DecimalSeparator then
  1174. begin
  1175. if inife <> inint then result := False
  1176. else inife := infrac;
  1177. end;
  1178. 'e',
  1179. 'E': if inife = inexp
  1180. then result := False
  1181. else inife := inexp;
  1182. '+',
  1183. '-': if ( inife = inexp ) AND ( fp[inexp] = 0 )
  1184. then pse := i // position of exponent sign
  1185. else result := False;
  1186. else begin
  1187. result := False;
  1188. errp := i;
  1189. end;
  1190. end;
  1191. end;
  1192. if not result
  1193. then begin
  1194. result := True;
  1195. for i := errp TO lav do // skip trailing spaces
  1196. if aValue[i] <> ' '
  1197. then result := False;
  1198. end;
  1199. if not result
  1200. then EXIT;
  1201. if ps <> 0
  1202. then Neg := aValue[ps] = '-';
  1203. if lp[infrac] = 0
  1204. then fp[infrac] := 0;
  1205. if fp[inexp] <> 0
  1206. then begin
  1207. exp := 0;
  1208. for i := fp[inexp] TO lp[inexp] do
  1209. if result
  1210. then
  1211. if aValue[i] <> Format.ThousandSeparator
  1212. then begin
  1213. exp := exp * 10 + ( Ord ( aValue[i] ) - Ord ( '0' ) );
  1214. if exp > 999
  1215. then result := False;
  1216. end;
  1217. if not result
  1218. then EXIT;
  1219. if pse <> 0
  1220. then
  1221. if aValue[pse] = '-'
  1222. then exp := -exp;
  1223. end;
  1224. p := -exp;
  1225. if fp[infrac] <> 0
  1226. then begin
  1227. for i := fp[infrac] TO lp[infrac] do
  1228. if aValue[i] <> Format.ThousandSeparator
  1229. then begin
  1230. if p < ( MaxFmtBCDFractionSize + 2 )
  1231. then begin
  1232. Inc ( p );
  1233. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1234. end;
  1235. end;
  1236. end;
  1237. LDig := p;
  1238. p := 1 - exp;
  1239. if fp[inint] <> 0
  1240. then
  1241. for i := lp[inint] DOWNTO fp[inint] do
  1242. if aValue[i] <> Format.ThousandSeparator
  1243. then begin
  1244. if p > - ( MaxFmtBCDFractionSize + 2 )
  1245. then begin
  1246. Dec ( p );
  1247. Singles[p] := Ord ( aValue[i] ) - Ord ( '0' );
  1248. end
  1249. else result := False;
  1250. end;
  1251. if not result
  1252. then EXIT;
  1253. FDig := p;
  1254. if LDig < 0
  1255. then LDig := 0;
  1256. Plac := LDig;
  1257. result := pack_BCD ( bh, BCD );
  1258. end;
  1259. end;
  1260. end;
  1261. function StrToBCD ( const aValue : FmtBCDStringtype ) : tBCD;
  1262. begin
  1263. Result := StrToBCD(aValue, DefaultFormatSettings);
  1264. end;
  1265. function StrToBCD ( const aValue : FmtBCDStringtype;
  1266. Const Format : TFormatSettings ) : tBCD;
  1267. begin
  1268. if not TryStrToBCD ( aValue, Result, Format ) then
  1269. raise eBCDOverflowException.create ( 'in StrToBCD' );
  1270. end;
  1271. {$ifndef FPUNONE}
  1272. procedure DoubleToBCD ( const aValue : myRealtype;
  1273. var BCD : tBCD );
  1274. var
  1275. s : string [ 30 ];
  1276. f : TFormatSettings;
  1277. begin
  1278. Str ( aValue : 25, s );
  1279. f.DecimalSeparator := '.';
  1280. f.ThousandSeparator := #0;
  1281. BCD := StrToBCD ( s, f );
  1282. end;
  1283. function DoubleToBCD ( const aValue : myRealtype ) : tBCD; Inline;
  1284. begin
  1285. DoubleToBCD ( aValue, result );
  1286. end;
  1287. {$endif}
  1288. function IntegerToBCD ( const aValue : myInttype ) : tBCD;
  1289. var
  1290. bh : tBCD_helper;
  1291. v : {$ifopt r+} 0..high ( myInttype ) {$else} Integer {$endif};
  1292. p : {$ifopt r+} low ( bh.Singles ) - 1..0 {$else} Integer {$endif};
  1293. exitloop : Boolean;
  1294. begin
  1295. _SELECT
  1296. _WHEN aValue = 0
  1297. _THEN result := ZeroBCD;
  1298. _WHEN aValue = 1
  1299. _THEN result := OneBCD;
  1300. _WHEN aValue = low ( myInttype )
  1301. _THEN
  1302. {$if declared ( myMinIntBCD ) }
  1303. result := myMinIntBCD;
  1304. {$else}
  1305. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1306. {$endif}
  1307. _WHENOTHER
  1308. bh := null_.bh;
  1309. WITH bh do
  1310. begin
  1311. Neg := aValue < 0;
  1312. if Neg
  1313. then v := -aValue
  1314. else v := +aValue;
  1315. LDig := 0;
  1316. p := 0;
  1317. REPEAT
  1318. Singles[p] := v MOD 10;
  1319. v := v DIV 10;
  1320. exitloop := v = 0;
  1321. Dec ( p );
  1322. if p < low ( Singles )
  1323. then begin
  1324. exitloop := True;
  1325. (* what to do if error occurred? *)
  1326. RAISE eBCDOverflowException.create ( 'in IntegerToBCD' );
  1327. end;
  1328. UNTIL exitloop;
  1329. FDig := p + 1;
  1330. end;
  1331. pack_BCD ( bh, result );
  1332. _endSELECT;
  1333. end;
  1334. function CurrToBCD ( const Curr : currency;
  1335. var BCD : tBCD;
  1336. Precision : Integer = 32;
  1337. Decimals : Integer = 4 ) : Boolean;
  1338. {
  1339. this works under the assumption that a currency is an int64,
  1340. except for scale of 10000
  1341. }
  1342. var
  1343. i : int64 absolute Curr;
  1344. begin
  1345. BCD := IntegerToBCD ( i );
  1346. {$ifndef bigger_BCD}
  1347. BCD.SignSpecialPlaces := 4 OR ( BCD.SignSpecialPlaces AND NegBit );
  1348. {$else}
  1349. BCD.Places := 4;
  1350. {$endif}
  1351. if (Decimals <> 4) or (Decimals > BCD.Precision) then
  1352. Result := NormalizeBCD ( BCD, BCD, Precision, Decimals )
  1353. else
  1354. Result := True;
  1355. end;
  1356. {$ifdef comproutines}
  1357. function CompToBCD ( const Curr : Comp ) : tBCD; Inline;
  1358. var
  1359. cc : int64 absolute Curr;
  1360. begin
  1361. result := IntegerToBCD ( cc );
  1362. end;
  1363. function BCDToComp ( const BCD : tBCD ) : Comp; Inline;
  1364. var
  1365. zz : record
  1366. case Boolean of
  1367. False: ( i : int64 );
  1368. True: ( c : Comp );
  1369. end;
  1370. begin
  1371. zz.i := BCDToInteger ( BCD );
  1372. BCDToComp := zz.c;
  1373. end;
  1374. {$endif}
  1375. { Convert BCD struct to string/Double/Integer }
  1376. function BCDToStr ( const BCD : tBCD ) : FmtBCDStringtype;
  1377. begin
  1378. Result := BCDToStr(BCD, DefaultFormatSettings);
  1379. end;
  1380. function BCDToStr ( const BCD : tBCD;
  1381. Const Format : TFormatSettings ) : FmtBCDStringtype;
  1382. var
  1383. bh : tBCD_helper;
  1384. l : {$ifopt r+} 0..maxfmtbcdfractionsize + 1 + 1 {$else} Integer {$endif};
  1385. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1386. pp : {$ifopt r+} low ( bh.FDig ) - 1..1 {$else} Integer {$endif};
  1387. begin
  1388. {$ifdef use_ansistring}
  1389. result := '';
  1390. {$endif}
  1391. unpack_BCD ( BCD, bh );
  1392. WITH bh do
  1393. begin
  1394. l := 0;
  1395. if Neg then
  1396. begin
  1397. {$ifndef use_ansistring}
  1398. Inc ( l );
  1399. result[l] := '-';
  1400. {$else}
  1401. result := result + '-';
  1402. {$endif}
  1403. end;
  1404. if Plac >= Prec then
  1405. begin
  1406. // insert leading 0 before decimal point
  1407. {$ifndef use_ansistring}
  1408. Inc ( l );
  1409. result[l] := '0';
  1410. {$else}
  1411. result := result + '0';
  1412. {$endif}
  1413. end;
  1414. if Prec > 0 then
  1415. begin
  1416. if Plac > 0 then
  1417. begin
  1418. if Plac > Prec then FDig := 1;
  1419. pp := 1;
  1420. end
  1421. else
  1422. pp := low ( bh.FDig ) - 1; // there is no decimal point
  1423. for i := FDig TO LDig do
  1424. begin
  1425. if i = pp then
  1426. begin
  1427. {$ifndef use_ansistring}
  1428. Inc ( l );
  1429. result[l] := Format.DecimalSeparator;
  1430. {$else}
  1431. result := result + Format.DecimalSeparator;
  1432. {$endif}
  1433. end;
  1434. {$ifndef use_ansistring}
  1435. Inc ( l );
  1436. result[l] := Chr ( Singles[i] + Ord ( '0' ) );
  1437. {$else}
  1438. result := result + Chr ( Singles[i] + Ord ( '0' ) );
  1439. {$endif}
  1440. end;
  1441. end;
  1442. end;
  1443. {$ifndef use_ansistring}
  1444. result[0] := Chr ( l );
  1445. {$endif}
  1446. end;
  1447. {$ifndef FPUNONE}
  1448. function BCDToDouble ( const BCD : tBCD ) : myRealtype;
  1449. var
  1450. bh : tBCD_helper;
  1451. i : {$ifopt r+} low ( bh.FDig )..high ( bh.LDig ) {$else} Integer {$endif};
  1452. r,
  1453. e : myRealtype;
  1454. begin
  1455. unpack_BCD ( BCD, bh );
  1456. WITH bh do
  1457. begin
  1458. r := 0;
  1459. e := 1;
  1460. for i := 0 DOWNTO FDig do
  1461. begin
  1462. r := r + Singles[i] * e;
  1463. e := e * 10;
  1464. end;
  1465. e := 1;
  1466. for i := 1 TO LDig do
  1467. begin
  1468. e := e / 10;
  1469. r := r + Singles[i] * e;
  1470. end;
  1471. if Neg
  1472. then BCDToDouble := -r
  1473. else BCDToDouble := +r;
  1474. end;
  1475. end;
  1476. {$endif}
  1477. function BCDToInteger ( const BCD : tBCD;
  1478. Truncate : Boolean = False ) : myInttype;
  1479. var
  1480. bh : tBCD_helper;
  1481. res : myInttype;
  1482. i : {$ifopt r+} low ( bh.FDig )..0 {$else} Integer {$endif};
  1483. {
  1484. unclear: behaviour if overflow: abort? return 0? return something?
  1485. so: checks are missing yet
  1486. }
  1487. begin
  1488. unpack_BCD ( BCD, bh );
  1489. res := 0;
  1490. WITH bh do
  1491. begin
  1492. for i := FDig TO 0 do
  1493. res := res * 10 - Singles[i];
  1494. if NOT Truncate
  1495. then
  1496. if Plac > 0
  1497. then
  1498. if Singles[1] > 4
  1499. then Dec ( res );
  1500. if Neg
  1501. then BCDToInteger := +res
  1502. else BCDToInteger := -res;
  1503. end;
  1504. end;
  1505. { From DB.pas }
  1506. function BCDToCurr ( const BCD : tBCD;
  1507. var Curr : currency ) : Boolean;
  1508. const
  1509. MaxCurr: array[boolean] of QWord = (QWord($7FFFFFFFFFFFFFFF), QWord($8000000000000000));
  1510. var
  1511. bh : tBCD_helper;
  1512. res : QWord;
  1513. c : currency absolute res;
  1514. i : {$ifopt r+} low ( bh.FDig )..4 {$else} Integer {$endif};
  1515. {
  1516. unclear: behaviour if overflow: abort? return 0? return something?
  1517. }
  1518. begin
  1519. BCDToCurr := False;
  1520. if BCDPrecision(BCD) - BCDScale(BCD) > 15 then
  1521. Exit;
  1522. unpack_BCD ( BCD, bh );
  1523. res := 0;
  1524. WITH bh do
  1525. begin
  1526. for i := FDig TO 4 do
  1527. res := res * 10 + Singles[i];
  1528. if Plac > 4
  1529. then
  1530. if Singles[5] > 4
  1531. then Inc ( res );
  1532. if res > MaxCurr[Neg] then
  1533. Exit;
  1534. if Neg then
  1535. begin
  1536. res := not res;
  1537. inc(res);
  1538. end;
  1539. Curr := c;
  1540. BCDToCurr := True;
  1541. end;
  1542. end;
  1543. procedure BCDAdd ( const BCDin1,
  1544. BCDin2 : tBCD;
  1545. var BCDout : tBCD );
  1546. var
  1547. bhr,
  1548. bh1,
  1549. bh2 : tBCD_helper;
  1550. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1551. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1552. v : {$ifopt r+} 0..9 + 9 + 1 {$else} Integer {$endif};
  1553. BCD : tBCD;
  1554. negate : Boolean;
  1555. begin
  1556. negate := IsBCDNegative ( BCDin1 );
  1557. if negate <> IsBCDNegative ( BCDin2 )
  1558. then begin
  1559. if negate
  1560. then begin
  1561. BCD := BCDin1;
  1562. BCDNegate ( BCD );
  1563. BCDSubtract ( BCDin2, BCD, BCDout );
  1564. EXIT;
  1565. end;
  1566. BCD := BCDin2;
  1567. BCDNegate ( BCD );
  1568. BCDSubtract ( BCDin1, BCD, BCDout );
  1569. EXIT;
  1570. end;
  1571. bhr := null_.bh;
  1572. WITH bhr do
  1573. begin
  1574. unpack_BCD ( BCDin1, bh1 );
  1575. unpack_BCD ( BCDin2, bh2 );
  1576. if bh1.FDig < bh2.FDig
  1577. then FDig := bh1.FDig
  1578. else FDig := bh2.FDig;
  1579. if bh1.LDig > bh2.LDig
  1580. then LDig := bh1.LDig
  1581. else LDig := bh2.LDig;
  1582. Plac := LDig;
  1583. ue := 0;
  1584. for i := LDig DOWNTO FDig do
  1585. begin
  1586. v := bh1.Singles[i] + bh2.Singles[i] + ue;
  1587. ue := v DIV 10;
  1588. Singles[i] := v MOD 10;
  1589. end;
  1590. if ue <> 0
  1591. then begin
  1592. Dec ( FDig );
  1593. Singles[FDig] := ue;
  1594. end;
  1595. Neg := negate;
  1596. end;
  1597. if NOT pack_BCD ( bhr, BCDout )
  1598. then begin
  1599. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  1600. end;
  1601. end;
  1602. procedure BCDSubtract ( const BCDin1,
  1603. BCDin2 : tBCD;
  1604. var BCDout : tBCD );
  1605. var
  1606. bhr,
  1607. bh1,
  1608. bh2 : tBCD_helper;
  1609. cmp : {$ifopt r+} -1..1 {$else} Integer {$endif};
  1610. ue : {$ifopt r+} 0..1 {$else} Integer {$endif};
  1611. i : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1612. v : {$ifopt r+} 0 - 9 - 1..9 - 0 - 0 {$else} Integer {$endif};
  1613. negate : Boolean;
  1614. BCD : tBCD;
  1615. begin
  1616. negate := IsBCDNegative ( BCDin1 );
  1617. if negate <> IsBCDNegative ( BCDin2 )
  1618. then begin
  1619. if negate
  1620. then begin
  1621. BCD := BCDin1;
  1622. BCDNegate ( BCD );
  1623. BCDAdd ( BCDin2, BCD, BCDout );
  1624. BCDNegate ( BCDout );
  1625. EXIT;
  1626. end;
  1627. BCD := BCDin2;
  1628. BCDNegate ( BCD );
  1629. BCDAdd ( BCDin1, BCD, BCDout );
  1630. EXIT;
  1631. end;
  1632. cmp := BCDCompare ( BCDin1, BCDin2 );
  1633. if cmp = 0
  1634. then begin
  1635. BCDout := NullBCD;
  1636. EXIT;
  1637. end;
  1638. bhr := null_.bh; { n n }
  1639. WITH bhr do { > < > < }
  1640. begin { }
  1641. if ( cmp > 0 ) = negate { +123 +12 -12 -123 }
  1642. then begin { - +12 - +123 - -123 - -12 }
  1643. unpack_BCD ( BCDin1, bh2 ); { x x }
  1644. unpack_BCD ( BCDin2, bh1 ); { s s s s }
  1645. negate := NOT negate; { nn n nn n }
  1646. end
  1647. else begin
  1648. unpack_BCD ( BCDin1, bh1 );
  1649. unpack_BCD ( BCDin2, bh2 );
  1650. end;
  1651. if bh1.FDig < bh2.FDig
  1652. then FDig := bh1.FDig
  1653. else FDig := bh2.FDig;
  1654. if bh1.LDig > bh2.LDig
  1655. then LDig := bh1.LDig
  1656. else LDig := bh2.LDig;
  1657. Plac := LDig;
  1658. ue := 0;
  1659. for i := LDig DOWNTO FDig do
  1660. begin
  1661. v := Integer ( bh1.Singles[i] ) - bh2.Singles[i] - ue;
  1662. ue := 0;
  1663. if v < 0
  1664. then begin
  1665. ue := 1;
  1666. Inc ( v, 10 );
  1667. end;
  1668. Singles[i] := v;
  1669. end;
  1670. Neg := negate;
  1671. if NOT pack_BCD ( bhr, BCDout )
  1672. then begin
  1673. {should never occur!}
  1674. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  1675. end;
  1676. end;
  1677. end;
  1678. { Returns True if successful, False if Int Digits needed to be truncated }
  1679. function NormalizeBCD ( const InBCD : tBCD;
  1680. var OutBCD : tBCD;
  1681. const Precision,
  1682. Places : Integer ) : Boolean;
  1683. var
  1684. bh : tBCD_helper;
  1685. tm : {$ifopt r+} __lo_bh..__hi_bh {$else} Integer {$endif};
  1686. begin
  1687. {$ifopt r+}
  1688. if ( Precision < 0 ) OR ( Precision > MaxFmtBCDFractionSize ) then RangeError;
  1689. if ( Places < 0 ) OR ( Precision >= MaxFmtBCDFractionSize ) then RangeError;
  1690. {$endif}
  1691. if (BCDScale(InBCD) > Places) or (BCDPrecision(InBCD) < Places) then
  1692. begin
  1693. unpack_BCD ( InBCD, bh );
  1694. tm := bh.Plac - Places;
  1695. bh.Plac := Places;
  1696. { dec ( prec, tm ); Dec/Inc error? }
  1697. bh.Prec := bh.Prec - tm;
  1698. { dec ( LDig, tm ); Dec/Inc error? }
  1699. bh.LDig := bh.LDig - tm;
  1700. NormalizeBCD := tm <= 0;
  1701. if NOT pack_BCD ( bh, OutBCD ) then
  1702. RAISE eBCDOverflowException.Create ( 'in NormalizeBCD' );
  1703. end
  1704. else
  1705. begin
  1706. OutBCD := InBCD;
  1707. NormalizeBCD := True;
  1708. end
  1709. end;
  1710. procedure BCDMultiply ( const BCDin1,
  1711. BCDin2 : tBCD;
  1712. var BCDout : tBCD );
  1713. var
  1714. bh1,
  1715. bh2,
  1716. bhr : tBCD_helper;
  1717. bhrr : tBCD_helper_big;
  1718. i1 : {$ifopt r+} low ( bh1.FDig )..high ( bh1.LDig ) {$else} Integer {$endif};
  1719. i2 : {$ifopt r+} low ( bh2.FDig )..high ( bh2.LDig ) {$else} Integer {$endif};
  1720. i3 : {$ifopt r+} low ( bhrr.FDig )..high ( bhrr.LDig ) {$else} Integer {$endif};
  1721. v : {$ifopt r+} low ( bhrr.Singles[0] )..high ( bhrr.Singles[0] ) {$else} Integer {$endif};
  1722. ue : {$ifopt r+} low ( bhrr.Singles[0] ) DIV 10..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  1723. begin
  1724. unpack_BCD ( BCDin1, bh1 );
  1725. unpack_BCD ( BCDin2, bh2 );
  1726. if ( bh1.Prec = 0 ) OR ( bh2.Prec = 0 )
  1727. then begin
  1728. BCDout := NullBCD;
  1729. EXIT;
  1730. end;
  1731. bhr := null_.bh;
  1732. bhrr := null_.bhb;
  1733. WITH bhrr do
  1734. begin
  1735. Neg := bh1.Neg XOR bh2.Neg;
  1736. {
  1737. writeln ( __lo_bhb, ' ', __hi_bhb, ' ', bh1.fdig, ' ', bh2.fdig, ' ', low ( fdig ), ' ', low ( ldig ) );
  1738. }
  1739. FDig := bh1.FDig + bh2.FDig;
  1740. LDig := bh1.LDig + bh2.LDig;
  1741. for i1 := bh1.FDig TO bh1.LDig do
  1742. for i2 := bh2.FDig TO bh2.LDig do
  1743. begin
  1744. Inc ( Singles[i1 + i2],
  1745. bh1.Singles[i1]
  1746. * bh2.Singles[i2] );
  1747. {
  1748. write ( Singles[i1 + i2], ' ', bh1.Singles[i1], ' ', bh2.Singles[i2], ' : ' );
  1749. writeln ( Singles[i1 + i2] + bh1.Singles[i1] + bh2.Singles[i2] );
  1750. }
  1751. {
  1752. Singles[i1 + i2] := Singles[i1 + i2]
  1753. + bh1.Singles[i1]
  1754. * bh2.Singles[i2];
  1755. }
  1756. end;
  1757. {
  1758. for i3 := fdig to ldig do
  1759. write ( ' ', singles[i3] );
  1760. writeln;
  1761. }
  1762. if FDig < low ( bhr.Singles )
  1763. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1764. ue := 0;
  1765. for i3 := LDig DOWNTO FDig do
  1766. begin
  1767. v := Singles[i3] + ue;
  1768. ue := v DIV 10;
  1769. v := v MOD 10;
  1770. bhr.Singles[i3] := v;
  1771. end;
  1772. while ue <> 0 do
  1773. begin
  1774. Dec ( FDig );
  1775. if FDig < low ( bhr.Singles )
  1776. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1777. bhr.Singles[FDig] := ue MOD 10;
  1778. ue := ue DIV 10;
  1779. end;
  1780. bhr.neg := bh1.Neg XOR bh2.Neg;
  1781. bhr.Plac := LDig;
  1782. bhr.FDig := FDig;
  1783. if LDig > high ( bhr.Singles )
  1784. then bhr.LDig := high ( bhr.Singles )
  1785. else bhr.LDig := LDig;
  1786. end;
  1787. if NOT pack_BCD ( bhr, BCDout )
  1788. then begin
  1789. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  1790. end;
  1791. end;
  1792. {$ifndef FPUNONE}
  1793. procedure BCDMultiply ( const BCDIn : tBCD;
  1794. const DoubleIn : myRealtype;
  1795. var BCDout : tBCD ); Inline;
  1796. begin
  1797. BCDMultiply ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  1798. end;
  1799. {$endif}
  1800. procedure BCDMultiply ( const BCDIn : tBCD;
  1801. const StringIn : FmtBCDStringtype;
  1802. var BCDout : tBCD ); Inline;
  1803. begin
  1804. BCDMultiply ( BCDIn, StrToBCD ( StringIn ), BCDout );
  1805. end;
  1806. procedure BCDMultiply ( const StringIn1,
  1807. StringIn2 : FmtBCDStringtype;
  1808. var BCDout : tBCD ); Inline;
  1809. begin
  1810. BCDMultiply ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  1811. end;
  1812. procedure BCDDivide ( const Dividend,
  1813. Divisor : tBCD;
  1814. var BCDout : tBCD );
  1815. var
  1816. bh1 : ARRAY [ Boolean ] of tBCD_helper;
  1817. bh2,
  1818. bh : tBCD_helper;
  1819. p : {$ifopt r+} low ( bh.FDig ) - high ( bh.FDig )..high ( bh.FDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1820. v1 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1821. v2 : {$ifopt r+} low ( bh.Singles[0] )..high ( bh.Singles[0] ) {$else} Integer {$endif};
  1822. lFDig : {$ifopt r+} low ( bh.FDig )..high ( bh.FDig ) {$else} Integer {$endif};
  1823. d1 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1824. d2 : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1825. d : {$ifopt r+} low ( bh.LDig ) - high ( bh.FDig )..high ( bh.LDig ) - low ( bh.FDig ) {$else} Integer {$endif};
  1826. lLdig : {$ifopt r+} low ( lFDig ) + low ( d )..high ( lFDig ) + high ( d ) {$else} Integer {$endif};
  1827. tm : {$ifopt r+} low ( lLdig ) - high ( bh2.Singles )..high ( lLdig ) - high ( bh2.Singles ) {$else} Integer {$endif};
  1828. i2 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1829. i3 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1830. ie : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1831. i4 : {$ifopt r+} low ( lFDig )..high ( lLdig ) {$else} Integer {$endif};
  1832. nFDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1833. nLDig : {$ifopt r+} low ( i2 )..high ( i2 ) {$else} Integer {$endif};
  1834. dd : {$ifopt r+} 0..9 {$else} Integer {$endif};
  1835. Add : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1836. ue : {$ifopt r+} 0..99 {$else} Integer {$endif};
  1837. 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};
  1838. v4 : {$ifopt r+} low ( bh.Singles[0] ) + low ( add )..high ( bh.Singles[0] ) + high ( add ) {$else} Integer {$endif};
  1839. FlipFlop,
  1840. nz,
  1841. sf,
  1842. sh,
  1843. fdset : Boolean;
  1844. {
  1845. bh1p : ARRAY [ Boolean ] of ^ tBCD_helper;
  1846. }
  1847. begin
  1848. { test:
  1849. bh1p[false] := @ bh1[false];
  1850. bh1p[true] := @ bh1[true];
  1851. v := bh1[false].singles[0];
  1852. v := bh1[true].singles[0];
  1853. v := bh1p[false]^.singles[0];
  1854. v := bh1p[true]^.singles[0];
  1855. v := bh1[nz].singles[0];
  1856. v := bh1p[nz]^.singles[0];
  1857. }
  1858. unpack_BCD ( Divisor, bh2 );
  1859. unpack_BCD ( Dividend, bh1[False] );
  1860. p := bh1[False].FDig - bh2.FDig;
  1861. _SELECT
  1862. _WHEN bh2.Prec = 0
  1863. _THEN RAISE eBCDException.create ( 'Division by zero' );
  1864. _WHEN bh1[False].Prec = 0
  1865. _THEN BCDout := NullBCD;
  1866. _WHEN p < low ( bh2.Singles )
  1867. _THEN RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  1868. _WHENOTHER
  1869. bh := null_.bh;
  1870. bh.Neg := bh1[False].Neg XOR bh2.Neg;
  1871. if p <= high ( bh.Singles )
  1872. then begin
  1873. bh1[True] := null_.bh;
  1874. FlipFlop := False;
  1875. fdset := p > 0;
  1876. Add := 0;
  1877. nz := True;
  1878. while nz do
  1879. WITH bh1[FlipFlop] do
  1880. begin
  1881. {
  1882. WriteLn('#####');
  1883. dumpbh ( bh1[flipflop] );
  1884. dumpbh ( bh2 );
  1885. dumpbh ( bh );
  1886. }
  1887. if ( Singles[FDig] + bh2.Singles[bh2.FDig] ) = 0
  1888. then begin
  1889. if ( FDig >= LDig )
  1890. OR ( bh2.FDig >= bh2.LDig )
  1891. then nz := False
  1892. else begin
  1893. Inc ( FDig );
  1894. Inc ( bh2.FDig );
  1895. end;
  1896. end
  1897. else begin
  1898. v1 := Singles[FDig];
  1899. v2 := bh2.Singles[bh2.FDig];
  1900. sh := v1 < v2;
  1901. if ( v1 = v2 )
  1902. then begin
  1903. nz := False;
  1904. i3 := Succ ( FDig );
  1905. ie := LDig;
  1906. while ( i3 <= ie ) AND ( NOT nz ) AND ( NOT sh ) do
  1907. begin
  1908. v1 := Singles[i3];
  1909. v2 := bh2.Singles[i3 - p];
  1910. if v1 <> v2
  1911. then begin
  1912. nz := True;
  1913. if v1 < v2
  1914. then sh := True;
  1915. end;
  1916. Inc ( i3 );
  1917. end;
  1918. end;
  1919. if NOT nz
  1920. then Add := 1
  1921. else begin
  1922. if sh
  1923. then begin
  1924. Inc ( p );
  1925. {
  1926. if p > 3 then halt;
  1927. }
  1928. if p > high ( bh.Singles )
  1929. then nz := False
  1930. else Dec ( bh2.FDig );
  1931. end
  1932. else begin
  1933. lFDig := FDig;
  1934. d1 := LDig - FDig;
  1935. d2 := bh2.LDig - bh2.FDig;
  1936. if d1 > d2
  1937. then d := d1
  1938. else d := d2;
  1939. lLdig := lFDig + d;
  1940. if lLdig > high ( bh2.Singles )
  1941. then begin
  1942. tm := ( lLdig ) - high ( bh2.Singles );
  1943. d := d - tm;
  1944. lLdig := lLdig - tm;
  1945. {runden?}
  1946. end;
  1947. sf := True;
  1948. Add := 0;
  1949. nFDig := 0;
  1950. nLDig := 0;
  1951. ue := 0;
  1952. dd := Singles[lFDig] DIV ( bh2.Singles[lFDig - p] + 1 );
  1953. if dd < 1
  1954. then dd := 1;
  1955. {
  1956. writeln ( 'p=', p, ' dd=', dd, ' lFdig=', lfdig, ' lldig=', lldig );
  1957. }
  1958. for i2 := lLdig DOWNTO lFDig do
  1959. begin
  1960. // Typecase needed on 64-bit because evaluation happens using qword...
  1961. v3 := Longint(Singles[i2]) - Longint(bh2.Singles[i2 - p] * dd) - Longint(ue);
  1962. ue := 0;
  1963. while v3 < 0 do
  1964. begin
  1965. Inc ( ue );;
  1966. v3 := v3 + 10;
  1967. end;
  1968. {
  1969. if v3 <> 0
  1970. then begin
  1971. }
  1972. bh1[NOT FlipFlop].Singles[i2] := v3;
  1973. {
  1974. nFDig := i2;
  1975. if sf
  1976. then begin
  1977. nLDig := i2;
  1978. sf := False;
  1979. end;
  1980. end;
  1981. }
  1982. end;
  1983. sf := False;
  1984. nFDig := lFDig;
  1985. nLDig := lLDig;
  1986. Inc ( Add, dd );
  1987. if sf
  1988. then nz := False
  1989. else begin
  1990. FillChar ( bh1[FlipFlop], SizeOf ( bh1[FlipFlop] ), #0 );
  1991. FlipFlop := NOT FlipFlop;
  1992. WITH bh1[FlipFlop] do
  1993. begin
  1994. FDig := nFDig;
  1995. LDig := nLDig;
  1996. end;
  1997. end;
  1998. end;
  1999. end;
  2000. if Add <> 0
  2001. then begin
  2002. if NOT fdset
  2003. then begin
  2004. bh.FDig := p;
  2005. fdset := True;
  2006. end;
  2007. if bh.LDig < p
  2008. then begin
  2009. bh.LDig := p;
  2010. if ( bh.LDig - bh.FDig ) > Succ ( MaxFmtBCDFractionSize )
  2011. then nz := False;
  2012. end;
  2013. i4 := p;
  2014. while ( Add <> 0 ) AND ( i4 >= bh.FDig ) do
  2015. begin
  2016. {
  2017. writeln ( '> ', i4, ' ', bh.Singles[i4], ' ', Add );
  2018. }
  2019. v4 := bh.Singles[i4] + Add;
  2020. Add := v4 DIV 10;
  2021. bh.Singles[i4] := v4 MOD 10;
  2022. Dec ( i4 );
  2023. end;
  2024. if Add <> 0
  2025. then begin
  2026. Dec ( bh.FDig );
  2027. bh.Singles[bh.FDig] := Add;
  2028. Add := 0;
  2029. end;
  2030. end;
  2031. end;
  2032. end;
  2033. end;
  2034. WITH bh do
  2035. begin
  2036. if LDig < 0
  2037. then LDig := 0;
  2038. if LDig > 0
  2039. then Plac := LDig
  2040. else Plac := 0;
  2041. end;
  2042. if NOT pack_BCD ( bh, BCDout )
  2043. then begin
  2044. RAISE eBCDOverflowException.create ( 'in BCDDivide' );
  2045. end;
  2046. _endSELECT
  2047. end;
  2048. procedure BCDDivide ( const Dividend,
  2049. Divisor : FmtBCDStringtype;
  2050. var BCDout : tBCD ); Inline;
  2051. begin
  2052. BCDDivide ( StrToBCD ( Dividend ), StrToBCD ( Divisor ), BCDout );
  2053. end;
  2054. {$ifndef FPUNONE}
  2055. procedure BCDDivide ( const Dividend : tBCD;
  2056. const Divisor : myRealtype;
  2057. var BCDout : tBCD ); Inline;
  2058. begin
  2059. BCDDivide ( Dividend, DoubleToBCD ( Divisor ), BCDout );
  2060. end;
  2061. {$endif}
  2062. procedure BCDDivide ( const Dividend : tBCD;
  2063. const Divisor : FmtBCDStringtype;
  2064. var BCDout : tBCD ); Inline;
  2065. begin
  2066. BCDDivide ( Dividend, StrToBCD ( Divisor ), BCDout );
  2067. end;
  2068. { TBCD variant creation utils }
  2069. procedure VarFmtBCDCreate ( var aDest : Variant;
  2070. const aBCD : tBCD );
  2071. begin
  2072. VarClear(aDest);
  2073. TVarData(aDest).Vtype:=FMTBcdFactory.Vartype;
  2074. TVarData(aDest).VPointer:=TFMTBcdVarData.create(aBCD);
  2075. end;
  2076. function VarFmtBCDCreate : Variant;
  2077. begin
  2078. VarFmtBCDCreate ( result, NullBCD );
  2079. end;
  2080. function VarFmtBCDCreate ( const aValue : FmtBCDStringtype;
  2081. Precision,
  2082. Scale : Word ) : Variant;
  2083. begin
  2084. VarFmtBCDCreate ( result, StrToBCD ( aValue ) );
  2085. end;
  2086. {$ifndef FPUNONE}
  2087. function VarFmtBCDCreate ( const aValue : myRealtype;
  2088. Precision : Word = 18;
  2089. Scale : Word = 4 ) : Variant;
  2090. begin
  2091. VarFmtBCDCreate ( result, DoubleToBCD ( aValue ) );
  2092. end;
  2093. {$endif}
  2094. function VarFmtBCDCreate ( const aBCD : tBCD ) : Variant;
  2095. begin
  2096. VarFmtBCDCreate ( result, aBCD );
  2097. end;
  2098. function VarIsFmtBCD ( const aValue : Variant ) : Boolean;
  2099. begin
  2100. Result:=TVarData(aValue).VType=FMTBcdFactory.VarType;
  2101. end;
  2102. function VarFmtBCD : TVartype;
  2103. begin
  2104. Result:=FMTBcdFactory.VarType;
  2105. end;
  2106. { Formatting BCD as string }
  2107. function BCDToStrF ( const BCD : tBCD;
  2108. Format : TFloatFormat;
  2109. const Precision,
  2110. Digits : Integer ) : FmtBCDStringtype;
  2111. var P, E: integer;
  2112. Negative: boolean;
  2113. DS, TS: char;
  2114. procedure RoundDecimalDigits(const d: integer);
  2115. var i,j: integer;
  2116. begin
  2117. j:=P+d;
  2118. if (Length(Result) > j) and (Result[j+1] >= '5') then
  2119. for i:=j downto 1+ord(Negative) do
  2120. begin
  2121. if Result[i] = '9' then
  2122. begin
  2123. Result[i] := '0';
  2124. if i = 1+ord(Negative) then
  2125. begin
  2126. Insert('1', Result, i);
  2127. inc(P);
  2128. inc(j);
  2129. end;
  2130. end
  2131. else if Result[i] <> DS then
  2132. begin
  2133. inc(Result[i]);
  2134. break;
  2135. end;
  2136. end;
  2137. if d = 0 then dec(j); // if decimal separator is last char then do not copy them
  2138. Result := copy(Result, 1, j);
  2139. end;
  2140. procedure AddDecimalDigits(d: integer);
  2141. var n: integer;
  2142. begin
  2143. if P > Length(Result) then // there isn't decimal separator
  2144. if d = 0 then
  2145. Exit
  2146. else
  2147. Result := Result + DS;
  2148. n := d + P - Length(Result);
  2149. if n > 0 then
  2150. Result := Result + StringOfChar('0', n)
  2151. else if n < 0 then
  2152. RoundDecimalDigits(d);
  2153. end;
  2154. procedure AddThousandSeparators;
  2155. begin
  2156. Dec(P, 3);
  2157. While (P > 1) Do
  2158. Begin
  2159. If (Result[P - 1] <> '-') And (TS <> #0) Then
  2160. Insert(TS, Result, P);
  2161. Dec(P, 3);
  2162. End;
  2163. end;
  2164. begin
  2165. Result := BCDToStr(BCD);
  2166. if Format = ffGeneral then Exit;
  2167. DS:=DefaultFormatSettings.DecimalSeparator;
  2168. TS:=DefaultFormatSettings.ThousandSeparator;
  2169. Negative := Result[1] = '-';
  2170. P := Pos(DS, Result);
  2171. if P = 0 then
  2172. P := Length(Result) + 1;
  2173. Case Format Of
  2174. ffExponent:
  2175. Begin
  2176. E := P - 2 - ord(Negative);
  2177. if (E = 0) and (Result[P-1] = '0') then // 0.###
  2178. repeat
  2179. dec(E);
  2180. until (Length(Result) <= P-E) or (Result[P-E] <> '0');
  2181. if E <> 0 then
  2182. begin
  2183. System.Delete(Result, P, 1);
  2184. dec(P, E);
  2185. Insert(DS, Result, P);
  2186. end;
  2187. AddDecimalDigits(Precision-1);
  2188. if E < 0 then
  2189. begin
  2190. System.Delete(Result, P+E-1, -E);
  2191. Result := Result + SysUtils.Format('E%.*d' , [Digits,E])
  2192. end
  2193. else
  2194. Result := Result + SysUtils.Format('E+%.*d', [Digits,E]);
  2195. End;
  2196. ffFixed:
  2197. Begin
  2198. AddDecimalDigits(Digits);
  2199. End;
  2200. ffNumber:
  2201. Begin
  2202. AddDecimalDigits(Digits);
  2203. AddThousandSeparators;
  2204. End;
  2205. ffCurrency:
  2206. Begin
  2207. //implementation based on FloatToStrFIntl()
  2208. if Negative then System.Delete(Result, 1, 1);
  2209. AddDecimalDigits(Digits);
  2210. AddThousandSeparators;
  2211. If Not Negative Then
  2212. Begin
  2213. Case FormatSettings.CurrencyFormat Of
  2214. 0: Result := FormatSettings.CurrencyString + Result;
  2215. 1: Result := Result + FormatSettings.CurrencyString;
  2216. 2: Result := FormatSettings.CurrencyString + ' ' + Result;
  2217. 3: Result := Result + ' ' + FormatSettings.CurrencyString;
  2218. End
  2219. End
  2220. Else
  2221. Begin
  2222. Case FormatSettings.NegCurrFormat Of
  2223. 0: Result := '(' + FormatSettings.CurrencyString + Result + ')';
  2224. 1: Result := '-' + FormatSettings.CurrencyString + Result;
  2225. 2: Result := FormatSettings.CurrencyString + '-' + Result;
  2226. 3: Result := FormatSettings.CurrencyString + Result + '-';
  2227. 4: Result := '(' + Result + FormatSettings.CurrencyString + ')';
  2228. 5: Result := '-' + Result + FormatSettings.CurrencyString;
  2229. 6: Result := Result + '-' + FormatSettings.CurrencyString;
  2230. 7: Result := Result + FormatSettings.CurrencyString + '-';
  2231. 8: Result := '-' + Result + ' ' + FormatSettings.CurrencyString;
  2232. 9: Result := '-' + FormatSettings.CurrencyString + ' ' + Result;
  2233. 10: Result := FormatSettings.CurrencyString + ' ' + Result + '-';
  2234. End;
  2235. End;
  2236. End;
  2237. End;
  2238. end;
  2239. function FormatBCD ( const Format : string;
  2240. BCD : tBCD ) : FmtBCDStringtype;
  2241. // Tests: tests/test/units/fmtbcd/
  2242. type
  2243. TSection=record
  2244. FmtStart, FmtEnd, // positions in Format string,
  2245. Fmt1Dig, // position of 1st digit placeholder,
  2246. FmtDS: PChar; // position of decimal point
  2247. Digits: integer; // number of all digit placeholders
  2248. DigDS: integer; // number of digit placeholders after decimal separator
  2249. HasTS, HasDS: boolean; // has thousand or decimal separator?
  2250. end;
  2251. var
  2252. PFmt: PChar;
  2253. i, j, j1, je, ReqSec, Sec, Scale: integer;
  2254. Section: TSection;
  2255. FF: TFloatFormat;
  2256. BCDStr: string; // BCDToStrF of given BCD parameter
  2257. Buf: array [0..85] of char; // output buffer
  2258. // Parses Format parameter, their sections (positive;negative;zero) and
  2259. // builds Section information for requested section
  2260. procedure ParseFormat;
  2261. var C,Q: Char;
  2262. PFmtEnd: PChar;
  2263. Section1: TSection;
  2264. begin
  2265. PFmt:=@Format[1];
  2266. PFmtEnd:=PFmt+length(Format);
  2267. Section.FmtStart:=PFmt;
  2268. Section.Fmt1Dig:=nil;
  2269. Section.Digits:=0;
  2270. Section.HasTS:=false; // has thousand separator?
  2271. Section.HasDS:=false; // has decimal separator?
  2272. Sec:=1;
  2273. while true do begin
  2274. if PFmt>=PFmtEnd then
  2275. C:=#0 // hack if short strings used
  2276. else
  2277. C:=PFmt^;
  2278. case C of
  2279. '''', '"':
  2280. begin
  2281. Q:=PFmt^;
  2282. inc(PFmt);
  2283. while (PFmt<PFmtEnd-1) and (PFmt^<>Q) do
  2284. inc(PFmt);
  2285. end;
  2286. #0, ';': // end of Format string or end of section
  2287. begin
  2288. if Sec > 1 then
  2289. Section.FmtStart:=Section.FmtEnd+1;
  2290. Section.FmtEnd:=PFmt;
  2291. if not assigned(Section.Fmt1Dig) then
  2292. Section.Fmt1Dig:=Section.FmtEnd;
  2293. if not Section.HasDS then
  2294. begin
  2295. Section.FmtDS := Section.FmtEnd;
  2296. Section.DigDS := 0;
  2297. end;
  2298. if Sec = 1 then
  2299. Section1 := Section;
  2300. if (C = #0) or (Sec=ReqSec) then
  2301. break;
  2302. Section.Fmt1Dig:=nil;
  2303. Section.Digits:=0;
  2304. Section.HasTS:=false;
  2305. Section.HasDS:=false;
  2306. inc(Sec);
  2307. end;
  2308. '.': // decimal point
  2309. begin
  2310. Section.HasDS:=true;
  2311. Section.FmtDS:=PFmt;
  2312. Section.DigDS:=0;
  2313. end;
  2314. ',': // thousand separator
  2315. Section.HasTS:=true;
  2316. '0','#': // digits placeholders
  2317. begin
  2318. if not assigned(Section.Fmt1Dig) then Section.Fmt1Dig:=PFmt;
  2319. inc(Section.Digits);
  2320. inc(Section.DigDS);
  2321. end;
  2322. end;
  2323. inc(PFmt);
  2324. end;
  2325. // if requested section does not exists or is empty use first section
  2326. if (ReqSec > Sec) or (Section.FmtStart=Section.FmtEnd) then
  2327. begin
  2328. Section := Section1;
  2329. Sec := 1;
  2330. end;
  2331. end;
  2332. procedure PutFmtDigit(var AFmt: PChar; var iBCDStr, iBuf: integer; MoveBy: integer);
  2333. var ADig, Q: Char;
  2334. begin
  2335. if (iBuf < low(Buf)) or (iBuf > high(Buf)) then
  2336. raise eBCDOverflowException.Create ( 'in FormatBCD' );
  2337. if (iBCDStr < 1) or (iBCDStr > length(BCDStr)) then
  2338. ADig:=#0
  2339. else
  2340. ADig:=BCDStr[iBCDStr];
  2341. // write remaining leading part of BCDStr if there are no more digit placeholders in Format string
  2342. if ((AFmt < Section.Fmt1Dig) and (AFmt < Section.FmtDS) and (ADig <> #0)) or
  2343. (ADig = DefaultFormatSettings.ThousandSeparator) then
  2344. begin
  2345. Buf[iBuf] := BCDStr[iBCDStr];
  2346. inc(iBCDStr, MoveBy);
  2347. inc(iBuf, MoveBy);
  2348. Exit;
  2349. end;
  2350. case AFmt^ of
  2351. '''','"':
  2352. begin
  2353. Q:=AFmt^;
  2354. inc(AFmt, MoveBy);
  2355. // write all characters between quotes
  2356. while (AFmt>Section.FmtStart) and (AFmt<Section.FmtEnd) and (AFmt^ <> Q) do
  2357. begin
  2358. Buf[iBuf] := AFmt^;
  2359. inc(AFmt, MoveBy);
  2360. inc(iBuf, MoveBy);
  2361. end;
  2362. end;
  2363. '0','.':
  2364. begin
  2365. if AFmt^ = '.' then
  2366. Buf[iBuf] := DefaultFormatSettings.DecimalSeparator
  2367. else if ADig = #0 then
  2368. Buf[iBuf] := '0'
  2369. else
  2370. Buf[iBuf] := ADig;
  2371. inc(AFmt, MoveBy);
  2372. inc(iBCDStr, MoveBy);
  2373. inc(iBuf, MoveBy);
  2374. end;
  2375. '#':
  2376. begin
  2377. if ADig = #0 then
  2378. inc(AFmt, MoveBy)
  2379. else if (ADig = '0') and (iBCDStr = 1) then // skip leading zero
  2380. begin
  2381. inc(AFmt, MoveBy);
  2382. inc(iBCDStr, MoveBy);
  2383. end
  2384. else
  2385. begin
  2386. Buf[iBuf] := ADig;
  2387. inc(AFmt, MoveBy);
  2388. inc(iBCDStr, MoveBy);
  2389. inc(iBuf, MoveBy);
  2390. end;
  2391. end;
  2392. ',':
  2393. begin
  2394. inc(AFmt, MoveBy); // thousand separators are already in BCDStr
  2395. end;
  2396. else // write character what is in Format as is
  2397. begin
  2398. Buf[iBuf] := AFmt^;
  2399. inc(AFmt, MoveBy);
  2400. inc(iBuf, MoveBy);
  2401. end;
  2402. end;
  2403. end;
  2404. begin
  2405. case BCDCompare(BCD, NullBCD) of
  2406. 1: ReqSec := 1;
  2407. 0: ReqSec := 3;
  2408. -1: ReqSec := 2;
  2409. end;
  2410. // remove sign for negative value
  2411. if ReqSec = 2 then
  2412. BCDNegate(BCD);
  2413. // parse Format into Section
  2414. ParseFormat;
  2415. if Section.FmtStart=Section.FmtEnd then // empty section
  2416. FF := ffGeneral
  2417. else if Section.HasTS then
  2418. FF := ffNumber
  2419. else
  2420. FF := ffFixed;
  2421. Scale := BCDScale(BCD);
  2422. if (FF <> ffGeneral) and (Scale > Section.DigDS) then // we need rounding
  2423. Scale := Section.DigDS;
  2424. BCDStr := BCDToStrF(BCD, FF, 64, Scale);
  2425. if (FF = ffGeneral) then
  2426. begin
  2427. Result:=BCDStr;
  2428. Exit;
  2429. end;
  2430. // write to output buffer
  2431. j1 := high(Buf); // position of 1st number before decimal point in output buffer
  2432. je := length(Buf); // position after last digit in output buffer
  2433. // output decimal part of BCDStr
  2434. if Section.HasDS and (Section.FmtEnd-Section.FmtDS>1) then // is there something after decimal point?
  2435. begin
  2436. PFmt := Section.FmtDS; // start from decimal point until end
  2437. i := length(BCDStr) - Scale + ord(Scale=0);
  2438. dec(j1, Section.FmtEnd-Section.FmtDS);
  2439. j := j1 + 1;
  2440. while PFmt < Section.FmtEnd do
  2441. PutFmtDigit(PFmt, i, j, 1);
  2442. je := j; // store position after last decimal digit
  2443. end;
  2444. // output whole number part of BCDStr
  2445. PFmt := Section.FmtDS - 1;
  2446. i := length(BCDStr) - Scale - ord(Scale<>0);
  2447. j := j1;
  2448. while (i>0) and (j>0) do
  2449. PutFmtDigit(PFmt, i, j, -1);
  2450. // output leading '0' (f.e. '001.23')
  2451. while (PFmt >= Section.FmtStart) and (PFmt^ = '0') do
  2452. PutFmtDigit(PFmt, i, j, -1);
  2453. // output sign (-), if value is negative, and does not exists 2nd section
  2454. if (ReqSec = 2) and (Sec = 1) then
  2455. begin
  2456. Buf[j]:='-';
  2457. dec(j);
  2458. end;
  2459. // output remaining chars from begining of Format (f.e. 'abc' if given Format is 'abc0.00')
  2460. while PFmt >= Section.FmtStart do
  2461. PutFmtDigit(PFmt, i, j, -1);
  2462. inc(j);
  2463. if j > high(Buf) then
  2464. Result := ''
  2465. else
  2466. SetString(Result, @Buf[j], je-j);
  2467. end;
  2468. {$ifdef additional_routines}
  2469. function CurrToBCD ( const Curr : currency ) : tBCD; Inline;
  2470. begin
  2471. CurrToBCD ( Curr, result );
  2472. end;
  2473. procedure BCDAdd ( const BCDIn : tBCD;
  2474. const IntIn : myInttype;
  2475. var BCDout : tBCD );
  2476. var
  2477. BCD : tBCD;
  2478. bhr : tBCD_helper;
  2479. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2480. ue : {$ifopt r+} 0..high ( IntIn ) - 9 {$else} Integer {$endif};
  2481. v : {$ifopt r+} 0..{high ( ue ) + 9} high ( IntIn ) {$else} Integer {$endif};
  2482. nz : Boolean;
  2483. begin
  2484. if IntIn = 0
  2485. then begin
  2486. BCDout := BCDIn;
  2487. EXIT;
  2488. end;
  2489. if IntIn = low ( myInttype )
  2490. then begin
  2491. {$if declared ( myMinIntBCD ) }
  2492. BCDAdd ( BCDIn, myMinIntBCD, BCDout );
  2493. EXIT;
  2494. {$else}
  2495. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2496. {$endif}
  2497. end;
  2498. if IsBCDNegative ( BCDIn )
  2499. then begin
  2500. BCD := BCDIn;
  2501. BCDNegate ( BCD );
  2502. if IntIn < 0
  2503. then BCDAdd ( BCD, -IntIn, BCDout )
  2504. else BCDSubtract ( BCD, IntIn, BCDout );
  2505. BCDNegate ( BCDout );
  2506. EXIT;
  2507. end;
  2508. if IntIn < 0
  2509. then begin
  2510. BCDSubtract ( BCDIn, -IntIn, BCDout );
  2511. EXIT;
  2512. end;
  2513. if IntIn > ( high ( IntIn ) - 9 )
  2514. then begin
  2515. BCDAdd ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2516. EXIT;
  2517. end;
  2518. unpack_BCD ( BCDIn, bhr );
  2519. p := 0;
  2520. nz := True;
  2521. ue := IntIn;
  2522. while nz do
  2523. begin
  2524. v := bhr.Singles[p] + ue;
  2525. bhr.Singles[p] := v MOD 10;
  2526. ue := v DIV 10;
  2527. if ue = 0
  2528. then nz := False
  2529. else Dec ( p );
  2530. end;
  2531. if p < bhr.FDig
  2532. then begin
  2533. bhr.FDig := p;
  2534. bhr.Prec := bhr.Prec + ( bhr.FDig - p );
  2535. end;
  2536. if NOT pack_BCD ( bhr, BCDout )
  2537. then begin
  2538. RAISE eBCDOverflowException.create ( 'in BCDAdd' );
  2539. end;
  2540. end;
  2541. procedure BCDSubtract ( const BCDIn : tBCD;
  2542. const IntIn : myInttype;
  2543. var BCDout : tBCD );
  2544. {}
  2545. var
  2546. BCD : tBCD;
  2547. bhr : tBCD_helper;
  2548. p : {$ifopt r+} low ( bhr.FDig ) - 1..0 {$else} Integer {$endif};
  2549. ue : {$ifopt r+} 0..pred ( 100000000 ) {$else} Integer {$endif};
  2550. v : {$ifopt r+} -9..9 {$else} Integer {$endif};
  2551. direct : Boolean;
  2552. {}
  2553. begin
  2554. if IntIn = 0
  2555. then begin
  2556. BCDout := BCDIn;
  2557. EXIT;
  2558. end;
  2559. if IntIn = low ( myInttype )
  2560. then begin
  2561. {$if declared ( myMinIntBCD ) }
  2562. BCDSubtract ( BCDIn, myMinIntBCD, BCDout );
  2563. EXIT;
  2564. {$else}
  2565. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2566. {$endif}
  2567. end;
  2568. if IsBCDNegative ( BCDIn )
  2569. then begin
  2570. BCD := BCDIn;
  2571. BCDNegate ( BCD );
  2572. if IntIn < 0
  2573. then BCDSubtract ( BCD, -IntIn, BCDout )
  2574. else BCDAdd ( BCD, IntIn, BCDout );
  2575. BCDNegate ( BCDout );
  2576. EXIT;
  2577. end;
  2578. if IntIn < 0
  2579. then begin
  2580. BCDAdd ( BCDIn, -IntIn, BCDout );
  2581. EXIT;
  2582. end;
  2583. direct := False;
  2584. case BCDIn.Precision
  2585. -
  2586. {$ifndef bigger_BCD}
  2587. ( BCDIn.SignSpecialPlaces AND PlacesMask )
  2588. {$else}
  2589. BCDIn.Places
  2590. {$endif}
  2591. of
  2592. 2: direct := IntIn < 10;
  2593. 3: direct := IntIn < 100;
  2594. 4: direct := IntIn < 1000;
  2595. 5: direct := IntIn < 10000;
  2596. 6: direct := IntIn < 100000;
  2597. 7: direct := IntIn < 1000000;
  2598. 8: direct := IntIn < 10000000;
  2599. 9: direct := IntIn < 100000000;
  2600. end;
  2601. {
  2602. write(direct);dumpbcd(bcdin);write('[',intin,']');
  2603. }
  2604. if direct
  2605. then begin
  2606. unpack_BCD ( BCDIn, bhr );
  2607. WITH bhr do
  2608. begin
  2609. p := 0;
  2610. ue := IntIn;
  2611. while p >= FDig do
  2612. begin
  2613. v := Singles[p] - ue MOD 10;
  2614. ue := ue DIV 10;
  2615. if v < 0
  2616. then begin
  2617. v := v + 10;
  2618. ue := ue + 1;
  2619. end;
  2620. Singles[p] := v;
  2621. Dec ( p );
  2622. end;
  2623. end;
  2624. if NOT pack_BCD ( bhr, BCDout )
  2625. then begin
  2626. RAISE eBCDOverflowException.create ( 'in BCDSubtract' );
  2627. end;
  2628. end
  2629. else
  2630. {}
  2631. BCDSubtract ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2632. end;
  2633. procedure BCDAdd ( const IntIn : myInttype;
  2634. const BCDIn : tBCD;
  2635. var BCDout : tBCD ); Inline;
  2636. begin
  2637. BCDAdd ( BCDIn, IntIn, BCDout );
  2638. end;
  2639. {$ifndef FPUNONE}
  2640. procedure BCDAdd ( const BCDIn : tBCD;
  2641. const DoubleIn : myRealtype;
  2642. var BCDout : tBCD ); Inline;
  2643. begin
  2644. BCDAdd ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2645. end;
  2646. procedure BCDAdd ( const DoubleIn : myRealtype;
  2647. const BCDIn : tBCD;
  2648. var BCDout : tBCD ); Inline;
  2649. begin
  2650. BCDAdd ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2651. end;
  2652. {$endif}
  2653. procedure BCDAdd ( const BCDIn : tBCD;
  2654. const Currin : currency;
  2655. var BCDout : tBCD ); Inline;
  2656. begin
  2657. BCDAdd ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2658. end;
  2659. procedure BCDAdd ( const Currin : currency;
  2660. const BCDIn : tBCD;
  2661. var BCDout : tBCD ); Inline;
  2662. begin
  2663. BCDAdd ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2664. end;
  2665. {$ifdef comproutines}
  2666. procedure BCDAdd ( const BCDIn : tBCD;
  2667. const Compin : Comp;
  2668. var BCDout : tBCD ); Inline;
  2669. begin
  2670. BCDAdd ( BCDIn, CompToBCD ( Compin ), BCDout );
  2671. end;
  2672. procedure BCDAdd ( const Compin : Comp;
  2673. const BCDIn : tBCD;
  2674. var BCDout : tBCD ); Inline;
  2675. begin
  2676. BCDAdd ( CompToBCD ( Compin ), BCDIn, BCDout );
  2677. end;
  2678. {$endif}
  2679. procedure BCDAdd ( const BCDIn : tBCD;
  2680. const StringIn : FmtBCDStringtype;
  2681. var BCDout : tBCD ); Inline;
  2682. begin
  2683. BCDAdd ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2684. end;
  2685. procedure BCDAdd ( const StringIn : FmtBCDStringtype;
  2686. const BCDIn : tBCD;
  2687. var BCDout : tBCD ); Inline;
  2688. begin
  2689. BCDAdd ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2690. end;
  2691. procedure BCDAdd ( const StringIn1,
  2692. StringIn2 : FmtBCDStringtype;
  2693. var BCDout : tBCD ); Inline;
  2694. begin
  2695. BCDAdd ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2696. end;
  2697. procedure BCDSubtract ( const IntIn : myInttype;
  2698. const BCDIn : tBCD;
  2699. var BCDout : tBCD ); Inline;
  2700. begin
  2701. BCDSubtract ( BCDIn, IntIn, BCDout );
  2702. BCDNegate ( BCDout );
  2703. end;
  2704. {$ifndef FPUNONE}
  2705. procedure BCDSubtract ( const BCDIn : tBCD;
  2706. const DoubleIn : myRealtype;
  2707. var BCDout : tBCD ); Inline;
  2708. begin
  2709. BCDSubtract ( BCDIn, DoubleToBCD ( DoubleIn ), BCDout );
  2710. end;
  2711. procedure BCDSubtract ( const DoubleIn : myRealtype;
  2712. const BCDIn : tBCD;
  2713. var BCDout : tBCD ); Inline;
  2714. begin
  2715. BCDSubtract ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2716. end;
  2717. {$endif}
  2718. procedure BCDSubtract ( const BCDIn : tBCD;
  2719. const Currin : currency;
  2720. var BCDout : tBCD ); Inline;
  2721. begin
  2722. BCDSubtract ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2723. end;
  2724. procedure BCDSubtract ( const Currin : currency;
  2725. const BCDIn : tBCD;
  2726. var BCDout : tBCD ); Inline;
  2727. begin
  2728. BCDSubtract ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2729. end;
  2730. {$ifdef comproutines}
  2731. procedure BCDSubtract ( const BCDIn : tBCD;
  2732. const Compin : Comp;
  2733. var BCDout : tBCD ); Inline;
  2734. begin
  2735. BCDSubtract ( BCDIn, CompToBCD ( Compin ), BCDout );
  2736. end;
  2737. procedure BCDSubtract ( const Compin : Comp;
  2738. const BCDIn : tBCD;
  2739. var BCDout : tBCD ); Inline;
  2740. begin
  2741. BCDSubtract ( CompToBCD ( Compin ), BCDIn, BCDout );
  2742. end;
  2743. {$endif}
  2744. procedure BCDSubtract ( const BCDIn : tBCD;
  2745. const StringIn : FmtBCDStringtype;
  2746. var BCDout : tBCD ); Inline;
  2747. begin
  2748. BCDSubtract ( BCDIn, StrToBCD ( StringIn ), BCDout );
  2749. end;
  2750. procedure BCDSubtract ( const StringIn : FmtBCDStringtype;
  2751. const BCDIn : tBCD;
  2752. var BCDout : tBCD ); Inline;
  2753. begin
  2754. BCDSubtract ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2755. end;
  2756. procedure BCDSubtract ( const StringIn1,
  2757. StringIn2 : FmtBCDStringtype;
  2758. var BCDout : tBCD ); Inline;
  2759. begin
  2760. BCDSubtract ( StrToBCD ( StringIn1 ), StrToBCD ( StringIn2 ), BCDout );
  2761. end;
  2762. procedure BCDMultiply ( const BCDIn : tBCD;
  2763. const IntIn : myInttype;
  2764. var BCDout : tBCD );
  2765. var
  2766. bh : tBCD_helper;
  2767. bhr : tBCD_helper;
  2768. bhrr : tBCD_helper_big;
  2769. int : {$ifopt r+} 0..high ( bhrr.Singles[0] ) DIV 10 {$else} Integer {$endif};
  2770. i1 : {$ifopt r+} low ( bh.Singles )..high ( bh.Singles ) {$else} Integer {$endif};
  2771. i3 : {$ifopt r+} low ( bhr.Singles )..high ( bhr.Singles ) {$else} Integer {$endif};
  2772. 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};
  2773. ue : {$ifopt r+} 1 * ( low ( bhrr.Singles[0] ) + low ( bhrr.Singles[0] ) DIV 10 ) DIV 10
  2774. ..( high ( bhrr.Singles[0] ) + high ( bhrr.Singles[0] ) DIV 10 ) DIV 10 {$else} Integer {$endif};
  2775. begin
  2776. if IntIn = 0
  2777. then begin
  2778. BCDout := NullBCD;
  2779. EXIT;
  2780. end;
  2781. if IntIn = 1
  2782. then begin
  2783. BCDout := BCDIn;
  2784. EXIT;
  2785. end;
  2786. if IntIn = -1
  2787. then begin
  2788. BCDout := BCDIn;
  2789. BCDNegate ( BCDout );
  2790. EXIT;
  2791. end;
  2792. if IntIn = low ( myInttype )
  2793. then begin
  2794. {$if declared ( myMinIntBCD ) }
  2795. BCDMultiply ( BCDIn, myMinIntBCD, BCDout );
  2796. EXIT;
  2797. {$else}
  2798. RAISE eBCDOverflowException.create ( 'in BCDmultiply' );
  2799. {$endif}
  2800. end;
  2801. if Abs ( IntIn ) > low ( bhrr.Singles[0] ) DIV 10
  2802. then begin
  2803. BCDMultiply ( BCDIn, IntegerToBCD ( IntIn ), BCDout );
  2804. EXIT;
  2805. end;
  2806. unpack_BCD ( BCDIn, bh );
  2807. if bh.Prec = 0
  2808. then begin
  2809. BCDout := NullBCD;
  2810. EXIT;
  2811. end;
  2812. bhr := null_.bh;
  2813. bhrr := null_.bhb;
  2814. int := Abs ( IntIn );
  2815. WITH bhrr do
  2816. begin
  2817. Neg := bh.Neg XOR ( IntIn < 0 );
  2818. FDig := bh.FDig;
  2819. LDig := bh.LDig;
  2820. for i1 := bh.FDig TO bh.LDig do
  2821. Singles[i1] := bh.Singles[i1] * int;
  2822. {
  2823. for i3 := fdig to ldig do
  2824. write ( ' ', singles[i3] );
  2825. writeln;
  2826. }
  2827. ue := 0;
  2828. for i3 := LDig DOWNTO FDig do
  2829. begin
  2830. v := Singles[i3] + ue;
  2831. ue := v DIV 10;
  2832. v := v MOD 10;
  2833. bhr.Singles[i3] := v;
  2834. end;
  2835. while ue <> 0 do
  2836. begin
  2837. Dec ( FDig );
  2838. if FDig < low ( bhr.Singles )
  2839. then RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2840. bhr.Singles[FDig] := ue MOD 10;
  2841. ue := ue DIV 10;
  2842. end;
  2843. bhr.Plac := LDig;
  2844. bhr.FDig := FDig;
  2845. if LDig > high ( bhr.Singles )
  2846. then bhr.LDig := high ( bhr.Singles )
  2847. else bhr.LDig := LDig;
  2848. end;
  2849. if NOT pack_BCD ( bhr, BCDout )
  2850. then begin
  2851. RAISE eBCDOverflowException.create ( 'in BCDMultiply' );
  2852. end;
  2853. end;
  2854. procedure BCDMultiply ( const IntIn : myInttype;
  2855. const BCDIn : tBCD;
  2856. var BCDout : tBCD ); Inline;
  2857. begin
  2858. BCDMultiply ( BCDIn, IntIn, BCDout );
  2859. end;
  2860. {$ifndef FPUNONE}
  2861. procedure BCDMultiply ( const DoubleIn : myRealtype;
  2862. const BCDIn : tBCD;
  2863. var BCDout : tBCD ); Inline;
  2864. begin
  2865. BCDMultiply ( DoubleToBCD ( DoubleIn ), BCDIn, BCDout );
  2866. end;
  2867. {$endif}
  2868. procedure BCDMultiply ( const BCDIn : tBCD;
  2869. const Currin : currency;
  2870. var BCDout : tBCD ); Inline;
  2871. begin
  2872. BCDMultiply ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2873. end;
  2874. procedure BCDMultiply ( const Currin : currency;
  2875. const BCDIn : tBCD;
  2876. var BCDout : tBCD ); Inline;
  2877. begin
  2878. BCDMultiply ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2879. end;
  2880. {$ifdef comproutines}
  2881. procedure BCDMultiply ( const BCDIn : tBCD;
  2882. const Compin : Comp;
  2883. var BCDout : tBCD ); Inline;
  2884. begin
  2885. BCDMultiply ( BCDIn, CompToBCD ( Compin ), BCDout );
  2886. end;
  2887. procedure BCDMultiply ( const Compin : Comp;
  2888. const BCDIn : tBCD;
  2889. var BCDout : tBCD ); Inline;
  2890. begin
  2891. BCDMultiply ( CompToBCD ( Compin ), BCDIn, BCDout );
  2892. end;
  2893. {$endif}
  2894. procedure BCDMultiply ( const StringIn : FmtBCDStringtype;
  2895. const BCDIn : tBCD;
  2896. var BCDout : tBCD ); Inline;
  2897. begin
  2898. BCDMultiply ( StrToBCD ( StringIn ), BCDIn, BCDout );
  2899. end;
  2900. procedure BCDDivide ( const Dividend : tBCD;
  2901. const Divisor : myInttype;
  2902. var BCDout : tBCD ); Inline;
  2903. begin
  2904. BCDDivide ( Dividend, IntegerToBCD ( Divisor ), BCDout );
  2905. end;
  2906. procedure BCDDivide ( const Dividend : myInttype;
  2907. const Divisor : tBCD;
  2908. var BCDout : tBCD ); Inline;
  2909. begin
  2910. BCDDivide ( IntegerToBCD ( Dividend ), Divisor, BCDout );
  2911. end;
  2912. {$ifndef FPUNONE}
  2913. procedure BCDDivide ( const Dividend : myRealtype;
  2914. const Divisor : tBCD;
  2915. var BCDout : tBCD ); Inline;
  2916. begin
  2917. BCDDivide ( DoubleToBCD ( Dividend ), Divisor, BCDout );
  2918. end;
  2919. {$endif}
  2920. procedure BCDDivide ( const BCDIn : tBCD;
  2921. const Currin : currency;
  2922. var BCDout : tBCD ); Inline;
  2923. begin
  2924. BCDDivide ( BCDIn, CurrToBCD ( Currin ), BCDout );
  2925. end;
  2926. procedure BCDDivide ( const Currin : currency;
  2927. const BCDIn : tBCD;
  2928. var BCDout : tBCD ); Inline;
  2929. begin
  2930. BCDDivide ( CurrToBCD ( Currin ), BCDIn, BCDout );
  2931. end;
  2932. {$ifdef comproutines}
  2933. procedure BCDDivide ( const BCDIn : tBCD;
  2934. const Compin : Comp;
  2935. var BCDout : tBCD ); Inline;
  2936. begin
  2937. BCDDivide ( BCDIn, CompToBCD ( Compin ), BCDout );
  2938. end;
  2939. procedure BCDDivide ( const Compin : Comp;
  2940. const BCDIn : tBCD;
  2941. var BCDout : tBCD ); Inline;
  2942. begin
  2943. BCDDivide ( CompToBCD ( Compin ), BCDIn, BCDout );
  2944. end;
  2945. {$endif}
  2946. procedure BCDDivide ( const Dividend : FmtBCDStringtype;
  2947. const Divisor : tBCD;
  2948. var BCDout : tBCD ); Inline;
  2949. begin
  2950. BCDDivide ( StrToBCD ( Dividend ), Divisor, BCDout );
  2951. end;
  2952. operator = ( const BCD1,
  2953. BCD2 : tBCD ) z : Boolean; Inline;
  2954. begin
  2955. z := BCDCompare ( BCD1, BCD2 ) = 0;
  2956. end;
  2957. operator < ( const BCD1,
  2958. BCD2 : tBCD ) z : Boolean; Inline;
  2959. begin
  2960. z := BCDCompare ( BCD1, BCD2 ) < 0;
  2961. end;
  2962. operator > ( const BCD1,
  2963. BCD2 : tBCD ) z : Boolean; Inline;
  2964. begin
  2965. z := BCDCompare ( BCD1, BCD2 ) > 0;
  2966. end;
  2967. operator <= ( const BCD1,
  2968. BCD2 : tBCD ) z : Boolean; Inline;
  2969. begin
  2970. z := BCDCompare ( BCD1, BCD2 ) <= 0;
  2971. end;
  2972. operator >= ( const BCD1,
  2973. BCD2 : tBCD ) z : Boolean; Inline;
  2974. begin
  2975. z := BCDCompare ( BCD1, BCD2 ) >= 0;
  2976. end;
  2977. (* ######################## not allowed: why?
  2978. operator + ( const BCD : tBCD ) z : tBCD; Inline;
  2979. begin
  2980. z := bcd;
  2981. end;
  2982. ##################################################### *)
  2983. operator - ( const BCD : tBCD ) z : tBCD; Inline;
  2984. begin
  2985. z := BCD;
  2986. BCDNegate ( z );
  2987. end;
  2988. operator + ( const BCD1,
  2989. BCD2 : tBCD ) z : tBCD; Inline;
  2990. begin
  2991. BCDAdd ( BCD1, BCD2, z );
  2992. end;
  2993. operator + ( const BCD : tBCD;
  2994. const i : myInttype ) z : tBCD; Inline;
  2995. begin
  2996. BCDAdd ( BCD, i, z );
  2997. end;
  2998. operator + ( const i : myInttype;
  2999. const BCD : tBCD ) z : tBCD; Inline;
  3000. begin
  3001. BCDAdd ( i, BCD, z );
  3002. end;
  3003. {$ifndef FPUNONE}
  3004. operator + ( const BCD : tBCD;
  3005. const r : myRealtype ) z : tBCD; Inline;
  3006. begin
  3007. BCDAdd ( BCD, DoubleToBCD ( r ), z );
  3008. end;
  3009. operator + ( const r : myRealtype;
  3010. const BCD : tBCD ) z : tBCD; Inline;
  3011. begin
  3012. BCDAdd ( DoubleToBCD ( r ), BCD, z );
  3013. end;
  3014. {$endif}
  3015. operator + ( const BCD : tBCD;
  3016. const c : currency ) z : tBCD; Inline;
  3017. begin
  3018. BCDAdd ( BCD, CurrToBCD ( c ), z );
  3019. end;
  3020. operator + ( const c : currency;
  3021. const BCD : tBCD ) z : tBCD; Inline;
  3022. begin
  3023. BCDAdd ( CurrToBCD ( c ), BCD, z );
  3024. end;
  3025. {$ifdef comproutines}
  3026. operator + ( const BCD : tBCD;
  3027. const c : Comp ) z : tBCD; Inline;
  3028. begin
  3029. BCDAdd ( BCD, CompToBCD ( c ), z );
  3030. end;
  3031. operator + ( const c : Comp;
  3032. const BCD : tBCD ) z : tBCD; Inline;
  3033. begin
  3034. BCDAdd ( CompToBCD ( c ), BCD, z );
  3035. end;
  3036. {$endif}
  3037. operator + ( const BCD : tBCD;
  3038. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3039. begin
  3040. BCDAdd ( BCD, StrToBCD ( s ), z );
  3041. end;
  3042. operator + ( const s : FmtBCDStringtype;
  3043. const BCD : tBCD ) z : tBCD; Inline;
  3044. begin
  3045. BCDAdd ( StrToBCD ( s ), BCD, z );
  3046. end;
  3047. operator - ( const BCD1,
  3048. BCD2 : tBCD ) z : tBCD; Inline;
  3049. begin
  3050. BCDSubtract ( BCD1, BCD2, z );
  3051. end;
  3052. operator - ( const BCD : tBCD;
  3053. const i : myInttype ) z : tBCD; Inline;
  3054. begin
  3055. BCDSubtract ( BCD, i, z );
  3056. end;
  3057. operator - ( const i : myInttype;
  3058. const BCD : tBCD ) z : tBCD; Inline;
  3059. begin
  3060. BCDSubtract ( BCD, i, z );
  3061. BCDNegate ( z );
  3062. end;
  3063. {$ifndef FPUNONE}
  3064. operator - ( const BCD : tBCD;
  3065. const r : myRealtype ) z : tBCD; Inline;
  3066. begin
  3067. BCDSubtract ( BCD, DoubleToBCD ( r ), z );
  3068. end;
  3069. operator - ( const r : myRealtype;
  3070. const BCD : tBCD ) z : tBCD; Inline;
  3071. begin
  3072. BCDSubtract ( DoubleToBCD ( r ), BCD, z );
  3073. end;
  3074. {$endif}
  3075. operator - ( const BCD : tBCD;
  3076. const c : currency ) z : tBCD; Inline;
  3077. begin
  3078. BCDSubtract ( BCD, CurrToBCD ( c ), z );
  3079. end;
  3080. operator - ( const c : currency;
  3081. const BCD : tBCD ) z : tBCD; Inline;
  3082. begin
  3083. BCDSubtract ( CurrToBCD ( c ), BCD, z );
  3084. end;
  3085. {$ifdef comproutines}
  3086. operator - ( const BCD : tBCD;
  3087. const c : Comp ) z : tBCD; Inline;
  3088. begin
  3089. BCDSubtract ( BCD, CompToBCD ( c ), z );
  3090. end;
  3091. operator - ( const c : Comp;
  3092. const BCD : tBCD ) z : tBCD; Inline;
  3093. begin
  3094. BCDSubtract ( CompToBCD ( c ), BCD, z );
  3095. end;
  3096. {$endif}
  3097. operator - ( const BCD : tBCD;
  3098. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3099. begin
  3100. BCDSubtract ( BCD, StrToBCD ( s ), z );
  3101. end;
  3102. operator - ( const s : FmtBCDStringtype;
  3103. const BCD : tBCD ) z : tBCD; Inline;
  3104. begin
  3105. BCDSubtract ( StrToBCD ( s ), BCD, z );
  3106. end;
  3107. operator * ( const BCD1,
  3108. BCD2 : tBCD ) z : tBCD; Inline;
  3109. begin
  3110. BCDMultiply ( BCD1, BCD2, z );
  3111. end;
  3112. operator * ( const BCD : tBCD;
  3113. const i : myInttype ) z : tBCD; Inline;
  3114. begin
  3115. BCDMultiply ( BCD, i, z );
  3116. end;
  3117. operator * ( const i : myInttype;
  3118. const BCD : tBCD ) z : tBCD; Inline;
  3119. begin
  3120. BCDMultiply ( BCD, i, z );
  3121. end;
  3122. {$ifndef FPUNONE}
  3123. operator * ( const BCD : tBCD;
  3124. const r : myRealtype ) z : tBCD; Inline;
  3125. begin
  3126. BCDMultiply ( BCD, DoubleToBCD ( r ), z );
  3127. end;
  3128. operator * ( const r : myRealtype;
  3129. const BCD : tBCD ) z : tBCD; Inline;
  3130. begin
  3131. BCDMultiply ( DoubleToBCD ( r ), BCD, z );
  3132. end;
  3133. {$endif}
  3134. operator * ( const BCD : tBCD;
  3135. const c : currency ) z : tBCD; Inline;
  3136. begin
  3137. BCDMultiply ( BCD, CurrToBCD ( c ), z );
  3138. end;
  3139. operator * ( const c : currency;
  3140. const BCD : tBCD ) z : tBCD; Inline;
  3141. begin
  3142. BCDMultiply ( CurrToBCD ( c ), BCD, z );
  3143. end;
  3144. {$ifdef comproutines}
  3145. operator * ( const BCD : tBCD;
  3146. const c : Comp ) z : tBCD; Inline;
  3147. begin
  3148. BCDMultiply ( BCD, CompToBCD ( c ), z );
  3149. end;
  3150. operator * ( const c : Comp;
  3151. const BCD : tBCD ) z : tBCD; Inline;
  3152. begin
  3153. BCDMultiply ( CompToBCD ( c ), BCD, z );
  3154. end;
  3155. {$endif}
  3156. operator * ( const BCD : tBCD;
  3157. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3158. begin
  3159. BCDMultiply ( BCD, StrToBCD ( s ), z );
  3160. end;
  3161. operator * ( const s : FmtBCDStringtype;
  3162. const BCD : tBCD ) z : tBCD; Inline;
  3163. begin
  3164. BCDMultiply ( StrToBCD ( s ), BCD, z );
  3165. end;
  3166. operator / ( const BCD1,
  3167. BCD2 : tBCD ) z : tBCD; Inline;
  3168. begin
  3169. BCDDivide ( BCD1, BCD2, z );
  3170. end;
  3171. operator / ( const BCD : tBCD;
  3172. const i : myInttype ) z : tBCD; Inline;
  3173. begin
  3174. BCDDivide ( BCD, i, z );
  3175. end;
  3176. operator / ( const i : myInttype;
  3177. const BCD : tBCD ) z : tBCD; Inline;
  3178. begin
  3179. BCDDivide ( IntegerToBCD ( i ), BCD, z );
  3180. end;
  3181. {$ifndef FPUNONE}
  3182. operator / ( const BCD : tBCD;
  3183. const r : myRealtype ) z : tBCD; Inline;
  3184. begin
  3185. BCDDivide ( BCD, DoubleToBCD ( r ), z );
  3186. end;
  3187. operator / ( const r : myRealtype;
  3188. const BCD : tBCD ) z : tBCD; Inline;
  3189. begin
  3190. BCDDivide ( DoubleToBCD ( r ), BCD, z );
  3191. end;
  3192. {$endif}
  3193. operator / ( const BCD : tBCD;
  3194. const c : currency ) z : tBCD; Inline;
  3195. begin
  3196. BCDDivide ( BCD, CurrToBCD ( c ), z );
  3197. end;
  3198. operator / ( const c : currency;
  3199. const BCD : tBCD ) z : tBCD; Inline;
  3200. begin
  3201. BCDDivide ( CurrToBCD ( c ), BCD, z );
  3202. end;
  3203. {$ifdef comproutines}
  3204. operator / ( const BCD : tBCD;
  3205. const c : Comp ) z : tBCD; Inline;
  3206. begin
  3207. BCDDivide ( BCD, CompToBCD ( c ), z );
  3208. end;
  3209. operator / ( const c : Comp;
  3210. const BCD : tBCD ) z : tBCD; Inline;
  3211. begin
  3212. BCDDivide ( CompToBCD ( c ), BCD, z );
  3213. end;
  3214. {$endif}
  3215. operator / ( const BCD : tBCD;
  3216. const s : FmtBCDStringtype ) z : tBCD; Inline;
  3217. begin
  3218. BCDDivide ( BCD, StrToBCD ( s ), z );
  3219. end;
  3220. operator / ( const s : FmtBCDStringtype;
  3221. const BCD : tBCD ) z : tBCD; Inline;
  3222. begin
  3223. BCDDivide ( StrToBCD ( s ), BCD, z );
  3224. end;
  3225. operator := ( const i : Byte ) z : tBCD; Inline;
  3226. begin
  3227. z := IntegerToBCD ( myInttype ( i ) );
  3228. end;
  3229. operator := ( const BCD : tBCD ) z : Byte; Inline;
  3230. begin
  3231. z := BCDToInteger ( BCD );
  3232. end;
  3233. operator := ( const i : Word ) z : tBCD; Inline;
  3234. begin
  3235. z := IntegerToBCD ( myInttype ( i ) );
  3236. end;
  3237. operator := ( const BCD : tBCD ) z : Word; Inline;
  3238. begin
  3239. z := BCDToInteger ( BCD );
  3240. end;
  3241. operator := ( const i : longword ) z : tBCD; Inline;
  3242. begin
  3243. z := IntegerToBCD ( myInttype ( i ) );
  3244. end;
  3245. operator := ( const BCD : tBCD ) z : longword; Inline;
  3246. begin
  3247. z := BCDToInteger ( BCD );
  3248. end;
  3249. {$if declared ( qword ) }
  3250. operator := ( const i : qword ) z : tBCD; Inline;
  3251. begin
  3252. z := IntegerToBCD ( myInttype ( i ) );
  3253. end;
  3254. operator := ( const BCD : tBCD ) z : qword; Inline;
  3255. begin
  3256. z := BCDToInteger ( BCD );
  3257. end;
  3258. {$endif}
  3259. operator := ( const i : ShortInt ) z : tBCD; Inline;
  3260. begin
  3261. z := IntegerToBCD ( myInttype ( i ) );
  3262. end;
  3263. operator := ( const BCD : tBCD ) z : ShortInt; Inline;
  3264. begin
  3265. z := BCDToInteger ( BCD );
  3266. end;
  3267. operator := ( const i : smallint ) z : tBCD; Inline;
  3268. begin
  3269. z := IntegerToBCD ( myInttype ( i ) );
  3270. end;
  3271. operator := ( const BCD : tBCD ) z : smallint; Inline;
  3272. begin
  3273. z := BCDToInteger ( BCD );
  3274. end;
  3275. operator := ( const i : LongInt ) z : tBCD; Inline;
  3276. begin
  3277. z := IntegerToBCD ( myInttype ( i ) );
  3278. end;
  3279. operator := ( const BCD : tBCD ) z : LongInt; Inline;
  3280. begin
  3281. z := BCDToInteger ( BCD );
  3282. end;
  3283. {$if declared ( int64 ) }
  3284. operator := ( const i : int64 ) z : tBCD; Inline;
  3285. begin
  3286. z := IntegerToBCD ( myInttype ( i ) );
  3287. end;
  3288. operator := ( const BCD : tBCD ) z : int64; Inline;
  3289. begin
  3290. z := BCDToInteger ( BCD );
  3291. end;
  3292. {$endif}
  3293. {$ifndef FPUNONE}
  3294. operator := ( const r : Single ) z : tBCD; Inline;
  3295. begin
  3296. z := DoubleToBCD ( myRealtype ( r ) );
  3297. end;
  3298. operator := ( const BCD : tBCD ) z : Single; Inline;
  3299. begin
  3300. z := BCDToDouble ( BCD );
  3301. end;
  3302. operator := ( const r : Double ) z : tBCD; Inline;
  3303. begin
  3304. z := DoubleToBCD ( myRealtype ( r ) );
  3305. end;
  3306. operator := ( const BCD : tBCD ) z : Double; Inline;
  3307. begin
  3308. z := BCDToDouble ( BCD );
  3309. end;
  3310. {$if sizeof ( extended ) <> sizeof ( double )}
  3311. operator := ( const r : Extended ) z : tBCD; Inline;
  3312. begin
  3313. z := DoubleToBCD ( {myRealtype (} r {)} );
  3314. end;
  3315. operator := ( const BCD : tBCD ) z : Extended; Inline;
  3316. begin
  3317. z := BCDToDouble ( BCD );
  3318. end;
  3319. {$endif}
  3320. {$endif}
  3321. operator := ( const c : currency ) z : tBCD; Inline;
  3322. begin
  3323. CurrToBCD ( c, z );
  3324. end;
  3325. operator := ( const BCD : tBCD ) z : currency; Inline;
  3326. begin
  3327. BCDToCurr ( BCD, z );
  3328. end;
  3329. {$ifdef comproutines}
  3330. {$undef makedirect}
  3331. {$ifdef makedirect}
  3332. operator := ( const c : Comp ) z : tBCD; Inline;
  3333. var
  3334. cc : int64 absolute c;
  3335. begin
  3336. z := IntegerToBCD ( cc );
  3337. end;
  3338. { $define version1} { only one of these may be defined! }
  3339. { $define version2} { version 1 produces a compiler error (with INLINE only!)}
  3340. {$define version3} { I wasn't able to reduce the problem, sorry }
  3341. {$ifdef version1}
  3342. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3343. var
  3344. zz : Comp absolute z;
  3345. begin
  3346. zz := BCDToInteger ( BCD );
  3347. end;
  3348. {$endif}
  3349. {$ifdef version2}
  3350. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3351. var
  3352. zz : int64;
  3353. zzz : Comp absolute zz;
  3354. begin
  3355. zz := BCDToInteger ( BCD );
  3356. z := zzz;
  3357. end;
  3358. {$endif}
  3359. {$ifdef version3}
  3360. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3361. var
  3362. zz : record
  3363. case Boolean of
  3364. False: ( i : int64 );
  3365. True: ( c : Comp );
  3366. end;
  3367. begin
  3368. zz.i := BCDToInteger ( BCD );
  3369. z := zz.c;
  3370. end;
  3371. {$endif}
  3372. {$else}
  3373. operator := ( const c : Comp ) z : tBCD; Inline;
  3374. begin
  3375. z := CompToBCD ( c );
  3376. end;
  3377. operator := ( const BCD : tBCD ) z : Comp; Inline;
  3378. begin
  3379. z := BCDToComp ( BCD );
  3380. end;
  3381. {$endif}
  3382. {$endif}
  3383. operator := ( const s : string ) z : tBCD; Inline;
  3384. begin
  3385. z := StrToBCD ( s );
  3386. end;
  3387. operator := ( const BCD : tBCD ) z : string; Inline;
  3388. begin
  3389. z := BCDToStr ( BCD );
  3390. end;
  3391. operator := ( const s : AnsiString ) z : tBCD; Inline;
  3392. begin
  3393. z := StrToBCD ( s );
  3394. end;
  3395. operator := ( const BCD : tBCD ) z : AnsiString; Inline;
  3396. begin
  3397. z := BCDToStr ( BCD );
  3398. end;
  3399. {$endif}
  3400. Function VariantToBCD(const VargSrc : TVarData) : TBCD;
  3401. begin
  3402. with VargSrc do
  3403. case vType and not varTypeMask of
  3404. 0: case vType of
  3405. varEmpty : Result := 0;
  3406. varSmallInt : Result := vSmallInt;
  3407. varShortInt : Result := vShortInt;
  3408. varInteger : Result := vInteger;
  3409. varSingle : Result := vSingle;
  3410. varDouble : Result := vDouble;
  3411. varCurrency : Result := vCurrency;
  3412. varDate : Result := vDate;
  3413. varBoolean : Result := Integer(vBoolean);
  3414. varVariant : Result := VariantToBCD(PVarData(vPointer)^);
  3415. varByte : Result := vByte;
  3416. varWord : Result := vWord;
  3417. varLongWord : Result := vLongWord;
  3418. varInt64 : Result := vInt64;
  3419. varQword : Result := vQWord;
  3420. varString : Result := AnsiString(vString);
  3421. varOleStr : Result := WideString(vOleStr);
  3422. varUString : Result := UnicodeString(vString);
  3423. else
  3424. if vType=VarFmtBCD then
  3425. Result := TFMTBcdVarData(vPointer).BCD
  3426. else
  3427. not_implemented;
  3428. end;
  3429. varByRef: if Assigned(vPointer) then case vType and varTypeMask of
  3430. varSmallInt : Result := PSmallInt(vPointer)^;
  3431. varShortInt : Result := PShortInt(vPointer)^;
  3432. varInteger : Result := PInteger(vPointer)^;
  3433. varSingle : Result := PSingle(vPointer)^;
  3434. varDouble : Result := PDouble(vPointer)^;
  3435. varCurrency : Result := PCurrency(vPointer)^;
  3436. varDate : Result := PDate(vPointer)^;
  3437. varBoolean : Result := SmallInt(PWordBool(vPointer)^);
  3438. varVariant : Result := VariantToBCD(PVarData(vPointer)^);
  3439. varByte : Result := PByte(vPointer)^;
  3440. varWord : Result := PWord(vPointer)^;
  3441. varLongWord : Result := PLongWord(vPointer)^;
  3442. varInt64 : Result := PInt64(vPointer)^;
  3443. varQword : Result := PQWord(vPointer)^;
  3444. else { other vtype }
  3445. not_implemented;
  3446. end else { pointer is nil }
  3447. not_implemented;
  3448. else { array or something like that }
  3449. not_implemented;
  3450. end;
  3451. end;
  3452. function VarToBCD ( const aValue : Variant ) : tBCD;
  3453. begin
  3454. Result:=VariantToBCD(TVarData(aValue));
  3455. end;
  3456. constructor TFMTBcdVarData.create;
  3457. begin
  3458. inherited create;
  3459. FBcd:=NullBCD;
  3460. end;
  3461. constructor TFMTBcdVarData.create(const BCD : tBCD);
  3462. begin
  3463. inherited create;
  3464. FBcd:=BCD;
  3465. end;
  3466. function TFMTBcdFactory.GetInstance(const v : TVarData): tObject;
  3467. begin
  3468. result:=tObject(v.VPointer);
  3469. end;
  3470. procedure TFMTBcdFactory.BinaryOp(var Left: TVarData; const Right: TVarData; const Operation: TVarOp);
  3471. var l, r: TBCD;
  3472. begin
  3473. l:=VariantToBCD(Left);
  3474. r:=VariantToBCD(Right);
  3475. case Operation of
  3476. opAdd:
  3477. l:=l+r;
  3478. opSubtract:
  3479. l:=l-r;
  3480. opMultiply:
  3481. l:=l*r;
  3482. opDivide:
  3483. l:=l/r;
  3484. else
  3485. RaiseInvalidOp;
  3486. end;
  3487. if Left.vType = VarType then
  3488. TFMTBcdVarData(Left.VPointer).BCD := l
  3489. else if Left.vType = varDouble then
  3490. Left.vDouble := l
  3491. else
  3492. RaiseInvalidOp;
  3493. end;
  3494. procedure TFMTBcdFactory.Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult);
  3495. var l, r: TBCD;
  3496. CmpRes: integer;
  3497. begin
  3498. l:=VariantToBCD(Left);
  3499. r:=VariantToBCD(Right);
  3500. CmpRes := BCDCompare(l,r);
  3501. if CmpRes=0 then
  3502. Relationship := crEqual
  3503. else if CmpRes<0 then
  3504. Relationship := crLessThan
  3505. else
  3506. Relationship := crGreaterThan;
  3507. end;
  3508. function TFMTBcdFactory.CompareOp(const Left, Right: TVarData; const Operation: TVarOp): Boolean;
  3509. var l, r: TBCD;
  3510. begin
  3511. l:=VariantToBCD(Left);
  3512. r:=VariantToBCD(Right);
  3513. case Operation of
  3514. opCmpEq:
  3515. Result := l=r;
  3516. opCmpNe:
  3517. Result := l<>r;
  3518. opCmpLt:
  3519. Result := l<r;
  3520. opCmpLe:
  3521. Result := l<=r;
  3522. opCmpGt:
  3523. Result := l>r;
  3524. opCmpGe:
  3525. Result := l>=r;
  3526. else
  3527. RaiseInvalidOp;
  3528. end;
  3529. end;
  3530. procedure TFMTBcdFactory.Clear(var V: TVarData);
  3531. begin
  3532. FreeAndNil(tObject(V.VPointer));
  3533. V.VType:=varEmpty;
  3534. end;
  3535. procedure TFMTBcdFactory.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
  3536. begin
  3537. if Indirect then
  3538. Dest.VPointer:=Source.VPointer
  3539. else
  3540. Dest.VPointer:=TFMTBcdVarData.Create(TFMTBcdVarData(Source.VPointer).BCD);
  3541. Dest.VType:=VarType;
  3542. end;
  3543. procedure TFMTBcdFactory.Cast(var Dest: TVarData; const Source: TVarData);
  3544. begin
  3545. not_implemented;
  3546. end;
  3547. procedure TFMTBcdFactory.CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType);
  3548. var v: TVarData;
  3549. begin
  3550. if Source.vType=VarType then
  3551. if aVarType = varString then
  3552. VarDataFromStr(Dest, BCDToStr(TFMTBcdVarData(Source.vPointer).BCD))
  3553. else
  3554. begin
  3555. VarDataInit(v);
  3556. v.vType:=varDouble;
  3557. v.vDouble:=BCDToDouble(TFMTBcdVarData(Source.vPointer).BCD);
  3558. VarDataCastTo(Dest, v, aVarType); //now cast Double to any requested type
  3559. { finalizing v is not necessary here (Double is a simple type) }
  3560. end
  3561. else
  3562. inherited;
  3563. end;
  3564. {$if declared ( myMinIntBCD ) }
  3565. (*
  3566. {$if sizeof ( integer ) = 2 }
  3567. {$ifdef BCDgr4 }
  3568. const
  3569. myMinIntBCDValue : packed array [ 1..3 ] of Char = #$32#$76#$80;
  3570. {$endif}
  3571. {$else}
  3572. {$if sizeof ( integer ) = 4 }
  3573. *)
  3574. {$ifdef BCDgr9 }
  3575. const
  3576. myMinIntBCDValue : packed array [ 1..10 ] of Char = #$21#$47#$48#$36#$48;
  3577. {$endif}
  3578. (*
  3579. {$else}
  3580. {$if sizeof ( integer ) = 8 }
  3581. {$ifdef BCDgr18 }
  3582. const
  3583. myMinIntBCDValue : packed array [ 1..19 ] of Char = #$92#$23#$37#$20#$36#$85#$47#$75#$80#$80;
  3584. {$endif}
  3585. {$else}
  3586. {$fatal You have an interesting integer type! Sorry, not supported}
  3587. {$endif}
  3588. {$endif}
  3589. {$endif}
  3590. *)
  3591. {$endif}
  3592. initialization
  3593. FillChar ( null_, SizeOf ( null_ ), #0 );
  3594. FillChar ( NullBCD_, SizeOf ( NullBCD_ ), #0 );
  3595. FillChar ( OneBCD_, SizeOf ( OneBCD_ ), #0 );
  3596. OneBCD_.Precision := 1;
  3597. OneBCD_.Fraction[low ( OneBCD_.Fraction )] := $10;
  3598. {$if declared ( myMinIntBCD ) }
  3599. FillChar ( myMinIntBCD, SizeOf ( myMinIntBCD ), #0 );
  3600. {$ifndef bigger_BCD}
  3601. myMinIntBCD.SignSpecialPlaces := NegBit;
  3602. {$else}
  3603. myMinIntBCD.Negativ := True;
  3604. {$endif}
  3605. {$if sizeof ( integer ) = 2 }
  3606. {$ifdef BCDgr4 }
  3607. myMinIntBCD.Precision := 5;
  3608. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3609. {$endif}
  3610. {$else}
  3611. {$if sizeof ( integer ) = 4 }
  3612. {$ifdef BCDgr9 }
  3613. myMinIntBCD.Precision := 10;
  3614. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3615. {$endif}
  3616. {$else}
  3617. {$if sizeof ( integer ) = 8 }
  3618. {$ifdef BCDgr18 }
  3619. myMinIntBCD.Precision := 19;
  3620. Move ( myMinIntBCDValue, myMinIntBCD.Fraction, SizeOf ( myMinIntBCDValue ) );
  3621. {$endif}
  3622. {$else}
  3623. {$fatal You have an interesting integer type! Sorry, not supported}
  3624. {$endif}
  3625. {$endif}
  3626. {$endif}
  3627. {$endif}
  3628. FMTBcdFactory:=TFMTBcdFactory.create;
  3629. finalization
  3630. FreeAndNil(FMTBcdFactory)
  3631. end.