fmtbcd.pp 125 KB

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