fmtbcd.pp 115 KB

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