2
0

fmtbcd.pp 115 KB

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